@b3dotfun/sdk 0.1.2-alpha.2 → 0.1.2-alpha.4
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/cjs/anyspend/react/components/AnySpendCustomExactIn.d.ts +1 -0
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +110 -38
- package/dist/cjs/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/AnySpendStakeUpsideExactIn.js +2 -2
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +4 -6
- package/dist/cjs/anyspend/react/components/common/OrderDetailsCollapsible.js +6 -7
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +20 -1
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +118 -15
- package/dist/cjs/anyspend/react/hooks/useRecipientAddressState.js +1 -1
- package/dist/cjs/anyspend/utils/format.js +12 -2
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +2 -0
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.d.ts +1 -0
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +111 -39
- package/dist/esm/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +2 -1
- package/dist/esm/anyspend/react/components/AnySpendStakeUpsideExactIn.js +2 -2
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +4 -6
- package/dist/esm/anyspend/react/components/common/OrderDetailsCollapsible.js +6 -7
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +20 -1
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +118 -16
- package/dist/esm/anyspend/react/hooks/useRecipientAddressState.js +1 -1
- package/dist/esm/anyspend/utils/format.js +12 -2
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +2 -0
- package/dist/types/anyspend/react/components/AnySpendCustomExactIn.d.ts +1 -0
- package/dist/types/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +2 -1
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +20 -1
- package/dist/types/global-account/react/stores/useModalStore.d.ts +2 -0
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +125 -41
- package/src/anyspend/react/components/AnySpendStakeUpsideExactIn.tsx +3 -0
- package/src/anyspend/react/components/common/OrderDetails.tsx +4 -6
- package/src/anyspend/react/components/common/OrderDetailsCollapsible.tsx +7 -6
- package/src/anyspend/react/hooks/useAnyspendFlow.ts +140 -17
- package/src/anyspend/react/hooks/useRecipientAddressState.ts +1 -1
- package/src/anyspend/utils/format.ts +13 -2
- package/src/global-account/react/stores/useModalStore.ts +2 -0
|
@@ -18,6 +18,7 @@ export interface AnySpendCustomExactInProps {
|
|
|
18
18
|
sourceTokenChainId?: number;
|
|
19
19
|
destinationToken: components["schemas"]["Token"];
|
|
20
20
|
destinationChainId: number;
|
|
21
|
+
destinationTokenAmount?: string;
|
|
21
22
|
onSuccess?: (amount: string) => void;
|
|
22
23
|
onOpenCustomModal?: () => void;
|
|
23
24
|
mainFooter?: React.ReactNode;
|
|
@@ -33,13 +33,13 @@ function AnySpendCustomExactIn(props) {
|
|
|
33
33
|
const fingerprintConfig = (0, AnySpendFingerprintWrapper_1.getFingerprintConfig)();
|
|
34
34
|
return ((0, jsx_runtime_1.jsx)(AnySpendFingerprintWrapper_1.AnySpendFingerprintWrapper, { fingerprint: fingerprintConfig, children: (0, jsx_runtime_1.jsx)(AnySpendCustomExactInInner, { ...props }) }));
|
|
35
35
|
}
|
|
36
|
-
function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddress, paymentType = "crypto", sourceTokenAddress, sourceTokenChainId, destinationToken, destinationChainId, onSuccess, onOpenCustomModal, mainFooter, onTokenSelect, customUsdInputValues, preferEoa, customExactInConfig, orderType = "custom_exact_in", minDestinationAmount, header, returnToHomeUrl, customRecipientLabel, returnHomeLabel, classes, }) {
|
|
36
|
+
function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddress, paymentType = "crypto", sourceTokenAddress, sourceTokenChainId, destinationToken, destinationChainId, onSuccess, onOpenCustomModal, mainFooter, onTokenSelect, customUsdInputValues, preferEoa, customExactInConfig, destinationTokenAmount, orderType = "custom_exact_in", minDestinationAmount, header, returnToHomeUrl, customRecipientLabel, returnHomeLabel, classes, }) {
|
|
37
37
|
const actionLabel = customExactInConfig?.action ?? "Custom Execution";
|
|
38
38
|
const DESTINATION_TOKEN_DETAILS = {
|
|
39
39
|
SYMBOL: destinationToken.symbol ?? "TOKEN",
|
|
40
40
|
LOGO_URI: destinationToken.metadata?.logoURI ?? "",
|
|
41
41
|
};
|
|
42
|
-
const { activePanel, setActivePanel, orderId, setOrderId, oat, selectedSrcChainId, setSelectedSrcChainId, selectedSrcToken, setSelectedSrcToken, selectedDstToken, selectedDstChainId, srcAmount, setSrcAmount, dstAmount, isSrcInputDirty, setIsSrcInputDirty, selectedCryptoPaymentMethod, effectiveCryptoPaymentMethod, setSelectedCryptoPaymentMethod, selectedFiatPaymentMethod, setSelectedFiatPaymentMethod, selectedRecipientAddress, setSelectedRecipientAddress, recipientName, globalAddress, hasEnoughBalance, isBalanceLoading, anyspendQuote, isLoadingAnyspendQuote, activeInputAmountInWei, geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support, createOrder, isCreatingOrder, createOnrampOrder, isCreatingOnrampOrder, } = (0, useAnyspendFlow_1.useAnyspendFlow)({
|
|
42
|
+
const { activePanel, setActivePanel, orderId, setOrderId, oat, selectedSrcChainId, setSelectedSrcChainId, selectedSrcToken, setSelectedSrcToken, selectedDstToken, selectedDstChainId, srcAmount, setSrcAmount, dstAmount, dstAmountInput, setDstAmountInput, isSrcInputDirty, setIsSrcInputDirty, tradeType, selectedCryptoPaymentMethod, effectiveCryptoPaymentMethod, setSelectedCryptoPaymentMethod, selectedFiatPaymentMethod, setSelectedFiatPaymentMethod, selectedRecipientAddress, setSelectedRecipientAddress, recipientName, globalAddress, hasEnoughBalance, isBalanceLoading, anyspendQuote, isLoadingAnyspendQuote, isQuoteLoading, activeInputAmountInWei, activeOutputAmountInWei, geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support, createOrder, isCreatingOrder, createOnrampOrder, isCreatingOnrampOrder, } = (0, useAnyspendFlow_1.useAnyspendFlow)({
|
|
43
43
|
paymentType,
|
|
44
44
|
recipientAddress,
|
|
45
45
|
loadOrder,
|
|
@@ -51,6 +51,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
51
51
|
slippage: SLIPPAGE_PERCENT,
|
|
52
52
|
disableUrlParamManagement: true,
|
|
53
53
|
orderType,
|
|
54
|
+
customExactInConfig,
|
|
54
55
|
});
|
|
55
56
|
const { connectedEOAWallet } = (0, react_2.useAccountWallet)();
|
|
56
57
|
const setActiveWallet = (0, react_5.useSetActiveWallet)();
|
|
@@ -65,6 +66,17 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
}, [preferEoa, connectedEOAWallet, setActiveWallet]);
|
|
69
|
+
// Prefill destination amount if provided (for EXACT_OUTPUT mode)
|
|
70
|
+
const appliedDestinationAmount = (0, react_4.useRef)(false);
|
|
71
|
+
(0, react_4.useEffect)(() => {
|
|
72
|
+
if (destinationTokenAmount && !appliedDestinationAmount.current) {
|
|
73
|
+
appliedDestinationAmount.current = true;
|
|
74
|
+
// Convert wei to human-readable format
|
|
75
|
+
const formattedAmount = (0, number_1.formatUnits)(destinationTokenAmount, destinationToken.decimals);
|
|
76
|
+
setDstAmountInput(formattedAmount);
|
|
77
|
+
setIsSrcInputDirty(false); // Switch to EXACT_OUTPUT mode
|
|
78
|
+
}
|
|
79
|
+
}, [destinationTokenAmount, destinationToken.decimals, setDstAmountInput, setIsSrcInputDirty]);
|
|
68
80
|
const selectedRecipientOrDefault = selectedRecipientAddress ?? recipientAddress;
|
|
69
81
|
const expectedDstAmountRaw = anyspendQuote?.data?.currencyOut?.amount ?? "0";
|
|
70
82
|
const buildCustomPayload = (_recipient) => {
|
|
@@ -89,12 +101,14 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
89
101
|
};
|
|
90
102
|
};
|
|
91
103
|
const btnInfo = (0, react_4.useMemo)(() => {
|
|
92
|
-
|
|
104
|
+
// Check for empty amount based on trade type
|
|
105
|
+
const isAmountEmpty = tradeType === "EXACT_OUTPUT" ? !dstAmountInput || dstAmountInput === "0" : activeInputAmountInWei === "0";
|
|
106
|
+
if (isAmountEmpty)
|
|
93
107
|
return { text: "Enter an amount", disable: true, error: false, loading: false };
|
|
94
108
|
if (orderType === "hype_duel" && selectedSrcToken?.address?.toLowerCase() === constants_1.B3_TOKEN.address.toLowerCase()) {
|
|
95
109
|
return { text: "Convert to HYPE using B3", disable: false, error: false, loading: false };
|
|
96
110
|
}
|
|
97
|
-
if (
|
|
111
|
+
if (isQuoteLoading)
|
|
98
112
|
return { text: "Loading quote...", disable: true, error: false, loading: true };
|
|
99
113
|
if (isCreatingOrder || isCreatingOnrampOrder)
|
|
100
114
|
return { text: "Creating order...", disable: true, error: false, loading: true };
|
|
@@ -142,7 +156,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
142
156
|
return { text: "Continue", disable: false, error: false, loading: false };
|
|
143
157
|
}, [
|
|
144
158
|
activeInputAmountInWei,
|
|
145
|
-
|
|
159
|
+
isQuoteLoading,
|
|
146
160
|
isCreatingOrder,
|
|
147
161
|
isCreatingOnrampOrder,
|
|
148
162
|
selectedRecipientOrDefault,
|
|
@@ -157,6 +171,8 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
157
171
|
DESTINATION_TOKEN_DETAILS.SYMBOL,
|
|
158
172
|
orderType,
|
|
159
173
|
selectedSrcToken,
|
|
174
|
+
tradeType,
|
|
175
|
+
dstAmountInput,
|
|
160
176
|
]);
|
|
161
177
|
const onMainButtonClick = async () => {
|
|
162
178
|
if (orderType === "hype_duel" && selectedSrcToken?.address?.toLowerCase() === constants_1.B3_TOKEN.address.toLowerCase()) {
|
|
@@ -187,9 +203,9 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
187
203
|
const headerContent = header ? (header({ anyspendPrice: anyspendQuote, isLoadingAnyspendPrice: isLoadingAnyspendQuote })) : ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-as-primary text-xl font-bold", children: actionLabel }), (0, jsx_runtime_1.jsx)("p", { className: "text-as-secondary text-sm", children: "Pay from any token to execute a custom exact-in transaction." })] }) }));
|
|
188
204
|
const mainView = ((0, jsx_runtime_1.jsxs)("div", { className: classes?.container ||
|
|
189
205
|
"anyspend-custom-exact-in-container mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [headerContent, (0, jsx_runtime_1.jsx)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [paymentType === "crypto" ? ((0, jsx_runtime_1.jsx)(CryptoPaySection_1.CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(useAnyspendFlow_1.PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : ((0, jsx_runtime_1.jsx)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: (0, jsx_runtime_1.jsx)(PanelOnramp_1.PanelOnramp, { srcAmountOnRamp: srcAmount, setSrcAmountOnRamp: setSrcAmount, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: selectedRecipientOrDefault, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, hideDstToken: true, destinationAmount: dstAmount, onDestinationTokenChange: () => { }, onDestinationChainChange: () => { }, fiatPaymentMethodIndex: useAnyspendFlow_1.PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.FEE_DETAIL), customUsdInputValues: customUsdInputValues, customRecipientLabel: customRecipientLabel }) })), (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: (0, jsx_runtime_1.jsx)(react_2.Button, { variant: "ghost", className: classes?.swapDirectionButton ||
|
|
190
|
-
"swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode:
|
|
206
|
+
"swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: false, effectiveRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => setActivePanel(useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION), dstAmount: isSrcInputDirty ? dstAmount : dstAmountInput, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
|
|
191
207
|
setIsSrcInputDirty(false);
|
|
192
|
-
|
|
208
|
+
setDstAmountInput(value);
|
|
193
209
|
}, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.FEE_DETAIL) }))] }) }), (0, jsx_runtime_1.jsx)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: (0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (btnInfo.error && classes?.mainButtonError) ||
|
|
194
210
|
(btnInfo.disable && classes?.mainButtonDisabled) ||
|
|
195
211
|
classes?.mainButton ||
|
|
@@ -198,20 +214,49 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
198
214
|
try {
|
|
199
215
|
(0, invariant_1.default)(anyspendQuote, "Relay price is not found");
|
|
200
216
|
(0, invariant_1.default)(selectedRecipientOrDefault, "Recipient address is not found");
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
if (tradeType === "EXACT_OUTPUT") {
|
|
218
|
+
// EXACT_OUTPUT mode: create a custom order (like AnySpendStakeUpside)
|
|
219
|
+
const srcAmountFromQuote = anyspendQuote.data?.currencyIn?.amount;
|
|
220
|
+
(0, invariant_1.default)(srcAmountFromQuote, "Source amount from quote is not found");
|
|
221
|
+
const expectedDstAmount = anyspendQuote.data?.currencyOut?.amount ?? "0";
|
|
222
|
+
const encodedData = (0, useAnyspendFlow_1.generateEncodedData)(customExactInConfig, activeOutputAmountInWei);
|
|
223
|
+
createOrder({
|
|
224
|
+
recipientAddress: selectedRecipientOrDefault,
|
|
225
|
+
orderType: "custom",
|
|
226
|
+
srcChain: selectedSrcChainId,
|
|
227
|
+
dstChain: selectedDstChainId,
|
|
228
|
+
srcToken: selectedSrcToken,
|
|
229
|
+
dstToken: selectedDstToken,
|
|
230
|
+
srcAmount: srcAmountFromQuote,
|
|
231
|
+
expectedDstAmount,
|
|
232
|
+
creatorAddress: globalAddress,
|
|
233
|
+
payload: {
|
|
234
|
+
amount: activeOutputAmountInWei,
|
|
235
|
+
data: encodedData,
|
|
236
|
+
to: customExactInConfig ? (0, utils_1.normalizeAddress)(customExactInConfig.to) : undefined,
|
|
237
|
+
spenderAddress: customExactInConfig?.spenderAddress
|
|
238
|
+
? (0, utils_1.normalizeAddress)(customExactInConfig.spenderAddress)
|
|
239
|
+
: undefined,
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
// EXACT_INPUT mode: create custom_exact_in order (original behavior)
|
|
245
|
+
const srcAmountBigInt = BigInt(activeInputAmountInWei);
|
|
246
|
+
const payload = buildCustomPayload(selectedRecipientOrDefault);
|
|
247
|
+
createOrder({
|
|
248
|
+
recipientAddress: selectedRecipientOrDefault,
|
|
249
|
+
orderType,
|
|
250
|
+
srcChain: selectedSrcChainId,
|
|
251
|
+
dstChain: selectedDstChainId,
|
|
252
|
+
srcToken: selectedSrcToken,
|
|
253
|
+
dstToken: selectedDstToken,
|
|
254
|
+
srcAmount: srcAmountBigInt.toString(),
|
|
255
|
+
expectedDstAmount: expectedDstAmountRaw,
|
|
256
|
+
creatorAddress: globalAddress,
|
|
257
|
+
payload,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
215
260
|
}
|
|
216
261
|
catch (err) {
|
|
217
262
|
console.error(err);
|
|
@@ -247,23 +292,50 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
247
292
|
react_2.toast.error("Please select a payment method");
|
|
248
293
|
return;
|
|
249
294
|
}
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
295
|
+
const onrampOptions = {
|
|
296
|
+
vendor,
|
|
297
|
+
paymentMethod: paymentMethodString,
|
|
298
|
+
country: geoData?.country || "US",
|
|
299
|
+
redirectUrl: window.location.origin,
|
|
300
|
+
};
|
|
301
|
+
if (tradeType === "EXACT_OUTPUT") {
|
|
302
|
+
// EXACT_OUTPUT mode: create a custom order (like AnySpendStakeUpside)
|
|
303
|
+
const expectedDstAmount = anyspendQuote.data?.currencyOut?.amount ?? "0";
|
|
304
|
+
const encodedData = (0, useAnyspendFlow_1.generateEncodedData)(customExactInConfig, activeOutputAmountInWei);
|
|
305
|
+
createOnrampOrder({
|
|
306
|
+
recipientAddress: selectedRecipientOrDefault,
|
|
307
|
+
orderType: "custom",
|
|
308
|
+
dstChain: selectedDstChainId,
|
|
309
|
+
dstToken: selectedDstToken,
|
|
310
|
+
srcFiatAmount: srcAmount,
|
|
311
|
+
onramp: onrampOptions,
|
|
312
|
+
expectedDstAmount,
|
|
313
|
+
creatorAddress: globalAddress,
|
|
314
|
+
payload: {
|
|
315
|
+
amount: activeOutputAmountInWei,
|
|
316
|
+
data: encodedData,
|
|
317
|
+
to: customExactInConfig ? (0, utils_1.normalizeAddress)(customExactInConfig.to) : undefined,
|
|
318
|
+
spenderAddress: customExactInConfig?.spenderAddress
|
|
319
|
+
? (0, utils_1.normalizeAddress)(customExactInConfig.spenderAddress)
|
|
320
|
+
: undefined,
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
// EXACT_INPUT mode: create custom_exact_in order (original behavior)
|
|
326
|
+
const payload = buildCustomPayload(selectedRecipientOrDefault);
|
|
327
|
+
createOnrampOrder({
|
|
328
|
+
recipientAddress: selectedRecipientOrDefault,
|
|
329
|
+
orderType,
|
|
330
|
+
dstChain: selectedDstChainId,
|
|
331
|
+
dstToken: selectedDstToken,
|
|
332
|
+
srcFiatAmount: srcAmount,
|
|
333
|
+
onramp: onrampOptions,
|
|
334
|
+
expectedDstAmount: expectedDstAmountRaw,
|
|
335
|
+
creatorAddress: globalAddress,
|
|
336
|
+
payload,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
267
339
|
}
|
|
268
340
|
catch (err) {
|
|
269
341
|
console.error(err);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { components } from "../../../anyspend/types/api";
|
|
2
|
-
export declare function AnySpendStakeUpsideExactIn({ loadOrder, mode, recipientAddress, sourceTokenAddress, sourceTokenChainId, stakingContractAddress, token, onSuccess, }: {
|
|
2
|
+
export declare function AnySpendStakeUpsideExactIn({ loadOrder, mode, recipientAddress, sourceTokenAddress, sourceTokenChainId, destinationTokenAmount, stakingContractAddress, token, onSuccess, }: {
|
|
3
3
|
loadOrder?: string;
|
|
4
4
|
mode?: "modal" | "page";
|
|
5
5
|
recipientAddress: string;
|
|
@@ -7,5 +7,6 @@ export declare function AnySpendStakeUpsideExactIn({ loadOrder, mode, recipientA
|
|
|
7
7
|
sourceTokenChainId?: number;
|
|
8
8
|
stakingContractAddress: string;
|
|
9
9
|
token: components["schemas"]["Token"];
|
|
10
|
+
destinationTokenAmount?: string;
|
|
10
11
|
onSuccess?: (amount: string) => void;
|
|
11
12
|
}): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -17,7 +17,7 @@ const STAKE_FOR_FUNCTION_ABI = JSON.stringify([
|
|
|
17
17
|
outputs: [],
|
|
18
18
|
},
|
|
19
19
|
]);
|
|
20
|
-
function AnySpendStakeUpsideExactIn({ loadOrder, mode = "modal", recipientAddress, sourceTokenAddress, sourceTokenChainId, stakingContractAddress, token, onSuccess, }) {
|
|
20
|
+
function AnySpendStakeUpsideExactIn({ loadOrder, mode = "modal", recipientAddress, sourceTokenAddress, sourceTokenChainId, destinationTokenAmount, stakingContractAddress, token, onSuccess, }) {
|
|
21
21
|
if (!recipientAddress)
|
|
22
22
|
return null;
|
|
23
23
|
const header = () => ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)("div", { className: "from-b3-react-background to-as-on-surface-1 w-full rounded-t-lg bg-gradient-to-t", children: (0, jsx_runtime_1.jsx)("div", { className: "mb-1 flex w-full flex-col items-center gap-2", children: (0, jsx_runtime_1.jsxs)("span", { className: "font-sf-rounded text-2xl font-semibold", children: ["Swap & Stake ", token.symbol, " (Exact In)"] }) }) }) }));
|
|
@@ -29,5 +29,5 @@ function AnySpendStakeUpsideExactIn({ loadOrder, mode = "modal", recipientAddres
|
|
|
29
29
|
spenderAddress: stakingContractAddress,
|
|
30
30
|
action: `stake ${token.symbol}`,
|
|
31
31
|
};
|
|
32
|
-
return ((0, jsx_runtime_1.jsx)(AnySpendCustomExactIn_1.AnySpendCustomExactIn, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, sourceTokenAddress: sourceTokenAddress, sourceTokenChainId: sourceTokenChainId, destinationToken: token, destinationChainId: chains_1.base.id, customExactInConfig: customExactInConfig, header: header, onSuccess: onSuccess }));
|
|
32
|
+
return ((0, jsx_runtime_1.jsx)(AnySpendCustomExactIn_1.AnySpendCustomExactIn, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, sourceTokenAddress: sourceTokenAddress, sourceTokenChainId: sourceTokenChainId, destinationToken: token, destinationChainId: chains_1.base.id, destinationTokenAmount: destinationTokenAmount, customExactInConfig: customExactInConfig, header: header, onSuccess: onSuccess }));
|
|
33
33
|
}
|
|
@@ -354,13 +354,11 @@ exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal",
|
|
|
354
354
|
if (!srcToken || !dstToken) {
|
|
355
355
|
return (0, jsx_runtime_1.jsx)("div", { children: "Loading..." });
|
|
356
356
|
}
|
|
357
|
-
const expectedDstAmount = order.type === "mint_nft" ||
|
|
358
|
-
order.type === "join_tournament" ||
|
|
359
|
-
order.type === "fund_tournament" ||
|
|
360
|
-
order.type === "custom" ||
|
|
361
|
-
order.type === "deposit_first"
|
|
357
|
+
const expectedDstAmount = order.type === "mint_nft" || order.type === "join_tournament" || order.type === "fund_tournament"
|
|
362
358
|
? "0"
|
|
363
|
-
: order.
|
|
359
|
+
: order.type === "custom" || order.type === "deposit_first"
|
|
360
|
+
? order.payload.amount?.toString() || "0"
|
|
361
|
+
: order.payload.expectedDstAmount.toString();
|
|
364
362
|
const formattedExpectedDstAmount = (0, number_1.formatTokenAmount)(BigInt(expectedDstAmount), dstToken.decimals);
|
|
365
363
|
const actualDstAmount = order.settlement?.actualDstAmount;
|
|
366
364
|
const formattedActualDstAmount = actualDstAmount
|
|
@@ -22,13 +22,12 @@ exports.OrderDetailsCollapsible = (0, react_3.memo)(function OrderDetailsCollaps
|
|
|
22
22
|
const showOrderDetails = isOpen !== undefined ? isOpen : internalOpen;
|
|
23
23
|
const setShowOrderDetails = onOpenChange || setInternalOpen;
|
|
24
24
|
// Calculate expected amount if not provided
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
order.type === "fund_tournament" ||
|
|
28
|
-
order.type === "custom" ||
|
|
29
|
-
order.type === "deposit_first"
|
|
25
|
+
// For custom orders, use payload.amount as the expected destination amount
|
|
26
|
+
const expectedDstAmount = order.type === "mint_nft" || order.type === "join_tournament" || order.type === "fund_tournament"
|
|
30
27
|
? "0"
|
|
31
|
-
: order.
|
|
28
|
+
: order.type === "custom" || order.type === "deposit_first"
|
|
29
|
+
? order.payload.amount?.toString() || "0"
|
|
30
|
+
: order.payload.expectedDstAmount.toString();
|
|
32
31
|
const finalFormattedExpectedDstAmount = formattedExpectedDstAmount || (0, number_1.formatTokenAmount)(BigInt(expectedDstAmount), dstToken.decimals);
|
|
33
32
|
return ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)(classes?.container ||
|
|
34
33
|
"order-details-collapsible bg-as-surface-secondary border-as-border-secondary rounded-xl border px-4 py-2", className), children: showOrderDetails ? ((0, jsx_runtime_1.jsx)(react_2.motion.div, { className: "order-details-expanded w-full", initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: (0, jsx_runtime_1.jsxs)("div", { className: "order-details-content flex w-full flex-col items-center gap-3 whitespace-nowrap py-2 text-sm", children: [(0, jsx_runtime_1.jsxs)("div", { className: "order-details-recipient-section flex w-full justify-between gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-recipient-label text-as-tertiarry", children: "Recipient" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-recipient-info flex flex-col items-end gap-1", children: [recipientName && ((0, jsx_runtime_1.jsx)("div", { className: "order-details-recipient-name text-as-primary font-semibold", children: recipientName })), (0, jsx_runtime_1.jsx)(react_1.CopyToClipboard, { text: order.recipientAddress, onCopy: () => {
|
|
@@ -46,5 +45,5 @@ exports.OrderDetailsCollapsible = (0, react_3.memo)(function OrderDetailsCollaps
|
|
|
46
45
|
? order.metadata.action
|
|
47
46
|
? (0, anyspend_1.capitalizeFirstLetter)(order.metadata.action)
|
|
48
47
|
: "Contract execution"
|
|
49
|
-
: "" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-expected-value flex flex-wrap items-center justify-end gap-2", children: [order.type === "swap" || order.type === "deposit_first" ? ((0, jsx_runtime_1.jsx)("span", { className: "order-details-amount-text", children: `~${finalFormattedExpectedDstAmount} ${dstToken.symbol}` })) : order.type === "mint_nft" ? ((0, jsx_runtime_1.jsxs)("div", { className: "order-details-nft-info flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: nft?.imageUrl, alt: nft?.name || "NFT", className: "order-details-nft-image h-5 w-5" }), (0, jsx_runtime_1.jsx)("div", { className: "order-details-nft-name", children: nft?.name || "NFT" })] })) : order.type === "join_tournament" || order.type === "fund_tournament" ? ((0, jsx_runtime_1.jsxs)("div", { className: "order-details-tournament-info flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: tournament?.imageUrl, alt: tournament?.name || "Tournament", className: "order-details-tournament-image h-5 w-5" }), (0, jsx_runtime_1.jsx)("div", { className: "order-details-tournament-name", children: tournament?.name || "Tournament" })] })) : order.type === "hype_duel" ? ((0, jsx_runtime_1.jsx)("div", { className: "order-details-hype-info flex items-center gap-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "order-details-hype-amount", children: [(0, number_1.formatTokenAmount)(BigInt(order.payload.expectedDstAmount), dstToken.decimals), " HYPE"] }) })) : null, (0, jsx_runtime_1.jsxs)("div", { className: "order-details-chain-info text-as-primary/50 flex items-center gap-2", children: [(0, jsx_runtime_1.jsxs)("span", { className: "order-details-chain-text", children: ["on ", order.dstChain !== chains_1.b3.id && (0, anyspend_1.getChainName)(order.dstChain)] }), (0, jsx_runtime_1.jsx)("img", { src: anyspend_1.ALL_CHAINS[order.dstChain].logoUrl, alt: (0, anyspend_1.getChainName)(order.dstChain), className: (0, utils_1.cn)("order-details-chain-logo h-3", order.dstChain !== chains_1.b3.id && "w-3 rounded-full", order.dstChain === chains_1.b3.id && "h-4") })] })] })] }), points !== undefined && points !== null && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-divider divider w-full" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-points-section flex w-full justify-between gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-points-label text-as-tertiarry", children: "Points" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-points-value text-as-brand font-semibold", children: ["+", (0, formatNumber_1.formatNumber)(points), " pts"] })] })] })), (0, jsx_runtime_1.jsx)("div", { className: "order-details-divider divider w-full" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-id-total-section flex w-full justify-between gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-id-total-label text-as-tertiarry", children: showTotal ? "Total (included fee)" : "Order ID" }), (0, jsx_runtime_1.jsx)("div", { className: "order-details-id-total-value text-as-primary overflow-hidden text-ellipsis whitespace-nowrap", children: showTotal && totalAmount ? totalAmount : order.id })] })] }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "order-details-collapsed flex w-full items-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-collapsed-divider divider w-full" }), (0, jsx_runtime_1.jsx)("button", { className: "order-details-collapsed-button whitespace-nowrap text-sm", onClick: () => setShowOrderDetails(true), children: "Order Details" }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { className: "order-details-collapsed-chevron text-as-primary mx-1 h-4 min-h-4 w-4 min-w-4" }), (0, jsx_runtime_1.jsx)("div", { className: "order-details-collapsed-divider divider w-full" })] })) }));
|
|
48
|
+
: "" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-expected-value flex flex-wrap items-center justify-end gap-2", children: [order.type === "swap" || order.type === "deposit_first" ? ((0, jsx_runtime_1.jsx)("span", { className: "order-details-amount-text", children: `~${finalFormattedExpectedDstAmount} ${dstToken.symbol}` })) : order.type === "mint_nft" ? ((0, jsx_runtime_1.jsxs)("div", { className: "order-details-nft-info flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: nft?.imageUrl, alt: nft?.name || "NFT", className: "order-details-nft-image h-5 w-5" }), (0, jsx_runtime_1.jsx)("div", { className: "order-details-nft-name", children: nft?.name || "NFT" })] })) : order.type === "join_tournament" || order.type === "fund_tournament" ? ((0, jsx_runtime_1.jsxs)("div", { className: "order-details-tournament-info flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: tournament?.imageUrl, alt: tournament?.name || "Tournament", className: "order-details-tournament-image h-5 w-5" }), (0, jsx_runtime_1.jsx)("div", { className: "order-details-tournament-name", children: tournament?.name || "Tournament" })] })) : order.type === "hype_duel" ? ((0, jsx_runtime_1.jsx)("div", { className: "order-details-hype-info flex items-center gap-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "order-details-hype-amount", children: [(0, number_1.formatTokenAmount)(BigInt(order.payload.expectedDstAmount), dstToken.decimals), " HYPE"] }) })) : order.type === "custom" || order.type === "custom_exact_in" ? ((0, jsx_runtime_1.jsx)("span", { className: "order-details-amount-text", children: `~${finalFormattedExpectedDstAmount} ${dstToken.symbol}` })) : null, (0, jsx_runtime_1.jsxs)("div", { className: "order-details-chain-info text-as-primary/50 flex items-center gap-2", children: [(0, jsx_runtime_1.jsxs)("span", { className: "order-details-chain-text", children: ["on ", order.dstChain !== chains_1.b3.id && (0, anyspend_1.getChainName)(order.dstChain)] }), (0, jsx_runtime_1.jsx)("img", { src: anyspend_1.ALL_CHAINS[order.dstChain].logoUrl, alt: (0, anyspend_1.getChainName)(order.dstChain), className: (0, utils_1.cn)("order-details-chain-logo h-3", order.dstChain !== chains_1.b3.id && "w-3 rounded-full", order.dstChain === chains_1.b3.id && "h-4") })] })] })] }), points !== undefined && points !== null && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-divider divider w-full" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-points-section flex w-full justify-between gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-points-label text-as-tertiarry", children: "Points" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-points-value text-as-brand font-semibold", children: ["+", (0, formatNumber_1.formatNumber)(points), " pts"] })] })] })), (0, jsx_runtime_1.jsx)("div", { className: "order-details-divider divider w-full" }), (0, jsx_runtime_1.jsxs)("div", { className: "order-details-id-total-section flex w-full justify-between gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-id-total-label text-as-tertiarry", children: showTotal ? "Total (included fee)" : "Order ID" }), (0, jsx_runtime_1.jsx)("div", { className: "order-details-id-total-value text-as-primary overflow-hidden text-ellipsis whitespace-nowrap", children: showTotal && totalAmount ? totalAmount : order.id })] })] }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "order-details-collapsed flex w-full items-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "order-details-collapsed-divider divider w-full" }), (0, jsx_runtime_1.jsx)("button", { className: "order-details-collapsed-button whitespace-nowrap text-sm", onClick: () => setShowOrderDetails(true), children: "Order Details" }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { className: "order-details-collapsed-chevron text-as-primary mx-1 h-4 min-h-4 w-4 min-w-4" }), (0, jsx_runtime_1.jsx)("div", { className: "order-details-collapsed-divider divider w-full" })] })) }));
|
|
50
49
|
});
|
|
@@ -11,6 +11,19 @@ export declare enum PanelView {
|
|
|
11
11
|
POINTS_DETAIL = 6,
|
|
12
12
|
FEE_DETAIL = 7
|
|
13
13
|
}
|
|
14
|
+
export type CustomExactInConfig = {
|
|
15
|
+
functionAbi: string;
|
|
16
|
+
functionName: string;
|
|
17
|
+
functionArgs: string[];
|
|
18
|
+
to: string;
|
|
19
|
+
spenderAddress?: string;
|
|
20
|
+
action?: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Generates encoded function data for custom contract calls.
|
|
24
|
+
* Handles amount placeholder replacement and BigInt conversion.
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateEncodedData(config: CustomExactInConfig | undefined, amountInWei: string): string | undefined;
|
|
14
27
|
interface UseAnyspendFlowProps {
|
|
15
28
|
paymentType?: "crypto" | "fiat";
|
|
16
29
|
recipientAddress?: string;
|
|
@@ -25,8 +38,9 @@ interface UseAnyspendFlowProps {
|
|
|
25
38
|
slippage?: number;
|
|
26
39
|
disableUrlParamManagement?: boolean;
|
|
27
40
|
orderType?: "hype_duel" | "custom_exact_in" | "swap";
|
|
41
|
+
customExactInConfig?: CustomExactInConfig;
|
|
28
42
|
}
|
|
29
|
-
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, destinationTokenAddress, destinationTokenChainId, slippage, disableUrlParamManagement, orderType, }: UseAnyspendFlowProps): {
|
|
43
|
+
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, destinationTokenAddress, destinationTokenChainId, slippage, disableUrlParamManagement, orderType, customExactInConfig, }: UseAnyspendFlowProps): {
|
|
30
44
|
activePanel: PanelView;
|
|
31
45
|
setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
|
|
32
46
|
orderId: string | undefined;
|
|
@@ -91,8 +105,11 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
91
105
|
setSrcAmount: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
92
106
|
dstAmount: string;
|
|
93
107
|
setDstAmount: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
108
|
+
dstAmountInput: string;
|
|
109
|
+
setDstAmountInput: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
94
110
|
isSrcInputDirty: boolean;
|
|
95
111
|
setIsSrcInputDirty: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
112
|
+
tradeType: string;
|
|
96
113
|
cryptoPaymentMethod: CryptoPaymentMethodType;
|
|
97
114
|
setCryptoPaymentMethod: (method: CryptoPaymentMethodType) => void;
|
|
98
115
|
selectedCryptoPaymentMethod: CryptoPaymentMethodType;
|
|
@@ -176,8 +193,10 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
176
193
|
statusCode: number;
|
|
177
194
|
} | undefined;
|
|
178
195
|
isLoadingAnyspendQuote: boolean;
|
|
196
|
+
isQuoteLoading: boolean;
|
|
179
197
|
getAnyspendQuoteError: Error | null;
|
|
180
198
|
activeInputAmountInWei: string;
|
|
199
|
+
activeOutputAmountInWei: string;
|
|
181
200
|
geoData: import("../../../anyspend/react").GeoData | undefined;
|
|
182
201
|
coinbaseAvailablePaymentMethods: {
|
|
183
202
|
id?: string;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PanelView = void 0;
|
|
4
|
+
exports.generateEncodedData = generateEncodedData;
|
|
4
5
|
exports.useAnyspendFlow = useAnyspendFlow;
|
|
5
6
|
const anyspend_1 = require("../../../anyspend");
|
|
6
7
|
const react_1 = require("../../../anyspend/react");
|
|
7
8
|
const anyspend_2 = require("../../../anyspend/services/anyspend");
|
|
9
|
+
const utils_1 = require("../../../anyspend/utils");
|
|
8
10
|
const react_2 = require("../../../global-account/react");
|
|
9
11
|
const number_1 = require("../../../shared/utils/number");
|
|
10
12
|
const react_3 = require("react");
|
|
@@ -27,8 +29,50 @@ var PanelView;
|
|
|
27
29
|
PanelView[PanelView["POINTS_DETAIL"] = 6] = "POINTS_DETAIL";
|
|
28
30
|
PanelView[PanelView["FEE_DETAIL"] = 7] = "FEE_DETAIL";
|
|
29
31
|
})(PanelView || (exports.PanelView = PanelView = {}));
|
|
32
|
+
/**
|
|
33
|
+
* Generates encoded function data for custom contract calls.
|
|
34
|
+
* Handles amount placeholder replacement and BigInt conversion.
|
|
35
|
+
*/
|
|
36
|
+
function generateEncodedData(config, amountInWei) {
|
|
37
|
+
if (!config || !config.functionAbi || !config.functionName || !config.functionArgs) {
|
|
38
|
+
console.warn("customExactInConfig missing required fields for encoding:", {
|
|
39
|
+
hasConfig: !!config,
|
|
40
|
+
hasFunctionAbi: !!config?.functionAbi,
|
|
41
|
+
hasFunctionName: !!config?.functionName,
|
|
42
|
+
hasFunctionArgs: !!config?.functionArgs,
|
|
43
|
+
});
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const abi = JSON.parse(config.functionAbi);
|
|
48
|
+
const processedArgs = config.functionArgs.map(arg => {
|
|
49
|
+
// Replace amount placeholders ({{dstAmount}}, {{amount_out}}, etc.)
|
|
50
|
+
if (arg === "{{dstAmount}}" || arg === "{{amount_out}}") {
|
|
51
|
+
return BigInt(amountInWei);
|
|
52
|
+
}
|
|
53
|
+
// Convert numeric strings to BigInt for uint256 args
|
|
54
|
+
if (/^\d+$/.test(arg)) {
|
|
55
|
+
return BigInt(arg);
|
|
56
|
+
}
|
|
57
|
+
return arg;
|
|
58
|
+
});
|
|
59
|
+
return (0, viem_1.encodeFunctionData)({
|
|
60
|
+
abi,
|
|
61
|
+
functionName: config.functionName,
|
|
62
|
+
args: processedArgs,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
console.error("Failed to encode function data:", e, {
|
|
67
|
+
functionAbi: config.functionAbi,
|
|
68
|
+
functionName: config.functionName,
|
|
69
|
+
functionArgs: config.functionArgs,
|
|
70
|
+
});
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
30
74
|
// This hook serves for order hype_duel and custom_exact_in
|
|
31
|
-
function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, destinationTokenAddress, destinationTokenChainId, slippage = 0, disableUrlParamManagement = false, orderType = "hype_duel", }) {
|
|
75
|
+
function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, destinationTokenAddress, destinationTokenChainId, slippage = 0, disableUrlParamManagement = false, orderType = "hype_duel", customExactInConfig, }) {
|
|
32
76
|
const searchParams = (0, react_2.useSearchParamsSSR)();
|
|
33
77
|
const router = (0, react_2.useRouter)();
|
|
34
78
|
// Panel and order state
|
|
@@ -43,6 +87,8 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
43
87
|
const [selectedDstToken, setSelectedDstToken] = (0, react_3.useState)(defaultDstToken);
|
|
44
88
|
const [srcAmount, setSrcAmount] = (0, react_3.useState)(paymentType === "fiat" ? "5" : "0");
|
|
45
89
|
const [dstAmount, setDstAmount] = (0, react_3.useState)("");
|
|
90
|
+
const [dstAmountInput, setDstAmountInput] = (0, react_3.useState)(""); // User input for destination amount (EXACT_OUTPUT mode)
|
|
91
|
+
const [debouncedDstAmountInput, setDebouncedDstAmountInput] = (0, react_3.useState)(""); // Debounced version for quote requests
|
|
46
92
|
const [isSrcInputDirty, setIsSrcInputDirty] = (0, react_3.useState)(true);
|
|
47
93
|
// Derive destination chain ID from token or prop (cannot change)
|
|
48
94
|
const selectedDstChainId = destinationTokenChainId || selectedDstToken.chainId;
|
|
@@ -120,6 +166,16 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
120
166
|
};
|
|
121
167
|
fetchDestinationToken();
|
|
122
168
|
}, [destinationTokenAddress, destinationTokenChainId]);
|
|
169
|
+
// Check if destination token is ready (matches the expected address from props)
|
|
170
|
+
// This is important for EXACT_OUTPUT mode where we need correct decimals
|
|
171
|
+
const isDestinationTokenReady = !destinationTokenAddress || selectedDstToken.address.toLowerCase() === destinationTokenAddress.toLowerCase();
|
|
172
|
+
// Debounce destination amount input for quote requests (500ms delay)
|
|
173
|
+
(0, react_3.useEffect)(() => {
|
|
174
|
+
const timer = setTimeout(() => {
|
|
175
|
+
setDebouncedDstAmountInput(dstAmountInput);
|
|
176
|
+
}, 500);
|
|
177
|
+
return () => clearTimeout(timer);
|
|
178
|
+
}, [dstAmountInput]);
|
|
123
179
|
// Helper function for onramp vendor mapping
|
|
124
180
|
const getOnrampVendor = (paymentMethod) => {
|
|
125
181
|
switch (paymentMethod) {
|
|
@@ -133,8 +189,16 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
133
189
|
};
|
|
134
190
|
// Get quote
|
|
135
191
|
// For fiat payments, always use USDC decimals (6) regardless of selectedSrcToken
|
|
136
|
-
const
|
|
137
|
-
const activeInputAmountInWei = (0, viem_1.parseUnits)(srcAmount.replace(/,/g, ""),
|
|
192
|
+
const effectiveSrcDecimals = paymentType === "fiat" ? anyspend_1.USDC_BASE.decimals : selectedSrcToken.decimals;
|
|
193
|
+
const activeInputAmountInWei = (0, viem_1.parseUnits)(srcAmount.replace(/,/g, ""), effectiveSrcDecimals).toString();
|
|
194
|
+
// Calculate output amount in wei for EXACT_OUTPUT mode
|
|
195
|
+
// Only calculate when destination token is ready (has correct decimals)
|
|
196
|
+
// Use debounced value to reduce quote API calls
|
|
197
|
+
const activeOutputAmountInWei = isDestinationTokenReady
|
|
198
|
+
? (0, viem_1.parseUnits)(debouncedDstAmountInput.replace(/,/g, "") || "0", selectedDstToken.decimals).toString()
|
|
199
|
+
: "0";
|
|
200
|
+
// Determine trade type based on which input was last edited
|
|
201
|
+
const tradeType = isSrcInputDirty ? "EXACT_INPUT" : "EXACT_OUTPUT";
|
|
138
202
|
// Build quote request based on order type
|
|
139
203
|
const quoteRequest = (() => {
|
|
140
204
|
const baseParams = {
|
|
@@ -149,8 +213,8 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
149
213
|
return {
|
|
150
214
|
...baseParams,
|
|
151
215
|
type: "swap",
|
|
152
|
-
tradeType:
|
|
153
|
-
amount: activeInputAmountInWei,
|
|
216
|
+
tradeType: tradeType,
|
|
217
|
+
amount: tradeType === "EXACT_INPUT" ? activeInputAmountInWei : activeOutputAmountInWei,
|
|
154
218
|
};
|
|
155
219
|
}
|
|
156
220
|
else if (orderType === "hype_duel") {
|
|
@@ -161,6 +225,22 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
161
225
|
};
|
|
162
226
|
}
|
|
163
227
|
else {
|
|
228
|
+
// custom_exact_in - for EXACT_OUTPUT, use custom type to get the quote
|
|
229
|
+
if (tradeType === "EXACT_OUTPUT") {
|
|
230
|
+
const encodedData = generateEncodedData(customExactInConfig, activeOutputAmountInWei);
|
|
231
|
+
return {
|
|
232
|
+
...baseParams,
|
|
233
|
+
type: "custom",
|
|
234
|
+
payload: {
|
|
235
|
+
amount: activeOutputAmountInWei,
|
|
236
|
+
data: encodedData || "",
|
|
237
|
+
to: customExactInConfig ? (0, utils_1.normalizeAddress)(customExactInConfig.to) : "",
|
|
238
|
+
spenderAddress: customExactInConfig?.spenderAddress
|
|
239
|
+
? (0, utils_1.normalizeAddress)(customExactInConfig.spenderAddress)
|
|
240
|
+
: undefined,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
164
244
|
return {
|
|
165
245
|
...baseParams,
|
|
166
246
|
type: "custom_exact_in",
|
|
@@ -169,22 +249,40 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
169
249
|
}
|
|
170
250
|
})();
|
|
171
251
|
const { anyspendQuote, isLoadingAnyspendQuote, getAnyspendQuoteError } = (0, react_1.useAnyspendQuote)(quoteRequest);
|
|
252
|
+
// Combined loading state: includes debounce waiting period and actual quote fetching
|
|
253
|
+
// For EXACT_OUTPUT mode, also check if we're waiting for debounce
|
|
254
|
+
const isDebouncingDstAmount = tradeType === "EXACT_OUTPUT" && dstAmountInput !== debouncedDstAmountInput;
|
|
255
|
+
const isQuoteLoading = isLoadingAnyspendQuote || isDebouncingDstAmount;
|
|
172
256
|
// Get geo options for fiat
|
|
173
257
|
const { geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support } = (0, react_1.useGeoOnrampOptions)(paymentType === "fiat" ? (0, number_1.formatUnits)(activeInputAmountInWei, anyspend_1.USDC_BASE.decimals) : "0");
|
|
174
|
-
// Update
|
|
258
|
+
// Update amounts when quote changes based on trade type
|
|
175
259
|
(0, react_3.useEffect)(() => {
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
260
|
+
if (isSrcInputDirty) {
|
|
261
|
+
// EXACT_INPUT mode: update destination amount from quote
|
|
262
|
+
if (anyspendQuote?.data?.currencyOut?.amount && anyspendQuote.data.currencyOut.currency?.decimals) {
|
|
263
|
+
const amount = anyspendQuote.data.currencyOut.amount;
|
|
264
|
+
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
265
|
+
// Apply slippage (0-100) - reduce amount by slippage percentage
|
|
266
|
+
const amountWithSlippage = (BigInt(amount) * BigInt(100 - slippage)) / BigInt(100);
|
|
267
|
+
const formattedAmount = (0, number_1.formatTokenAmount)(amountWithSlippage, decimals, 6, false);
|
|
268
|
+
setDstAmount(formattedAmount);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
setDstAmount("");
|
|
272
|
+
}
|
|
183
273
|
}
|
|
184
274
|
else {
|
|
185
|
-
|
|
275
|
+
// EXACT_OUTPUT mode: update source amount from quote
|
|
276
|
+
if (anyspendQuote?.data?.currencyIn?.amount && anyspendQuote.data.currencyIn.currency?.decimals) {
|
|
277
|
+
const amount = anyspendQuote.data.currencyIn.amount;
|
|
278
|
+
const decimals = anyspendQuote.data.currencyIn.currency.decimals;
|
|
279
|
+
const formattedAmount = (0, number_1.formatTokenAmount)(BigInt(amount), decimals, 6, false);
|
|
280
|
+
setSrcAmount(formattedAmount);
|
|
281
|
+
}
|
|
282
|
+
// Also set the display destination amount from the user input
|
|
283
|
+
setDstAmount(dstAmountInput);
|
|
186
284
|
}
|
|
187
|
-
}, [anyspendQuote, slippage]);
|
|
285
|
+
}, [anyspendQuote, slippage, isSrcInputDirty, dstAmountInput]);
|
|
188
286
|
// Update useEffect for URL parameter to not override loadOrder
|
|
189
287
|
(0, react_3.useEffect)(() => {
|
|
190
288
|
if (loadOrder || disableUrlParamManagement)
|
|
@@ -269,8 +367,11 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
269
367
|
setSrcAmount,
|
|
270
368
|
dstAmount,
|
|
271
369
|
setDstAmount,
|
|
370
|
+
dstAmountInput,
|
|
371
|
+
setDstAmountInput,
|
|
272
372
|
isSrcInputDirty,
|
|
273
373
|
setIsSrcInputDirty,
|
|
374
|
+
tradeType,
|
|
274
375
|
// Payment methods
|
|
275
376
|
cryptoPaymentMethod,
|
|
276
377
|
setCryptoPaymentMethod,
|
|
@@ -291,8 +392,10 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
291
392
|
// Quote data
|
|
292
393
|
anyspendQuote,
|
|
293
394
|
isLoadingAnyspendQuote,
|
|
395
|
+
isQuoteLoading, // Combined loading state (includes debounce + quote fetching)
|
|
294
396
|
getAnyspendQuoteError,
|
|
295
397
|
activeInputAmountInWei,
|
|
398
|
+
activeOutputAmountInWei, // User's destination amount input in wei (for EXACT_OUTPUT mode)
|
|
296
399
|
// Geo/onramp data
|
|
297
400
|
geoData,
|
|
298
401
|
coinbaseAvailablePaymentMethods,
|
|
@@ -38,7 +38,7 @@ function useRecipientAddressState({ recipientAddressFromProps, walletAddress, gl
|
|
|
38
38
|
// selectedRecipientAddress: explicitly selected by user (undefined means no explicit selection)
|
|
39
39
|
const [selectedRecipientAddress, setSelectedRecipientAddress] = (0, react_1.useState)(undefined);
|
|
40
40
|
// The effective recipient address, derived on each render, respecting priority.
|
|
41
|
-
const effectiveRecipientAddress =
|
|
41
|
+
const effectiveRecipientAddress = selectedRecipientAddress || recipientAddressFromProps || walletAddress || globalAddress;
|
|
42
42
|
// Helper function to reset user's manual selection.
|
|
43
43
|
const resetRecipientAddress = () => {
|
|
44
44
|
setSelectedRecipientAddress(undefined);
|