@b3dotfun/sdk 0.0.40-alpha.10 → 0.0.40-alpha.12
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/AnySpend.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/AnySpend.js +6 -2
- package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +5 -2
- package/dist/cjs/anyspend/react/components/common/ConnectWalletPayment.js +5 -3
- package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +73 -3
- package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +3 -3
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +8 -8
- package/dist/cjs/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +2 -2
- package/dist/cjs/anyspend/react/components/common/PointsDetailPanel.d.ts +6 -0
- package/dist/cjs/anyspend/react/components/common/PointsDetailPanel.js +14 -0
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +2 -1
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +1 -0
- package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +22 -20
- package/dist/esm/anyspend/react/components/AnySpend.d.ts +2 -1
- package/dist/esm/anyspend/react/components/AnySpend.js +6 -2
- package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +5 -2
- package/dist/esm/anyspend/react/components/common/ConnectWalletPayment.js +6 -4
- package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +73 -3
- package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -1
- package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +3 -3
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +8 -8
- package/dist/esm/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
- package/dist/esm/anyspend/react/components/common/PanelOnramp.js +2 -2
- package/dist/esm/anyspend/react/components/common/PointsDetailPanel.d.ts +6 -0
- package/dist/esm/anyspend/react/components/common/PointsDetailPanel.js +8 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +2 -1
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +1 -0
- package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +22 -20
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/react/components/AnySpend.d.ts +2 -1
- package/dist/types/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -1
- package/dist/types/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
- package/dist/types/anyspend/react/components/common/PointsDetailPanel.d.ts +6 -0
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +2 -1
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpend.tsx +14 -0
- package/src/anyspend/react/components/AnyspendDepositHype.tsx +13 -0
- package/src/anyspend/react/components/common/ConnectWalletPayment.tsx +7 -4
- package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +124 -4
- package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +12 -4
- package/src/anyspend/react/components/common/OrderDetails.tsx +8 -9
- package/src/anyspend/react/components/common/PanelOnramp.tsx +10 -3
- package/src/anyspend/react/components/common/PointsDetailPanel.tsx +55 -0
- package/src/anyspend/react/hooks/useAnyspendFlow.ts +1 -0
- package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +23 -21
|
@@ -14,6 +14,7 @@ import { CryptoReceiveSection } from "./common/CryptoReceiveSection";
|
|
|
14
14
|
import { ErrorSection } from "./common/ErrorSection";
|
|
15
15
|
import { FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaymentMethod";
|
|
16
16
|
import { OrderDetails } from "./common/OrderDetails";
|
|
17
|
+
import { PointsDetailPanel } from "./common/PointsDetailPanel";
|
|
17
18
|
import { RecipientSelection } from "./common/RecipientSelection";
|
|
18
19
|
|
|
19
20
|
import { ArrowDown } from "lucide-react";
|
|
@@ -224,6 +225,7 @@ function AnySpendDepositHypeInner({
|
|
|
224
225
|
fiatPaymentMethodIndex={PanelView.FIAT_PAYMENT_METHOD}
|
|
225
226
|
recipientSelectionPanelIndex={PanelView.RECIPIENT_SELECTION}
|
|
226
227
|
anyspendQuote={anyspendQuote}
|
|
228
|
+
onShowPointsDetail={() => setActivePanel(PanelView.POINTS_DETAIL)}
|
|
227
229
|
/>
|
|
228
230
|
</motion.div>
|
|
229
231
|
)}
|
|
@@ -264,6 +266,7 @@ function AnySpendDepositHypeInner({
|
|
|
264
266
|
setSrcAmount(value);
|
|
265
267
|
}}
|
|
266
268
|
anyspendQuote={anyspendQuote}
|
|
269
|
+
onShowPointsDetail={() => setActivePanel(PanelView.POINTS_DETAIL)}
|
|
267
270
|
/>
|
|
268
271
|
)}
|
|
269
272
|
</div>
|
|
@@ -449,6 +452,13 @@ function AnySpendDepositHypeInner({
|
|
|
449
452
|
/>
|
|
450
453
|
);
|
|
451
454
|
|
|
455
|
+
const pointsDetailView = (
|
|
456
|
+
<PointsDetailPanel
|
|
457
|
+
pointsAmount={anyspendQuote?.data?.pointsAmount || 0}
|
|
458
|
+
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
459
|
+
/>
|
|
460
|
+
);
|
|
461
|
+
|
|
452
462
|
// If showing token selection, render with panel transitions
|
|
453
463
|
return (
|
|
454
464
|
<StyleRoot>
|
|
@@ -498,6 +508,9 @@ function AnySpendDepositHypeInner({
|
|
|
498
508
|
<div key="loading-view" className={cn(mode === "page" && "p-6")}>
|
|
499
509
|
{loadingView}
|
|
500
510
|
</div>,
|
|
511
|
+
<div key="points-detail-view" className={cn(mode === "page" && "p-6")}>
|
|
512
|
+
{pointsDetailView}
|
|
513
|
+
</div>,
|
|
501
514
|
]}
|
|
502
515
|
</TransitionPanel>
|
|
503
516
|
</div>
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { RELAY_SOLANA_MAINNET_CHAIN_ID } from "@b3dotfun/sdk/anyspend";
|
|
4
4
|
import { components } from "@b3dotfun/sdk/anyspend/types/api";
|
|
5
|
-
import { ShinyButton, useProfile } from "@b3dotfun/sdk/global-account/react";
|
|
5
|
+
import { ShinyButton, useAccountWallet, useProfile } from "@b3dotfun/sdk/global-account/react";
|
|
6
6
|
import centerTruncate from "@b3dotfun/sdk/shared/utils/centerTruncate";
|
|
7
7
|
import { formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
|
|
8
8
|
import { motion } from "framer-motion";
|
|
9
9
|
import { ChevronRight, Loader2 } from "lucide-react";
|
|
10
|
-
import { useAccount } from "wagmi";
|
|
11
10
|
import { CryptoPaymentMethodType } from "./CryptoPaymentMethod";
|
|
12
11
|
import { OrderDetailsCollapsible } from "./OrderDetailsCollapsible";
|
|
13
12
|
import { PaymentMethodSwitch } from "./PaymentMethodSwitch";
|
|
@@ -41,7 +40,11 @@ export default function ConnectWalletPayment({
|
|
|
41
40
|
}: ConnectWalletPaymentProps) {
|
|
42
41
|
const profile = useProfile({ address: order.recipientAddress });
|
|
43
42
|
const recipientName = profile.data?.name?.replace(/\.b3\.fun/g, "");
|
|
44
|
-
const {
|
|
43
|
+
const { connectedEOAWallet, connectedSmartWallet } = useAccountWallet();
|
|
44
|
+
const connectedEvmAddress =
|
|
45
|
+
cryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET
|
|
46
|
+
? connectedSmartWallet?.getAccount()?.address
|
|
47
|
+
: connectedEOAWallet?.getAccount()?.address;
|
|
45
48
|
|
|
46
49
|
const srcToken = order.metadata.srcToken;
|
|
47
50
|
const dstToken = order.metadata.dstToken;
|
|
@@ -97,7 +100,7 @@ export default function ConnectWalletPayment({
|
|
|
97
100
|
Connected to:{" "}
|
|
98
101
|
{order.srcChain === RELAY_SOLANA_MAINNET_CHAIN_ID && phantomWalletAddress
|
|
99
102
|
? centerTruncate(phantomWalletAddress, 6)
|
|
100
|
-
: centerTruncate(
|
|
103
|
+
: centerTruncate(connectedEvmAddress || "")}
|
|
101
104
|
</span>
|
|
102
105
|
|
|
103
106
|
<PaymentMethodSwitch currentMethod={cryptoPaymentMethod} onMethodChange={onPaymentMethodChange} />
|
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
import { useAccountWallet } from "@b3dotfun/sdk/global-account/react";
|
|
4
4
|
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
5
5
|
import { shortenAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
|
|
6
|
+
import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
|
|
6
7
|
import { WalletCoinbase, WalletMetamask, WalletPhantom, WalletRainbow, WalletWalletConnect } from "@web3icons/react";
|
|
7
8
|
import { ChevronLeft, ChevronRightCircle, Wallet, X, ZapIcon } from "lucide-react";
|
|
8
9
|
import { useState } from "react";
|
|
9
10
|
import { createPortal } from "react-dom";
|
|
10
11
|
import { toast } from "sonner";
|
|
12
|
+
import { useSetActiveWallet, useWalletInfo } from "thirdweb/react";
|
|
13
|
+
import { WalletId, createWallet } from "thirdweb/wallets";
|
|
11
14
|
import { useAccount, useConnect, useDisconnect, useWalletClient } from "wagmi";
|
|
12
15
|
|
|
13
16
|
export enum CryptoPaymentMethodType {
|
|
@@ -38,13 +41,69 @@ export function CryptoPaymentMethod({
|
|
|
38
41
|
onBack,
|
|
39
42
|
onSelectPaymentMethod,
|
|
40
43
|
}: CryptoPaymentMethodProps) {
|
|
41
|
-
const {
|
|
42
|
-
|
|
44
|
+
const {
|
|
45
|
+
wallet: globalWallet,
|
|
46
|
+
connectedEOAWallet: connectedEOAWallet,
|
|
47
|
+
connectedSmartWallet: connectedSmartWallet,
|
|
48
|
+
} = useAccountWallet();
|
|
49
|
+
const { connector, address, isConnected: wagmiWalletIsConnected } = useAccount();
|
|
43
50
|
const { connect, connectors, isPending } = useConnect();
|
|
44
51
|
const { disconnect } = useDisconnect();
|
|
45
52
|
const { data: walletClient } = useWalletClient();
|
|
46
53
|
const [showWalletModal, setShowWalletModal] = useState(false);
|
|
47
54
|
|
|
55
|
+
const setActiveWallet = useSetActiveWallet();
|
|
56
|
+
const { data: eoaWalletInfo } = useWalletInfo(connectedEOAWallet?.id);
|
|
57
|
+
|
|
58
|
+
const isConnected = !!connectedEOAWallet;
|
|
59
|
+
const globalAddress = connectedSmartWallet?.getAccount()?.address;
|
|
60
|
+
|
|
61
|
+
// Helper function to check if two addresses are the same
|
|
62
|
+
const isSameAddress = (addr1?: string, addr2?: string): boolean => {
|
|
63
|
+
if (!addr1 || !addr2) return false;
|
|
64
|
+
return addr1.toLowerCase() === addr2.toLowerCase();
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Check if connectedEOAWallet and wagmi wallet represent the same wallet
|
|
68
|
+
const connectedEOAAddress = connectedEOAWallet?.getAccount()?.address;
|
|
69
|
+
const wagmiAddress = address;
|
|
70
|
+
const isWalletDuplicated = isSameAddress(connectedEOAAddress, wagmiAddress);
|
|
71
|
+
|
|
72
|
+
// Determine which wallet to show (prefer connectedEOAWallet if both exist and are the same)
|
|
73
|
+
const shouldShowConnectedEOA = !!connectedEOAWallet;
|
|
74
|
+
const shouldShowWagmiWallet = wagmiWalletIsConnected && (!isWalletDuplicated || !connectedEOAWallet);
|
|
75
|
+
|
|
76
|
+
// Map wagmi connector names to thirdweb wallet IDs
|
|
77
|
+
const getThirdwebWalletId = (connectorName: string): WalletId | null => {
|
|
78
|
+
const walletMap: Record<string, WalletId> = {
|
|
79
|
+
MetaMask: "io.metamask",
|
|
80
|
+
"Coinbase Wallet": "com.coinbase.wallet",
|
|
81
|
+
Rainbow: "me.rainbow",
|
|
82
|
+
WalletConnect: "walletConnect",
|
|
83
|
+
Phantom: "app.phantom",
|
|
84
|
+
};
|
|
85
|
+
return walletMap[connectorName] || null;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Create thirdweb wallet from wagmi connector
|
|
89
|
+
const createThirdwebWalletFromConnector = async (connectorName: string) => {
|
|
90
|
+
const walletId = getThirdwebWalletId(connectorName);
|
|
91
|
+
if (!walletId) {
|
|
92
|
+
console.warn(`No thirdweb wallet ID found for connector: ${connectorName}`);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const thirdwebWallet = createWallet(walletId);
|
|
98
|
+
// Connect the wallet to sync with the existing wagmi connection
|
|
99
|
+
await thirdwebWallet.connect({ client });
|
|
100
|
+
return thirdwebWallet;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error(`Failed to create thirdweb wallet for ${connectorName}:`, error);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
48
107
|
// Define available wallet connectors
|
|
49
108
|
const availableConnectors = connectors.filter(connector =>
|
|
50
109
|
["MetaMask", "WalletConnect", "Coinbase Wallet", "Rainbow", "Phantom"].includes(connector.name),
|
|
@@ -202,16 +261,77 @@ export function CryptoPaymentMethod({
|
|
|
202
261
|
</button>
|
|
203
262
|
|
|
204
263
|
{/* Installed Wallets Section */}
|
|
205
|
-
{(
|
|
264
|
+
{(shouldShowConnectedEOA || shouldShowWagmiWallet || globalAddress) && (
|
|
206
265
|
<div className="installed-wallets">
|
|
207
266
|
<h3 className="text-as-primary/80 mb-3 text-sm font-medium">Connected wallets</h3>
|
|
208
267
|
<div className="space-y-2">
|
|
209
268
|
{/* Current Connected Wallet */}
|
|
210
|
-
|
|
269
|
+
|
|
270
|
+
{shouldShowConnectedEOA && (
|
|
211
271
|
<button
|
|
212
272
|
onClick={() => {
|
|
213
273
|
setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
214
274
|
onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
275
|
+
setActiveWallet(connectedEOAWallet);
|
|
276
|
+
toast.success(`Selected ${eoaWalletInfo?.name || connector?.name || "wallet"}`);
|
|
277
|
+
}}
|
|
278
|
+
className={cn(
|
|
279
|
+
"crypto-payment-method-connect-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md",
|
|
280
|
+
selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
|
|
281
|
+
? "connected-wallet border-as-brand bg-as-brand/5"
|
|
282
|
+
: "border-as-border-secondary bg-as-surface-primary hover:border-as-secondary/80",
|
|
283
|
+
)}
|
|
284
|
+
>
|
|
285
|
+
<div className="flex items-center justify-between">
|
|
286
|
+
<div className="flex items-center gap-3">
|
|
287
|
+
<div className="wallet-icon flex h-10 w-10 items-center justify-center rounded-full bg-blue-100">
|
|
288
|
+
<Wallet className="h-5 w-5 text-blue-600" />
|
|
289
|
+
</div>
|
|
290
|
+
<div className="flex flex-col">
|
|
291
|
+
<span className="text-as-primary font-semibold">
|
|
292
|
+
{eoaWalletInfo?.name || connector?.name || "Connected Wallet"}
|
|
293
|
+
</span>
|
|
294
|
+
<span className="text-as-primary/60 text-sm">
|
|
295
|
+
{shortenAddress(connectedEOAWallet?.getAccount()?.address || "")}
|
|
296
|
+
</span>
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
<div className="flex items-center gap-2">
|
|
300
|
+
{selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET && (
|
|
301
|
+
<div className="h-2 w-2 rounded-full bg-green-500"></div>
|
|
302
|
+
)}
|
|
303
|
+
<button
|
|
304
|
+
onClick={e => {
|
|
305
|
+
e.stopPropagation();
|
|
306
|
+
disconnect();
|
|
307
|
+
toast.success("Wallet disconnected");
|
|
308
|
+
if (selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET) {
|
|
309
|
+
setSelectedPaymentMethod(CryptoPaymentMethodType.NONE);
|
|
310
|
+
}
|
|
311
|
+
}}
|
|
312
|
+
className="text-as-primary/60 hover:text-as-primary/80 rounded-lg p-1.5 transition-colors"
|
|
313
|
+
>
|
|
314
|
+
<X className="h-4 w-4" />
|
|
315
|
+
</button>
|
|
316
|
+
</div>
|
|
317
|
+
</div>
|
|
318
|
+
</button>
|
|
319
|
+
)}
|
|
320
|
+
|
|
321
|
+
{shouldShowWagmiWallet && (
|
|
322
|
+
<button
|
|
323
|
+
onClick={async () => {
|
|
324
|
+
setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
325
|
+
onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
326
|
+
|
|
327
|
+
// Create thirdweb wallet from wagmi connector
|
|
328
|
+
if (connector?.name) {
|
|
329
|
+
const thirdwebWallet = await createThirdwebWalletFromConnector(connector.name);
|
|
330
|
+
if (thirdwebWallet) {
|
|
331
|
+
setActiveWallet(thirdwebWallet);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
215
335
|
toast.success(`Selected ${connector?.name || "wallet"}`);
|
|
216
336
|
}}
|
|
217
337
|
className={cn(
|
|
@@ -28,6 +28,8 @@ interface CryptoReceiveSectionProps {
|
|
|
28
28
|
// custom dst token data
|
|
29
29
|
dstTokenSymbol?: string;
|
|
30
30
|
dstTokenLogoURI?: string;
|
|
31
|
+
// Points navigation
|
|
32
|
+
onShowPointsDetail?: () => void;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export function CryptoReceiveSection({
|
|
@@ -45,6 +47,7 @@ export function CryptoReceiveSection({
|
|
|
45
47
|
anyspendQuote,
|
|
46
48
|
dstTokenSymbol,
|
|
47
49
|
dstTokenLogoURI,
|
|
50
|
+
onShowPointsDetail,
|
|
48
51
|
}: CryptoReceiveSectionProps) {
|
|
49
52
|
const featureFlags = useFeatureFlags();
|
|
50
53
|
|
|
@@ -103,7 +106,7 @@ export function CryptoReceiveSection({
|
|
|
103
106
|
setToken={setSelectedDstToken || (() => {})}
|
|
104
107
|
/>
|
|
105
108
|
)}
|
|
106
|
-
<div className="text-as-primary/50 flex h-5 items-center justify-
|
|
109
|
+
<div className="text-as-primary/50 flex h-5 items-center justify-start gap-2 text-sm">
|
|
107
110
|
<div className="flex items-center gap-2">
|
|
108
111
|
{formatDisplayNumber(anyspendQuote?.data?.currencyOut?.amountUsd, {
|
|
109
112
|
style: "currency",
|
|
@@ -161,9 +164,14 @@ export function CryptoReceiveSection({
|
|
|
161
164
|
})()}
|
|
162
165
|
</div>
|
|
163
166
|
{featureFlags.showPoints && anyspendQuote?.data?.pointsAmount && anyspendQuote.data.pointsAmount > 0 && (
|
|
164
|
-
<
|
|
165
|
-
|
|
166
|
-
|
|
167
|
+
<button
|
|
168
|
+
key={`points-${anyspendQuote.data.pointsAmount}`}
|
|
169
|
+
className="bg-as-brand hover:scale-102 active:scale-98 active:scale-98 relative flex cursor-pointer items-center gap-1 rounded-lg px-2 py-1 transition-all"
|
|
170
|
+
onClick={() => onShowPointsDetail?.()}
|
|
171
|
+
>
|
|
172
|
+
<div className="pointer-events-none absolute inset-0 h-full w-full rounded-lg border border-white/10 border-t-white/20 bg-gradient-to-b from-white/10 to-white/0" />
|
|
173
|
+
<span className="text-xs text-white">+{anyspendQuote.data.pointsAmount.toLocaleString()} pts</span>
|
|
174
|
+
</button>
|
|
167
175
|
)}
|
|
168
176
|
</div>
|
|
169
177
|
</motion.div>
|
|
@@ -223,10 +223,9 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
223
223
|
// Read crypto payment method from URL parameters
|
|
224
224
|
const cryptoPaymentMethodFromUrl = searchParams.get("cryptoPaymentMethod") as CryptoPaymentMethodType | null;
|
|
225
225
|
const effectiveCryptoPaymentMethod =
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const orderStatusPaymentMethod = selectedCryptoPaymentMethod || effectiveCryptoPaymentMethod;
|
|
226
|
+
selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE
|
|
227
|
+
? selectedCryptoPaymentMethod
|
|
228
|
+
: cryptoPaymentMethod || cryptoPaymentMethodFromUrl || CryptoPaymentMethodType.NONE;
|
|
230
229
|
|
|
231
230
|
const setB3ModalOpen = useModalStore((state: any) => state.setB3ModalOpen);
|
|
232
231
|
|
|
@@ -575,7 +574,7 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
575
574
|
if (refundTxs.length > 0) {
|
|
576
575
|
return (
|
|
577
576
|
<>
|
|
578
|
-
<OrderStatus order={order} selectedCryptoPaymentMethod={
|
|
577
|
+
<OrderStatus order={order} selectedCryptoPaymentMethod={effectiveCryptoPaymentMethod} />
|
|
579
578
|
<OrderDetailsCollapsible
|
|
580
579
|
order={order}
|
|
581
580
|
dstToken={dstToken}
|
|
@@ -653,7 +652,7 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
653
652
|
if (executeTx) {
|
|
654
653
|
return (
|
|
655
654
|
<>
|
|
656
|
-
<OrderStatus order={order} selectedCryptoPaymentMethod={
|
|
655
|
+
<OrderStatus order={order} selectedCryptoPaymentMethod={effectiveCryptoPaymentMethod} />
|
|
657
656
|
<OrderDetailsCollapsible
|
|
658
657
|
order={order}
|
|
659
658
|
dstToken={dstToken}
|
|
@@ -780,7 +779,7 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
780
779
|
if (relayTxs.length > 0 && relayTxs.every(tx => tx.status === "success")) {
|
|
781
780
|
return (
|
|
782
781
|
<>
|
|
783
|
-
<OrderStatus order={order} selectedCryptoPaymentMethod={
|
|
782
|
+
<OrderStatus order={order} selectedCryptoPaymentMethod={effectiveCryptoPaymentMethod} />
|
|
784
783
|
<OrderDetailsCollapsible
|
|
785
784
|
order={order}
|
|
786
785
|
dstToken={dstToken}
|
|
@@ -909,7 +908,7 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
909
908
|
if (depositTxs?.length || waitingForDeposit) {
|
|
910
909
|
return (
|
|
911
910
|
<>
|
|
912
|
-
<OrderStatus order={order} selectedCryptoPaymentMethod={
|
|
911
|
+
<OrderStatus order={order} selectedCryptoPaymentMethod={effectiveCryptoPaymentMethod} />
|
|
913
912
|
<OrderDetailsCollapsible
|
|
914
913
|
order={order}
|
|
915
914
|
dstToken={dstToken}
|
|
@@ -1008,7 +1007,7 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
1008
1007
|
|
|
1009
1008
|
return (
|
|
1010
1009
|
<>
|
|
1011
|
-
<OrderStatus order={order} selectedCryptoPaymentMethod={
|
|
1010
|
+
<OrderStatus order={order} selectedCryptoPaymentMethod={effectiveCryptoPaymentMethod} />
|
|
1012
1011
|
{statusDisplay === "processing" && (
|
|
1013
1012
|
<>
|
|
1014
1013
|
{order.onrampMetadata ? (
|
|
@@ -28,6 +28,7 @@ export function PanelOnramp({
|
|
|
28
28
|
dstTokenSymbol,
|
|
29
29
|
hideDstToken = false,
|
|
30
30
|
anyspendQuote,
|
|
31
|
+
onShowPointsDetail,
|
|
31
32
|
}: {
|
|
32
33
|
srcAmountOnRamp: string;
|
|
33
34
|
setSrcAmountOnRamp: (amount: string) => void;
|
|
@@ -44,6 +45,7 @@ export function PanelOnramp({
|
|
|
44
45
|
dstTokenSymbol?: string;
|
|
45
46
|
hideDstToken?: boolean;
|
|
46
47
|
anyspendQuote?: GetQuoteResponse;
|
|
48
|
+
onShowPointsDetail?: () => void;
|
|
47
49
|
}) {
|
|
48
50
|
const featureFlags = useFeatureFlags();
|
|
49
51
|
// Get geo-based onramp options to access fee information
|
|
@@ -258,9 +260,14 @@ export function PanelOnramp({
|
|
|
258
260
|
})()}
|
|
259
261
|
</span>
|
|
260
262
|
{featureFlags.showPoints && anyspendQuote?.data?.pointsAmount && anyspendQuote.data.pointsAmount > 0 && (
|
|
261
|
-
<
|
|
262
|
-
|
|
263
|
-
|
|
263
|
+
<button
|
|
264
|
+
key={`points-${anyspendQuote.data.pointsAmount}`}
|
|
265
|
+
className="bg-as-brand hover:scale-102 active:scale-98 relative flex cursor-pointer items-center gap-1 rounded-lg px-2 py-1 transition-all"
|
|
266
|
+
onClick={() => onShowPointsDetail?.()}
|
|
267
|
+
>
|
|
268
|
+
<div className="pointer-events-none absolute inset-0 h-full w-full rounded-lg border border-white/10 border-t-white/20 bg-gradient-to-b from-white/10 to-white/0" />
|
|
269
|
+
<span className="text-xs text-white">+{anyspendQuote.data.pointsAmount.toLocaleString()} pts</span>
|
|
270
|
+
</button>
|
|
264
271
|
)}
|
|
265
272
|
</div>
|
|
266
273
|
<span className="text-as-primary font-semibold">
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Button, ShinyButton } from "@b3dotfun/sdk/global-account/react";
|
|
2
|
+
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
3
|
+
import { ArrowDown } from "lucide-react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
|
|
6
|
+
interface PointsDetailPanelProps {
|
|
7
|
+
pointsAmount?: number;
|
|
8
|
+
onBack: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function PointsDetailPanel({ pointsAmount = 0, onBack }: PointsDetailPanelProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div className="mx-auto flex w-[460px] max-w-full flex-col items-center gap-4">
|
|
14
|
+
<div className="flex w-full items-center justify-between">
|
|
15
|
+
<Button
|
|
16
|
+
variant="ghost"
|
|
17
|
+
onClick={onBack}
|
|
18
|
+
className="text-as-primary/70 hover:text-as-primary flex items-center gap-2"
|
|
19
|
+
>
|
|
20
|
+
<ArrowDown className="h-4 w-4 rotate-90" />
|
|
21
|
+
Back
|
|
22
|
+
</Button>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div className="flex flex-col items-center gap-4 text-center">
|
|
26
|
+
<h3 className="text-as-primary text-xl font-bold">Earn Points with Every Swap</h3>
|
|
27
|
+
<p className="text-as-primary/70 text-balance text-sm leading-relaxed">
|
|
28
|
+
You'll earn <span className="text-as-brand font-semibold">+{pointsAmount.toLocaleString()} points</span>{" "}
|
|
29
|
+
towards the{" "}
|
|
30
|
+
<Link href="https://anyspend.com/points" target="_blank" className="text-as-brand underline">
|
|
31
|
+
next AnySpend airdrop
|
|
32
|
+
</Link>{" "}
|
|
33
|
+
when you complete this transaction.
|
|
34
|
+
</p>
|
|
35
|
+
<div className="bg-as-surface-primary border-as-border-secondary mt-2 w-full rounded-lg border p-4 text-left">
|
|
36
|
+
<h4 className="text-as-primary mb-2 font-semibold">How it works:</h4>
|
|
37
|
+
<ul className="text-as-primary/70 space-y-1 text-sm">
|
|
38
|
+
<li>• Points are earned based on transaction volume</li>
|
|
39
|
+
<li>• Higher volume = more points</li>
|
|
40
|
+
<li>• Points contribute to future airdrops</li>
|
|
41
|
+
<li>• Keep swapping to maximize your rewards</li>
|
|
42
|
+
</ul>
|
|
43
|
+
</div>
|
|
44
|
+
<ShinyButton
|
|
45
|
+
accentColor={"hsl(var(--as-brand))"}
|
|
46
|
+
onClick={onBack}
|
|
47
|
+
className={cn("as-main-button !bg-as-brand relative w-full")}
|
|
48
|
+
textClassName={cn("text-white")}
|
|
49
|
+
>
|
|
50
|
+
Back to Swap
|
|
51
|
+
</ShinyButton>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -6,10 +6,11 @@ import invariant from "invariant";
|
|
|
6
6
|
import { useCallback, useState } from "react";
|
|
7
7
|
import { toast } from "sonner";
|
|
8
8
|
import { prepareTransaction, sendTransaction as twSendTransaction } from "thirdweb";
|
|
9
|
+
import { useActiveWallet } from "thirdweb/react";
|
|
10
|
+
import { isAddress } from "viem";
|
|
9
11
|
import { useSwitchChain, useWalletClient } from "wagmi";
|
|
10
12
|
import { useB3 } from "../components";
|
|
11
13
|
import { useAccountWallet } from "./useAccountWallet";
|
|
12
|
-
import { isAddress } from "viem";
|
|
13
14
|
|
|
14
15
|
export interface UnifiedTransactionParams {
|
|
15
16
|
to: string;
|
|
@@ -29,46 +30,53 @@ export function useUnifiedChainSwitchAndExecute() {
|
|
|
29
30
|
const { data: walletClient } = useWalletClient();
|
|
30
31
|
const { switchChainAsync } = useSwitchChain();
|
|
31
32
|
const [isSwitchingOrExecuting, setIsSwitchingOrExecuting] = useState(false);
|
|
33
|
+
const activeWallet = useActiveWallet();
|
|
32
34
|
|
|
33
|
-
const { isActiveSmartWallet, isActiveEOAWallet } = useAccountWallet();
|
|
35
|
+
const { isActiveSmartWallet, isActiveEOAWallet, connectedEOAWallet } = useAccountWallet();
|
|
34
36
|
const { account: aaAccount } = useB3();
|
|
35
37
|
|
|
36
38
|
// Handle EOA wallet chain switch and execute transaction
|
|
37
39
|
const handleEOASwitchChainAndSendTransaction = useCallback(
|
|
38
40
|
async (targetChainId: number, params: UnifiedTransactionParams): Promise<string | undefined> => {
|
|
39
|
-
if (!
|
|
41
|
+
if (!connectedEOAWallet) {
|
|
40
42
|
toast.error("Please connect your wallet");
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
+
// Get target chain configuration once
|
|
47
|
+
const targetChain = supportedChains.find(chain => chain.id === targetChainId);
|
|
48
|
+
if (!targetChain) {
|
|
49
|
+
toast.error(`Chain ${targetChainId} is not supported`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const currentChainId = activeWallet?.getChain()?.id;
|
|
54
|
+
const onCorrectChain = currentChainId === targetChainId;
|
|
46
55
|
|
|
47
56
|
// Helper function to execute the transaction
|
|
48
57
|
const executeTransaction = async (): Promise<string> => {
|
|
49
|
-
const signer =
|
|
58
|
+
const signer = activeWallet?.getAccount();
|
|
50
59
|
if (!signer) {
|
|
51
60
|
throw new Error("No account connected");
|
|
52
61
|
}
|
|
53
62
|
|
|
54
|
-
//
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
57
|
-
|
|
63
|
+
// Coinbase Smart Wallet specific chain switching (different behavior from other wallets)
|
|
64
|
+
const walletChain = connectedEOAWallet.getChain();
|
|
65
|
+
if (walletChain?.id !== targetChainId) {
|
|
66
|
+
activeWallet?.switchChain(getThirdwebChain(targetChainId));
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
invariant(isAddress(params.to), "params.to is not a valid address");
|
|
61
70
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
chain: targetChain,
|
|
71
|
+
const result = await signer.sendTransaction({
|
|
72
|
+
chainId: targetChainId,
|
|
65
73
|
to: params.to,
|
|
66
74
|
data: params.data as `0x${string}`,
|
|
67
75
|
value: params.value,
|
|
68
76
|
});
|
|
69
77
|
|
|
70
|
-
toast.success(`Transaction sent: ${
|
|
71
|
-
return
|
|
78
|
+
toast.success(`Transaction sent: ${result.transactionHash.slice(0, 10)}...`);
|
|
79
|
+
return result.transactionHash;
|
|
72
80
|
};
|
|
73
81
|
|
|
74
82
|
try {
|
|
@@ -80,12 +88,6 @@ export function useUnifiedChainSwitchAndExecute() {
|
|
|
80
88
|
|
|
81
89
|
const switchingToastId = toast.info(`Switching to ${getChainName(targetChainId)}…`);
|
|
82
90
|
|
|
83
|
-
const targetChain = supportedChains.find(chain => chain.id === targetChainId);
|
|
84
|
-
if (!targetChain) {
|
|
85
|
-
toast.error(`Chain ${targetChainId} is not supported`);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
91
|
const blockExplorerUrl = targetChain.blockExplorers?.default.url;
|
|
90
92
|
invariant(blockExplorerUrl, "Block explorer URL is required");
|
|
91
93
|
const nativeCurrency = getNativeToken(targetChainId);
|