@b3dotfun/sdk 0.0.63-test.0 → 0.0.63
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 +34 -0
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +275 -0
- package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.d.ts +9 -0
- package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.js +288 -0
- package/dist/cjs/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +11 -0
- package/dist/cjs/anyspend/react/components/AnySpendStakeUpsideExactIn.js +33 -0
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +10 -2
- package/dist/cjs/anyspend/react/components/common/OrderDetailsCollapsible.js +2 -3
- package/dist/cjs/anyspend/react/components/index.d.ts +5 -1
- package/dist/cjs/anyspend/react/components/index.js +11 -3
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +25 -3
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +30 -8
- package/dist/cjs/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +116 -0
- package/dist/cjs/anyspend/react/hooks/useAnyspendQuote.js +1 -1
- package/dist/cjs/anyspend/types/api.d.ts +665 -3
- package/dist/cjs/anyspend/utils/orderPayload.js +4 -0
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +10 -1
- package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStep.js +2 -2
- package/dist/cjs/global-account/react/hooks/useAuthentication.d.ts +2 -2
- package/dist/cjs/global-account/react/hooks/useAuthentication.js +7 -2
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +31 -1
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.d.ts +34 -0
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +269 -0
- package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.d.ts +9 -0
- package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.js +285 -0
- package/dist/esm/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +11 -0
- package/dist/esm/anyspend/react/components/AnySpendStakeUpsideExactIn.js +30 -0
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +10 -2
- package/dist/esm/anyspend/react/components/common/OrderDetailsCollapsible.js +2 -3
- package/dist/esm/anyspend/react/components/index.d.ts +5 -1
- package/dist/esm/anyspend/react/components/index.js +5 -1
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +25 -3
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +30 -8
- package/dist/esm/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +116 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendQuote.js +1 -1
- package/dist/esm/anyspend/types/api.d.ts +665 -3
- package/dist/esm/anyspend/utils/orderPayload.js +4 -0
- package/dist/esm/global-account/react/components/B3DynamicModal.js +11 -2
- package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStep.js +2 -2
- package/dist/esm/global-account/react/hooks/useAuthentication.d.ts +2 -2
- package/dist/esm/global-account/react/hooks/useAuthentication.js +7 -2
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +31 -1
- package/dist/types/anyspend/react/components/AnySpendCustomExactIn.d.ts +34 -0
- package/dist/types/anyspend/react/components/AnySpendStakeB3ExactIn.d.ts +9 -0
- package/dist/types/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +11 -0
- package/dist/types/anyspend/react/components/index.d.ts +5 -1
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +25 -3
- package/dist/types/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +116 -0
- package/dist/types/anyspend/types/api.d.ts +665 -3
- package/dist/types/global-account/react/hooks/useAuthentication.d.ts +2 -2
- package/dist/types/global-account/react/stores/useModalStore.d.ts +31 -1
- package/package.json +3 -3
- package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +595 -0
- package/src/anyspend/react/components/AnySpendStakeB3ExactIn.tsx +522 -0
- package/src/anyspend/react/components/AnySpendStakeUpsideExactIn.tsx +73 -0
- package/src/anyspend/react/components/common/OrderDetails.tsx +10 -2
- package/src/anyspend/react/components/common/OrderDetailsCollapsible.tsx +2 -3
- package/src/anyspend/react/components/index.ts +5 -1
- package/src/anyspend/react/hooks/useAnyspendFlow.ts +38 -8
- package/src/anyspend/react/hooks/useAnyspendQuote.ts +1 -1
- package/src/anyspend/types/api.ts +669 -1
- package/src/anyspend/utils/orderPayload.ts +5 -1
- package/src/global-account/react/components/B3DynamicModal.tsx +11 -1
- package/src/global-account/react/components/SignInWithB3/steps/LoginStep.tsx +2 -2
- package/src/global-account/react/hooks/useAuthentication.ts +10 -2
- package/src/global-account/react/stores/useModalStore.ts +34 -0
|
@@ -8,9 +8,9 @@ export declare function useAuthentication(partnerId: string): {
|
|
|
8
8
|
isConnected: boolean;
|
|
9
9
|
wallet: import("thirdweb/dist/types/wallets/in-app/core/wallet/types").EcosystemWallet;
|
|
10
10
|
preAuthenticate: typeof preAuthenticate;
|
|
11
|
-
connect: (
|
|
11
|
+
connect: (_walleAutoConnectedWith: Wallet, allConnectedWallets: Wallet[]) => Promise<void>;
|
|
12
12
|
isAuthenticating: boolean;
|
|
13
|
-
onConnect: (
|
|
13
|
+
onConnect: (_walleAutoConnectedWith: Wallet, allConnectedWallets: Wallet[]) => Promise<void>;
|
|
14
14
|
user: {
|
|
15
15
|
email?: string | undefined;
|
|
16
16
|
username?: string | undefined;
|
|
@@ -210,6 +210,20 @@ export interface AnySpendStakeB3Props extends BaseModalProps {
|
|
|
210
210
|
/** Callback function called when the stake is successful */
|
|
211
211
|
onSuccess?: () => void;
|
|
212
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Props for the AnySpend Stake B3 (Custom Exact In) modal
|
|
215
|
+
* Handles B3 token staking operations using the custom exact in flow
|
|
216
|
+
*/
|
|
217
|
+
export interface AnySpendStakeB3ExactInProps extends BaseModalProps {
|
|
218
|
+
/** Modal type identifier */
|
|
219
|
+
type: "anySpendStakeB3ExactIn";
|
|
220
|
+
/** Recipient address to stake B3 for */
|
|
221
|
+
recipientAddress: string;
|
|
222
|
+
/** Stake amount */
|
|
223
|
+
stakeAmount?: string;
|
|
224
|
+
/** Callback function called when the stake is successful */
|
|
225
|
+
onSuccess?: () => void;
|
|
226
|
+
}
|
|
213
227
|
/**
|
|
214
228
|
* Props for the AnySpend Stake Contract modal
|
|
215
229
|
* Handles token staking operations to a given contract
|
|
@@ -230,6 +244,22 @@ export interface AnySpendStakeUpsideProps extends BaseModalProps {
|
|
|
230
244
|
/** Callback function called when the stake is successful */
|
|
231
245
|
onSuccess?: () => void;
|
|
232
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Props for the AnySpend Stake Upside (Exact In) modal
|
|
249
|
+
* Handles token staking operations using the custom exact in flow
|
|
250
|
+
*/
|
|
251
|
+
export interface AnySpendStakeUpsideExactInProps extends BaseModalProps {
|
|
252
|
+
/** Modal type identifier */
|
|
253
|
+
type: "anySpendStakeUpsideExactIn";
|
|
254
|
+
/** Recipient address to stake tokens for */
|
|
255
|
+
recipientAddress: string;
|
|
256
|
+
/** Staking contract address */
|
|
257
|
+
stakingContractAddress: string;
|
|
258
|
+
/** Token to stake */
|
|
259
|
+
token: components["schemas"]["Token"];
|
|
260
|
+
/** Callback function called when the stake is successful */
|
|
261
|
+
onSuccess?: () => void;
|
|
262
|
+
}
|
|
233
263
|
/**
|
|
234
264
|
* Props for the AnySpend Buy Spin modal
|
|
235
265
|
* Handles spin wheel entry purchases
|
|
@@ -324,7 +354,7 @@ export interface AvatarEditorModalProps extends BaseModalProps {
|
|
|
324
354
|
/**
|
|
325
355
|
* Union type of all possible modal content types
|
|
326
356
|
*/
|
|
327
|
-
export type ModalContentType = SignInWithB3ModalProps | RequestPermissionsModalProps | ManageAccountModalProps | AnySpendModalProps | AnyspendOrderDetailsProps | AnySpendNftProps | AnySpendJoinTournamentProps | AnySpendFundTournamentProps | AnySpendOrderHistoryProps | AnySpendStakeB3Props | AnySpendStakeUpsideProps | AnySpendBuySpinProps | AnySpendSignatureMintProps | AnySpendBondKitProps | LinkAccountModalProps | AnySpendDepositHypeProps | AvatarEditorModalProps;
|
|
357
|
+
export type ModalContentType = SignInWithB3ModalProps | RequestPermissionsModalProps | ManageAccountModalProps | AnySpendModalProps | AnyspendOrderDetailsProps | AnySpendNftProps | AnySpendJoinTournamentProps | AnySpendFundTournamentProps | AnySpendOrderHistoryProps | AnySpendStakeB3Props | AnySpendStakeB3ExactInProps | AnySpendStakeUpsideProps | AnySpendStakeUpsideExactInProps | AnySpendBuySpinProps | AnySpendSignatureMintProps | AnySpendBondKitProps | LinkAccountModalProps | AnySpendDepositHypeProps | AvatarEditorModalProps;
|
|
328
358
|
/**
|
|
329
359
|
* State interface for the modal store
|
|
330
360
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b3dotfun/sdk",
|
|
3
|
-
"version": "0.0.63
|
|
3
|
+
"version": "0.0.63",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"react-native": "./dist/cjs/index.native.js",
|
|
@@ -358,7 +358,7 @@
|
|
|
358
358
|
"postcss-prefix-selector": "^2.1.1",
|
|
359
359
|
"tailwindcss": "3.4.1",
|
|
360
360
|
"tailwindcss-animate": "^1.0.7",
|
|
361
|
-
"thirdweb": "5.
|
|
361
|
+
"thirdweb": "5.112.0",
|
|
362
362
|
"tsc-alias": "^1.8.16",
|
|
363
363
|
"tsc-watch": "^7.1.1",
|
|
364
364
|
"vitest": "^3.2.4"
|
|
@@ -381,7 +381,7 @@
|
|
|
381
381
|
"react": "^18.0.0 || ^19.0.0",
|
|
382
382
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
383
383
|
"react-native-mmkv": "^3.2.0",
|
|
384
|
-
"thirdweb": "5.
|
|
384
|
+
"thirdweb": "5.112.0",
|
|
385
385
|
"three": "^0.175.0",
|
|
386
386
|
"viem": "2.37.9",
|
|
387
387
|
"wagmi": "2.16.9"
|
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
import { components } from "@b3dotfun/sdk/anyspend/types/api";
|
|
2
|
+
import { GetQuoteResponse } from "@b3dotfun/sdk/anyspend/types/api_req_res";
|
|
3
|
+
import { normalizeAddress } from "@b3dotfun/sdk/anyspend/utils";
|
|
4
|
+
import { Button, ShinyButton, StyleRoot, TransitionPanel, useAccountWallet } from "@b3dotfun/sdk/global-account/react";
|
|
5
|
+
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
6
|
+
import invariant from "invariant";
|
|
7
|
+
import { ArrowDown, Loader2 } from "lucide-react";
|
|
8
|
+
import { motion } from "motion/react";
|
|
9
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
10
|
+
import { toast } from "sonner";
|
|
11
|
+
import { useActiveWallet, useSetActiveWallet } from "thirdweb/react";
|
|
12
|
+
import { useGlobalWalletState } from "../../utils";
|
|
13
|
+
import { PanelView, useAnyspendFlow } from "../hooks/useAnyspendFlow";
|
|
14
|
+
import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper";
|
|
15
|
+
import { CryptoPaySection } from "./common/CryptoPaySection";
|
|
16
|
+
import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod";
|
|
17
|
+
import { CryptoReceiveSection } from "./common/CryptoReceiveSection";
|
|
18
|
+
import { FeeDetailPanel } from "./common/FeeDetailPanel";
|
|
19
|
+
import { FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaymentMethod";
|
|
20
|
+
import { OrderDetails } from "./common/OrderDetails";
|
|
21
|
+
import { PanelOnramp } from "./common/PanelOnramp";
|
|
22
|
+
import { PointsDetailPanel } from "./common/PointsDetailPanel";
|
|
23
|
+
import { RecipientSelection } from "./common/RecipientSelection";
|
|
24
|
+
|
|
25
|
+
const SLIPPAGE_PERCENT = 3;
|
|
26
|
+
|
|
27
|
+
type CustomExactInConfig = {
|
|
28
|
+
functionAbi: string;
|
|
29
|
+
functionName: string;
|
|
30
|
+
functionArgs: string[];
|
|
31
|
+
to: string;
|
|
32
|
+
spenderAddress?: string;
|
|
33
|
+
action?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export interface AnySpendCustomExactInProps {
|
|
37
|
+
loadOrder?: string;
|
|
38
|
+
mode?: "modal" | "page";
|
|
39
|
+
recipientAddress: string;
|
|
40
|
+
paymentType?: "crypto" | "fiat";
|
|
41
|
+
sourceTokenAddress?: string;
|
|
42
|
+
sourceTokenChainId?: number;
|
|
43
|
+
destinationToken: components["schemas"]["Token"];
|
|
44
|
+
destinationChainId: number;
|
|
45
|
+
onSuccess?: (amount: string) => void;
|
|
46
|
+
mainFooter?: React.ReactNode;
|
|
47
|
+
onTokenSelect?: (token: components["schemas"]["Token"], event: { preventDefault: () => void }) => void;
|
|
48
|
+
customUsdInputValues?: string[];
|
|
49
|
+
preferEoa?: boolean;
|
|
50
|
+
customExactInConfig: CustomExactInConfig;
|
|
51
|
+
header?: ({
|
|
52
|
+
anyspendPrice,
|
|
53
|
+
isLoadingAnyspendPrice,
|
|
54
|
+
}: {
|
|
55
|
+
anyspendPrice: GetQuoteResponse | undefined;
|
|
56
|
+
isLoadingAnyspendPrice: boolean;
|
|
57
|
+
}) => React.JSX.Element;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function AnySpendCustomExactIn(props: AnySpendCustomExactInProps) {
|
|
61
|
+
const fingerprintConfig = getFingerprintConfig();
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<AnySpendFingerprintWrapper fingerprint={fingerprintConfig}>
|
|
65
|
+
<AnySpendCustomExactInInner {...props} />
|
|
66
|
+
</AnySpendFingerprintWrapper>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function AnySpendCustomExactInInner({
|
|
71
|
+
loadOrder,
|
|
72
|
+
mode = "modal",
|
|
73
|
+
recipientAddress,
|
|
74
|
+
paymentType = "crypto",
|
|
75
|
+
sourceTokenAddress,
|
|
76
|
+
sourceTokenChainId,
|
|
77
|
+
destinationToken,
|
|
78
|
+
destinationChainId,
|
|
79
|
+
onSuccess,
|
|
80
|
+
mainFooter,
|
|
81
|
+
onTokenSelect,
|
|
82
|
+
customUsdInputValues,
|
|
83
|
+
preferEoa,
|
|
84
|
+
customExactInConfig,
|
|
85
|
+
header,
|
|
86
|
+
}: AnySpendCustomExactInProps) {
|
|
87
|
+
const actionLabel = customExactInConfig.action ?? "Custom Execution";
|
|
88
|
+
|
|
89
|
+
const DESTINATION_TOKEN_DETAILS = {
|
|
90
|
+
SYMBOL: destinationToken.symbol ?? "TOKEN",
|
|
91
|
+
LOGO_URI: destinationToken.metadata?.logoURI ?? "",
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const {
|
|
95
|
+
activePanel,
|
|
96
|
+
setActivePanel,
|
|
97
|
+
orderId,
|
|
98
|
+
setOrderId,
|
|
99
|
+
oat,
|
|
100
|
+
selectedSrcChainId,
|
|
101
|
+
setSelectedSrcChainId,
|
|
102
|
+
selectedSrcToken,
|
|
103
|
+
setSelectedSrcToken,
|
|
104
|
+
selectedDstToken,
|
|
105
|
+
selectedDstChainId,
|
|
106
|
+
srcAmount,
|
|
107
|
+
setSrcAmount,
|
|
108
|
+
dstAmount,
|
|
109
|
+
isSrcInputDirty,
|
|
110
|
+
setIsSrcInputDirty,
|
|
111
|
+
selectedCryptoPaymentMethod,
|
|
112
|
+
setSelectedCryptoPaymentMethod,
|
|
113
|
+
selectedFiatPaymentMethod,
|
|
114
|
+
setSelectedFiatPaymentMethod,
|
|
115
|
+
selectedRecipientAddress,
|
|
116
|
+
setSelectedRecipientAddress,
|
|
117
|
+
recipientName,
|
|
118
|
+
globalAddress,
|
|
119
|
+
hasEnoughBalance,
|
|
120
|
+
isBalanceLoading,
|
|
121
|
+
anyspendQuote,
|
|
122
|
+
isLoadingAnyspendQuote,
|
|
123
|
+
activeInputAmountInWei,
|
|
124
|
+
geoData,
|
|
125
|
+
coinbaseAvailablePaymentMethods,
|
|
126
|
+
stripeWeb2Support,
|
|
127
|
+
createOrder,
|
|
128
|
+
isCreatingOrder,
|
|
129
|
+
createOnrampOrder,
|
|
130
|
+
isCreatingOnrampOrder,
|
|
131
|
+
} = useAnyspendFlow({
|
|
132
|
+
paymentType,
|
|
133
|
+
recipientAddress,
|
|
134
|
+
loadOrder,
|
|
135
|
+
isDepositMode: true,
|
|
136
|
+
onTransactionSuccess: onSuccess,
|
|
137
|
+
sourceTokenAddress,
|
|
138
|
+
sourceTokenChainId,
|
|
139
|
+
destinationTokenAddress: destinationToken.address,
|
|
140
|
+
destinationTokenChainId: destinationChainId,
|
|
141
|
+
slippage: SLIPPAGE_PERCENT,
|
|
142
|
+
disableUrlParamManagement: true,
|
|
143
|
+
orderType: "custom_exact_in",
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const { connectedEOAWallet } = useAccountWallet();
|
|
147
|
+
const setActiveWallet = useSetActiveWallet();
|
|
148
|
+
const activeWallet = useActiveWallet();
|
|
149
|
+
const setGlobalAccountWallet = useGlobalWalletState(state => state.setGlobalAccountWallet);
|
|
150
|
+
const appliedPreferEoa = useRef(false);
|
|
151
|
+
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (preferEoa && !appliedPreferEoa.current) {
|
|
154
|
+
if (connectedEOAWallet) {
|
|
155
|
+
appliedPreferEoa.current = true;
|
|
156
|
+
setGlobalAccountWallet(activeWallet);
|
|
157
|
+
setActiveWallet(connectedEOAWallet);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}, [preferEoa, connectedEOAWallet, setActiveWallet, activeWallet, setGlobalAccountWallet]);
|
|
161
|
+
|
|
162
|
+
const selectedRecipientOrDefault = selectedRecipientAddress ?? recipientAddress;
|
|
163
|
+
|
|
164
|
+
const expectedDstAmountRaw = anyspendQuote?.data?.currencyOut?.amount ?? "0";
|
|
165
|
+
|
|
166
|
+
const buildCustomPayload = (_recipient: string | undefined) => {
|
|
167
|
+
return {
|
|
168
|
+
amount: expectedDstAmountRaw,
|
|
169
|
+
expectedDstAmount: expectedDstAmountRaw,
|
|
170
|
+
functionAbi: customExactInConfig.functionAbi,
|
|
171
|
+
functionName: customExactInConfig.functionName,
|
|
172
|
+
functionArgs: customExactInConfig.functionArgs,
|
|
173
|
+
to: normalizeAddress(customExactInConfig.to),
|
|
174
|
+
spenderAddress: customExactInConfig.spenderAddress
|
|
175
|
+
? normalizeAddress(customExactInConfig.spenderAddress)
|
|
176
|
+
: undefined,
|
|
177
|
+
action: customExactInConfig.action,
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const btnInfo: { text: string; disable: boolean; error: boolean; loading: boolean } = useMemo(() => {
|
|
182
|
+
if (activeInputAmountInWei === "0") return { text: "Enter an amount", disable: true, error: false, loading: false };
|
|
183
|
+
if (isLoadingAnyspendQuote) return { text: "Loading quote...", disable: true, error: false, loading: true };
|
|
184
|
+
if (isCreatingOrder || isCreatingOnrampOrder)
|
|
185
|
+
return { text: "Creating order...", disable: true, error: false, loading: true };
|
|
186
|
+
if (!selectedRecipientOrDefault) return { text: "Select recipient", disable: false, error: false, loading: false };
|
|
187
|
+
if (!anyspendQuote || !anyspendQuote.success)
|
|
188
|
+
return { text: "Get quote error", disable: true, error: true, loading: false };
|
|
189
|
+
|
|
190
|
+
if (paymentType === "crypto") {
|
|
191
|
+
if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
|
|
192
|
+
return { text: "Choose payment method", disable: false, error: false, loading: false };
|
|
193
|
+
}
|
|
194
|
+
if (
|
|
195
|
+
!hasEnoughBalance &&
|
|
196
|
+
!isBalanceLoading &&
|
|
197
|
+
selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
|
|
198
|
+
) {
|
|
199
|
+
return { text: "Insufficient balance", disable: true, error: true, loading: false };
|
|
200
|
+
}
|
|
201
|
+
return { text: `Execute ${actionLabel}`, disable: false, error: false, loading: false };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (paymentType === "fiat") {
|
|
205
|
+
if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
|
|
206
|
+
return { text: "Select payment method", disable: false, error: false, loading: false };
|
|
207
|
+
}
|
|
208
|
+
return { text: "Buy", disable: false, error: false, loading: false };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return { text: "Continue", disable: false, error: false, loading: false };
|
|
212
|
+
}, [
|
|
213
|
+
activeInputAmountInWei,
|
|
214
|
+
isLoadingAnyspendQuote,
|
|
215
|
+
isCreatingOrder,
|
|
216
|
+
isCreatingOnrampOrder,
|
|
217
|
+
selectedRecipientOrDefault,
|
|
218
|
+
anyspendQuote,
|
|
219
|
+
paymentType,
|
|
220
|
+
selectedCryptoPaymentMethod,
|
|
221
|
+
selectedFiatPaymentMethod,
|
|
222
|
+
hasEnoughBalance,
|
|
223
|
+
isBalanceLoading,
|
|
224
|
+
actionLabel,
|
|
225
|
+
]);
|
|
226
|
+
|
|
227
|
+
const onMainButtonClick = async () => {
|
|
228
|
+
if (btnInfo.disable) return;
|
|
229
|
+
|
|
230
|
+
if (!selectedRecipientOrDefault) {
|
|
231
|
+
setActivePanel(PanelView.RECIPIENT_SELECTION);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (paymentType === "crypto") {
|
|
236
|
+
if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
|
|
237
|
+
setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
await handleCryptoOrder();
|
|
241
|
+
} else if (paymentType === "fiat") {
|
|
242
|
+
if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
|
|
243
|
+
setActivePanel(PanelView.FIAT_PAYMENT_METHOD);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
await handleFiatOrder();
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const headerContent = header ? (
|
|
251
|
+
header({ anyspendPrice: anyspendQuote, isLoadingAnyspendPrice: isLoadingAnyspendQuote })
|
|
252
|
+
) : (
|
|
253
|
+
<div className="mb-4 flex flex-col items-center gap-3 text-center">
|
|
254
|
+
<div>
|
|
255
|
+
<h1 className="text-as-primary text-xl font-bold">{actionLabel}</h1>
|
|
256
|
+
<p className="text-as-secondary text-sm">Pay from any token to execute a custom exact-in transaction.</p>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
const mainView = (
|
|
262
|
+
<div className="mx-auto flex w-[460px] max-w-full flex-col items-center gap-2">
|
|
263
|
+
{headerContent}
|
|
264
|
+
|
|
265
|
+
<div className="relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2">
|
|
266
|
+
<div className="relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2">
|
|
267
|
+
{paymentType === "crypto" ? (
|
|
268
|
+
<CryptoPaySection
|
|
269
|
+
selectedSrcChainId={selectedSrcChainId}
|
|
270
|
+
setSelectedSrcChainId={setSelectedSrcChainId}
|
|
271
|
+
selectedSrcToken={selectedSrcToken}
|
|
272
|
+
setSelectedSrcToken={setSelectedSrcToken}
|
|
273
|
+
srcAmount={srcAmount}
|
|
274
|
+
setSrcAmount={setSrcAmount}
|
|
275
|
+
isSrcInputDirty={isSrcInputDirty}
|
|
276
|
+
setIsSrcInputDirty={setIsSrcInputDirty}
|
|
277
|
+
selectedCryptoPaymentMethod={selectedCryptoPaymentMethod}
|
|
278
|
+
onSelectCryptoPaymentMethod={() => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD)}
|
|
279
|
+
anyspendQuote={anyspendQuote}
|
|
280
|
+
onTokenSelect={onTokenSelect}
|
|
281
|
+
/>
|
|
282
|
+
) : (
|
|
283
|
+
<motion.div
|
|
284
|
+
initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
|
|
285
|
+
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
|
286
|
+
transition={{ duration: 0.3, delay: 0, ease: "easeInOut" }}
|
|
287
|
+
>
|
|
288
|
+
<PanelOnramp
|
|
289
|
+
srcAmountOnRamp={srcAmount}
|
|
290
|
+
setSrcAmountOnRamp={setSrcAmount}
|
|
291
|
+
selectedPaymentMethod={selectedFiatPaymentMethod}
|
|
292
|
+
setActivePanel={setActivePanel}
|
|
293
|
+
_recipientAddress={selectedRecipientOrDefault}
|
|
294
|
+
destinationToken={selectedDstToken}
|
|
295
|
+
destinationChainId={selectedDstChainId}
|
|
296
|
+
dstTokenSymbol={DESTINATION_TOKEN_DETAILS.SYMBOL}
|
|
297
|
+
hideDstToken
|
|
298
|
+
destinationAmount={dstAmount}
|
|
299
|
+
onDestinationTokenChange={() => {}}
|
|
300
|
+
onDestinationChainChange={() => {}}
|
|
301
|
+
fiatPaymentMethodIndex={PanelView.FIAT_PAYMENT_METHOD}
|
|
302
|
+
recipientSelectionPanelIndex={PanelView.RECIPIENT_SELECTION}
|
|
303
|
+
anyspendQuote={anyspendQuote}
|
|
304
|
+
onShowPointsDetail={() => setActivePanel(PanelView.POINTS_DETAIL)}
|
|
305
|
+
onShowFeeDetail={() => setActivePanel(PanelView.FEE_DETAIL)}
|
|
306
|
+
customUsdInputValues={customUsdInputValues}
|
|
307
|
+
/>
|
|
308
|
+
</motion.div>
|
|
309
|
+
)}
|
|
310
|
+
|
|
311
|
+
<div
|
|
312
|
+
className={cn("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden")}
|
|
313
|
+
>
|
|
314
|
+
<Button
|
|
315
|
+
variant="ghost"
|
|
316
|
+
className={cn(
|
|
317
|
+
"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",
|
|
318
|
+
)}
|
|
319
|
+
>
|
|
320
|
+
<div className="relative flex items-center justify-center transition-opacity">
|
|
321
|
+
<ArrowDown className="text-as-primary/50 h-5 w-5" />
|
|
322
|
+
</div>
|
|
323
|
+
</Button>
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
{paymentType === "crypto" && (
|
|
327
|
+
<CryptoReceiveSection
|
|
328
|
+
isDepositMode={false}
|
|
329
|
+
isBuyMode={true}
|
|
330
|
+
selectedRecipientAddress={selectedRecipientOrDefault}
|
|
331
|
+
recipientName={recipientName || undefined}
|
|
332
|
+
onSelectRecipient={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
|
|
333
|
+
dstAmount={dstAmount}
|
|
334
|
+
dstToken={selectedDstToken}
|
|
335
|
+
dstTokenSymbol={DESTINATION_TOKEN_DETAILS.SYMBOL}
|
|
336
|
+
dstTokenLogoURI={DESTINATION_TOKEN_DETAILS.LOGO_URI}
|
|
337
|
+
selectedDstChainId={selectedDstChainId}
|
|
338
|
+
setSelectedDstChainId={() => {}}
|
|
339
|
+
setSelectedDstToken={() => {}}
|
|
340
|
+
isSrcInputDirty={isSrcInputDirty}
|
|
341
|
+
onChangeDstAmount={value => {
|
|
342
|
+
setIsSrcInputDirty(false);
|
|
343
|
+
setSrcAmount(value);
|
|
344
|
+
}}
|
|
345
|
+
anyspendQuote={anyspendQuote}
|
|
346
|
+
onShowPointsDetail={() => setActivePanel(PanelView.POINTS_DETAIL)}
|
|
347
|
+
onShowFeeDetail={() => setActivePanel(PanelView.FEE_DETAIL)}
|
|
348
|
+
/>
|
|
349
|
+
)}
|
|
350
|
+
</div>
|
|
351
|
+
</div>
|
|
352
|
+
|
|
353
|
+
<motion.div
|
|
354
|
+
initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
|
|
355
|
+
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
|
356
|
+
transition={{ duration: 0.3, delay: 0.2, ease: "easeInOut" }}
|
|
357
|
+
className={cn("mt-4 flex w-full max-w-[460px] flex-col gap-2")}
|
|
358
|
+
>
|
|
359
|
+
<ShinyButton
|
|
360
|
+
accentColor={"hsl(var(--as-brand))"}
|
|
361
|
+
disabled={btnInfo.disable}
|
|
362
|
+
onClick={onMainButtonClick}
|
|
363
|
+
className={cn(
|
|
364
|
+
"as-main-button relative w-full",
|
|
365
|
+
btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand",
|
|
366
|
+
)}
|
|
367
|
+
textClassName={cn(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white")}
|
|
368
|
+
>
|
|
369
|
+
<div className="flex items-center justify-center gap-2">
|
|
370
|
+
{btnInfo.loading && <Loader2 className="h-4 w-4 animate-spin" />}
|
|
371
|
+
{btnInfo.text}
|
|
372
|
+
</div>
|
|
373
|
+
</ShinyButton>
|
|
374
|
+
</motion.div>
|
|
375
|
+
|
|
376
|
+
{mainFooter ? mainFooter : null}
|
|
377
|
+
</div>
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
const handleCryptoOrder = async () => {
|
|
381
|
+
try {
|
|
382
|
+
invariant(anyspendQuote, "Relay price is not found");
|
|
383
|
+
invariant(selectedRecipientOrDefault, "Recipient address is not found");
|
|
384
|
+
|
|
385
|
+
const srcAmountBigInt = BigInt(activeInputAmountInWei);
|
|
386
|
+
const payload = buildCustomPayload(selectedRecipientOrDefault);
|
|
387
|
+
|
|
388
|
+
createOrder({
|
|
389
|
+
recipientAddress: selectedRecipientOrDefault,
|
|
390
|
+
orderType: "custom_exact_in",
|
|
391
|
+
srcChain: selectedSrcChainId,
|
|
392
|
+
dstChain: selectedDstChainId,
|
|
393
|
+
srcToken: selectedSrcToken,
|
|
394
|
+
dstToken: selectedDstToken,
|
|
395
|
+
srcAmount: srcAmountBigInt.toString(),
|
|
396
|
+
expectedDstAmount: expectedDstAmountRaw,
|
|
397
|
+
creatorAddress: globalAddress,
|
|
398
|
+
payload,
|
|
399
|
+
});
|
|
400
|
+
} catch (err: any) {
|
|
401
|
+
console.error(err);
|
|
402
|
+
toast.error("Failed to create order: " + err.message);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const handleFiatOrder = async () => {
|
|
407
|
+
try {
|
|
408
|
+
invariant(anyspendQuote, "Relay price is not found");
|
|
409
|
+
invariant(selectedRecipientOrDefault, "Recipient address is not found");
|
|
410
|
+
|
|
411
|
+
if (!srcAmount || parseFloat(srcAmount) <= 0) {
|
|
412
|
+
toast.error("Please enter a valid amount");
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
let vendor: "coinbase" | "stripe" | "stripe-web2";
|
|
417
|
+
let paymentMethodString = "";
|
|
418
|
+
|
|
419
|
+
if (selectedFiatPaymentMethod === FiatPaymentMethod.COINBASE_PAY) {
|
|
420
|
+
if (coinbaseAvailablePaymentMethods.length === 0) {
|
|
421
|
+
toast.error("Coinbase Pay not available");
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
vendor = "coinbase";
|
|
425
|
+
paymentMethodString = coinbaseAvailablePaymentMethods[0]?.id || "";
|
|
426
|
+
} else if (selectedFiatPaymentMethod === FiatPaymentMethod.STRIPE) {
|
|
427
|
+
if (!stripeWeb2Support || !stripeWeb2Support.isSupport) {
|
|
428
|
+
toast.error("Stripe not available");
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
vendor = "stripe-web2";
|
|
432
|
+
} else {
|
|
433
|
+
toast.error("Please select a payment method");
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const payload = buildCustomPayload(selectedRecipientOrDefault);
|
|
438
|
+
|
|
439
|
+
createOnrampOrder({
|
|
440
|
+
recipientAddress: selectedRecipientOrDefault,
|
|
441
|
+
orderType: "custom_exact_in",
|
|
442
|
+
dstChain: selectedDstChainId,
|
|
443
|
+
dstToken: selectedDstToken,
|
|
444
|
+
srcFiatAmount: srcAmount,
|
|
445
|
+
onramp: {
|
|
446
|
+
vendor,
|
|
447
|
+
paymentMethod: paymentMethodString,
|
|
448
|
+
country: geoData?.country || "US",
|
|
449
|
+
redirectUrl: window.location.origin,
|
|
450
|
+
},
|
|
451
|
+
expectedDstAmount: expectedDstAmountRaw,
|
|
452
|
+
creatorAddress: globalAddress,
|
|
453
|
+
payload,
|
|
454
|
+
});
|
|
455
|
+
} catch (err: any) {
|
|
456
|
+
console.error(err);
|
|
457
|
+
toast.error("Failed to create order: " + err.message);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
const orderDetailsView = (
|
|
462
|
+
<div className={"mx-auto w-[460px] max-w-full"}>
|
|
463
|
+
<div className="relative flex flex-col gap-4">
|
|
464
|
+
{oat && (
|
|
465
|
+
<OrderDetails
|
|
466
|
+
mode={mode}
|
|
467
|
+
order={oat.data.order}
|
|
468
|
+
depositTxs={oat.data.depositTxs}
|
|
469
|
+
relayTxs={oat.data.relayTxs}
|
|
470
|
+
executeTx={oat.data.executeTx}
|
|
471
|
+
refundTxs={oat.data.refundTxs}
|
|
472
|
+
cryptoPaymentMethod={paymentType === "fiat" ? CryptoPaymentMethodType.NONE : selectedCryptoPaymentMethod}
|
|
473
|
+
selectedCryptoPaymentMethod={selectedCryptoPaymentMethod}
|
|
474
|
+
onPaymentMethodChange={setSelectedCryptoPaymentMethod}
|
|
475
|
+
onBack={() => {
|
|
476
|
+
setOrderId(undefined);
|
|
477
|
+
setActivePanel(PanelView.MAIN);
|
|
478
|
+
}}
|
|
479
|
+
disableUrlParamManagement
|
|
480
|
+
points={oat.data.points || undefined}
|
|
481
|
+
/>
|
|
482
|
+
)}
|
|
483
|
+
</div>
|
|
484
|
+
</div>
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
const loadingView = (
|
|
488
|
+
<div className="mx-auto flex w-full flex-col items-center gap-4 p-5">
|
|
489
|
+
<div className="text-as-primary">Loading order details...</div>
|
|
490
|
+
</div>
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
const recipientSelectionView = (
|
|
494
|
+
<RecipientSelection
|
|
495
|
+
initialValue={selectedRecipientOrDefault || ""}
|
|
496
|
+
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
497
|
+
onConfirm={address => {
|
|
498
|
+
setSelectedRecipientAddress(address);
|
|
499
|
+
setActivePanel(PanelView.MAIN);
|
|
500
|
+
}}
|
|
501
|
+
/>
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
const cryptoPaymentMethodView = (
|
|
505
|
+
<CryptoPaymentMethod
|
|
506
|
+
globalAddress={globalAddress}
|
|
507
|
+
globalWallet={undefined}
|
|
508
|
+
selectedPaymentMethod={selectedCryptoPaymentMethod}
|
|
509
|
+
setSelectedPaymentMethod={setSelectedCryptoPaymentMethod}
|
|
510
|
+
isCreatingOrder={isCreatingOrder}
|
|
511
|
+
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
512
|
+
onSelectPaymentMethod={(method: CryptoPaymentMethodType) => {
|
|
513
|
+
setSelectedCryptoPaymentMethod(method);
|
|
514
|
+
setActivePanel(PanelView.MAIN);
|
|
515
|
+
}}
|
|
516
|
+
/>
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
const fiatPaymentMethodView = (
|
|
520
|
+
<FiatPaymentMethodComponent
|
|
521
|
+
selectedPaymentMethod={selectedFiatPaymentMethod}
|
|
522
|
+
setSelectedPaymentMethod={setSelectedFiatPaymentMethod}
|
|
523
|
+
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
524
|
+
onSelectPaymentMethod={(method: FiatPaymentMethod) => {
|
|
525
|
+
setSelectedFiatPaymentMethod(method);
|
|
526
|
+
setActivePanel(PanelView.MAIN);
|
|
527
|
+
}}
|
|
528
|
+
srcAmountOnRamp={srcAmount}
|
|
529
|
+
/>
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
const pointsDetailView = (
|
|
533
|
+
<PointsDetailPanel
|
|
534
|
+
pointsAmount={anyspendQuote?.data?.pointsAmount || 0}
|
|
535
|
+
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
536
|
+
/>
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
const feeDetailView = anyspendQuote?.data?.fee ? (
|
|
540
|
+
<FeeDetailPanel
|
|
541
|
+
fee={anyspendQuote.data.fee}
|
|
542
|
+
transactionAmountUsd={
|
|
543
|
+
paymentType === "fiat"
|
|
544
|
+
? parseFloat(srcAmount)
|
|
545
|
+
: anyspendQuote.data.currencyIn?.amountUsd
|
|
546
|
+
? Number(anyspendQuote.data.currencyIn.amountUsd)
|
|
547
|
+
: undefined
|
|
548
|
+
}
|
|
549
|
+
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
550
|
+
/>
|
|
551
|
+
) : null;
|
|
552
|
+
|
|
553
|
+
return (
|
|
554
|
+
<StyleRoot>
|
|
555
|
+
<div
|
|
556
|
+
className={cn(
|
|
557
|
+
"anyspend-container font-inter bg-as-surface-primary mx-auto w-full max-w-[460px] p-6",
|
|
558
|
+
mode === "page" && "border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl",
|
|
559
|
+
)}
|
|
560
|
+
>
|
|
561
|
+
<TransitionPanel
|
|
562
|
+
activeIndex={
|
|
563
|
+
orderId
|
|
564
|
+
? oat
|
|
565
|
+
? PanelView.ORDER_DETAILS
|
|
566
|
+
: PanelView.LOADING
|
|
567
|
+
: activePanel === PanelView.ORDER_DETAILS
|
|
568
|
+
? PanelView.MAIN
|
|
569
|
+
: activePanel
|
|
570
|
+
}
|
|
571
|
+
className={cn("rounded-2xl", {
|
|
572
|
+
"mt-0": mode === "modal",
|
|
573
|
+
})}
|
|
574
|
+
variants={{
|
|
575
|
+
enter: { x: 300, opacity: 0 },
|
|
576
|
+
center: { x: 0, opacity: 1 },
|
|
577
|
+
exit: { x: -300, opacity: 0 },
|
|
578
|
+
}}
|
|
579
|
+
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
|
580
|
+
>
|
|
581
|
+
{[
|
|
582
|
+
<div key="main-view">{mainView}</div>,
|
|
583
|
+
<div key="crypto-payment-method-view">{cryptoPaymentMethodView}</div>,
|
|
584
|
+
<div key="fiat-payment-method-view">{fiatPaymentMethodView}</div>,
|
|
585
|
+
<div key="recipient-selection-view">{recipientSelectionView}</div>,
|
|
586
|
+
<div key="order-details-view">{orderDetailsView}</div>,
|
|
587
|
+
<div key="loading-view">{loadingView}</div>,
|
|
588
|
+
<div key="points-detail-view">{pointsDetailView}</div>,
|
|
589
|
+
<div key="fee-detail-view">{feeDetailView}</div>,
|
|
590
|
+
]}
|
|
591
|
+
</TransitionPanel>
|
|
592
|
+
</div>
|
|
593
|
+
</StyleRoot>
|
|
594
|
+
);
|
|
595
|
+
}
|