@b3dotfun/sdk 0.0.29-alpha.3 → 0.0.29-alpha.5
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/AnyspendDepositHype.js +8 -2
- package/dist/cjs/anyspend/react/components/common/ConnectWalletPayment.js +9 -1
- package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +130 -41
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +6 -3
- package/dist/cjs/anyspend/react/components/common/PaySection.js +6 -4
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +2 -1
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +34 -3
- package/dist/cjs/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
- package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +1 -0
- package/dist/cjs/shared/constants/chains/b3Chain.d.ts +2 -2
- package/dist/cjs/shared/constants/chains/supported.d.ts +4 -4
- package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +8 -2
- package/dist/esm/anyspend/react/components/common/ConnectWalletPayment.js +6 -1
- package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +133 -44
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +7 -4
- package/dist/esm/anyspend/react/components/common/PaySection.js +7 -5
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +2 -1
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +35 -4
- package/dist/esm/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
- package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +1 -0
- package/dist/esm/shared/constants/chains/b3Chain.d.ts +2 -2
- package/dist/esm/shared/constants/chains/supported.d.ts +4 -4
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +2 -1
- package/dist/types/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/types/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
- package/dist/types/shared/constants/chains/b3Chain.d.ts +2 -2
- package/dist/types/shared/constants/chains/supported.d.ts +4 -4
- package/package.json +1 -1
- package/src/anyspend/react/components/AnyspendDepositHype.tsx +11 -1
- package/src/anyspend/react/components/common/ConnectWalletPayment.tsx +9 -0
- package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +289 -103
- package/src/anyspend/react/components/common/OrderDetails.tsx +7 -3
- package/src/anyspend/react/components/common/PaySection.tsx +9 -7
- package/src/anyspend/react/hooks/useAnyspendFlow.ts +41 -3
- package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +1 -0
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useAccountWallet } from "@b3dotfun/sdk/global-account/react";
|
|
4
|
-
import { thirdwebB3Mainnet } from "@b3dotfun/sdk/shared/constants/chains/b3Chain";
|
|
5
4
|
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
6
5
|
import { shortenAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
|
|
7
|
-
import {
|
|
8
|
-
import { ChevronLeft, ChevronRightCircle, Wallet, X } from "lucide-react";
|
|
6
|
+
import { ChevronLeft, ChevronRightCircle, Wallet, X, ZapIcon } from "lucide-react";
|
|
9
7
|
import { useState } from "react";
|
|
10
8
|
import { createPortal } from "react-dom";
|
|
11
9
|
import { toast } from "sonner";
|
|
12
|
-
import {
|
|
13
|
-
import { createWallet } from "thirdweb/wallets";
|
|
14
|
-
import { useDisconnect } from "wagmi";
|
|
10
|
+
import { useAccount, useConnect, useDisconnect, useWalletClient } from "wagmi";
|
|
15
11
|
|
|
16
12
|
export enum CryptoPaymentMethodType {
|
|
17
13
|
NONE = "none",
|
|
@@ -41,20 +37,107 @@ export function CryptoPaymentMethod({
|
|
|
41
37
|
onSelectPaymentMethod,
|
|
42
38
|
}: CryptoPaymentMethodProps) {
|
|
43
39
|
const { wallet: globalWallet } = useAccountWallet();
|
|
44
|
-
const
|
|
40
|
+
const { address, isConnected, connector } = useAccount();
|
|
41
|
+
const { connect, connectors, isPending } = useConnect();
|
|
45
42
|
const { disconnect } = useDisconnect();
|
|
46
|
-
const {
|
|
43
|
+
const { data: walletClient } = useWalletClient();
|
|
47
44
|
const [showWalletModal, setShowWalletModal] = useState(false);
|
|
45
|
+
const [selectedWalletConnector, setSelectedWalletConnector] = useState<any>(null);
|
|
46
|
+
const [modalStep, setModalStep] = useState<"wallet-selection" | "account-selection">("wallet-selection");
|
|
48
47
|
|
|
49
|
-
// Define available
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
// Define available wallet connectors
|
|
49
|
+
const availableConnectors = connectors.filter(connector =>
|
|
50
|
+
["MetaMask", "WalletConnect", "Coinbase Wallet", "Rainbow"].includes(connector.name),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Define wallet options with icons and info
|
|
54
|
+
const walletOptions = [
|
|
55
|
+
{
|
|
56
|
+
id: "metamask",
|
|
57
|
+
name: "MetaMask",
|
|
58
|
+
icon: "🦊",
|
|
59
|
+
description: "Connect using MetaMask browser extension",
|
|
60
|
+
connector: availableConnectors.find(c => c.name === "MetaMask"),
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: "coinbase",
|
|
64
|
+
name: "Coinbase Wallet",
|
|
65
|
+
icon: "🔵",
|
|
66
|
+
description: "Connect using Coinbase Wallet",
|
|
67
|
+
connector: availableConnectors.find(c => c.name === "Coinbase Wallet"),
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "rainbow",
|
|
71
|
+
name: "Rainbow",
|
|
72
|
+
icon: "🌈",
|
|
73
|
+
description: "Connect using Rainbow wallet",
|
|
74
|
+
connector: availableConnectors.find(c => c.name === "Rainbow"),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "walletconnect",
|
|
78
|
+
name: "WalletConnect",
|
|
79
|
+
icon: "🔗",
|
|
80
|
+
description: "Connect using WalletConnect protocol",
|
|
81
|
+
connector: availableConnectors.find(c => c.name === "WalletConnect"),
|
|
82
|
+
},
|
|
83
|
+
].filter(wallet => wallet.connector); // Only show wallets that have available connectors
|
|
84
|
+
|
|
85
|
+
// Reset modal state when closing
|
|
86
|
+
const handleCloseModal = () => {
|
|
87
|
+
setShowWalletModal(false);
|
|
88
|
+
setModalStep("wallet-selection");
|
|
89
|
+
setSelectedWalletConnector(null);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Function to request wallet permissions for specific wallet
|
|
93
|
+
const requestWalletPermissions = async (walletConnector?: any) => {
|
|
94
|
+
try {
|
|
95
|
+
// If a specific wallet connector is provided and it's different from current
|
|
96
|
+
if (walletConnector && connector?.name !== walletConnector.name) {
|
|
97
|
+
// Disconnect current and connect to the selected wallet
|
|
98
|
+
// if (isConnected) {
|
|
99
|
+
// disconnect();
|
|
100
|
+
// // Small delay to ensure disconnection
|
|
101
|
+
// await new Promise(resolve => setTimeout(resolve, 100));
|
|
102
|
+
// }
|
|
103
|
+
await connect({ connector: walletConnector });
|
|
104
|
+
setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
105
|
+
onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
106
|
+
toast.success(`Connected to ${walletConnector.name}`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// If same wallet or no specific wallet, request permissions for account switching
|
|
111
|
+
if (walletClient && "request" in walletClient) {
|
|
112
|
+
await walletClient.request({
|
|
113
|
+
method: "wallet_requestPermissions",
|
|
114
|
+
params: [{ eth_accounts: {} }],
|
|
115
|
+
});
|
|
116
|
+
toast.success("Account selection completed");
|
|
117
|
+
setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
118
|
+
onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
119
|
+
} else {
|
|
120
|
+
// Fallback: show modal for manual wallet selection
|
|
121
|
+
setShowWalletModal(true);
|
|
122
|
+
}
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error("Failed to request wallet permissions:", error);
|
|
125
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
126
|
+
const errorMessage = (error as any).message.toLowerCase();
|
|
127
|
+
if (
|
|
128
|
+
errorMessage.includes("rejected") ||
|
|
129
|
+
errorMessage.includes("denied") ||
|
|
130
|
+
errorMessage.includes("cancelled")
|
|
131
|
+
) {
|
|
132
|
+
toast.error("Account selection cancelled");
|
|
133
|
+
} else {
|
|
134
|
+
toast.error("Failed to open account selection");
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
toast.error("Failed to open account selection");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
58
141
|
|
|
59
142
|
return (
|
|
60
143
|
<div className="crypto-payment-method mx-auto h-fit w-[460px] max-w-full">
|
|
@@ -68,78 +151,32 @@ export function CryptoPaymentMethod({
|
|
|
68
151
|
</button>
|
|
69
152
|
<div className="flex items-center justify-around gap-4">
|
|
70
153
|
<div className="flex-1 text-center">
|
|
71
|
-
<h2 className="text-as-primary text-lg font-semibold">
|
|
154
|
+
<h2 className="text-as-primary text-lg font-semibold">Select a payment method</h2>
|
|
72
155
|
</div>
|
|
73
156
|
</div>
|
|
74
157
|
|
|
75
158
|
{/* Payment Methods */}
|
|
76
|
-
<div className="crypto-payment-methods flex flex-col gap-
|
|
77
|
-
{/* Connect Wallet
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
<div className="flex flex-col items-start text-left">
|
|
89
|
-
<h4 className="text-as-primary font-semibold">Connect wallet</h4>
|
|
90
|
-
<p className="text-as-primary/60 text-sm">Choose from multiple wallet options</p>
|
|
91
|
-
</div>
|
|
159
|
+
<div className="crypto-payment-methods flex flex-col gap-6">
|
|
160
|
+
{/* Connect Wallet Section */}
|
|
161
|
+
<button
|
|
162
|
+
onClick={() => {
|
|
163
|
+
// Always show wallet selection modal first
|
|
164
|
+
setShowWalletModal(true);
|
|
165
|
+
}}
|
|
166
|
+
className="crypto-payment-method-connect-wallet bg-as-surface-primary border-as-border-secondary hover:border-as-secondary/80 group flex w-full items-center justify-between gap-4 rounded-xl border px-4 py-3.5 transition-all duration-200 hover:shadow-md"
|
|
167
|
+
>
|
|
168
|
+
<div className="flex items-center gap-3">
|
|
169
|
+
<div className="wallet-icon flex h-8 w-8 items-center justify-center rounded-full bg-blue-100">
|
|
170
|
+
<Wallet className="h-4 w-4 text-blue-600" />
|
|
92
171
|
</div>
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
) : (
|
|
96
|
-
// Connected - show wallet info
|
|
97
|
-
<div className="crypto-payment-method-connect-wallet wallet-connected bg-as-surface-primary border-as-border-secondary rounded-xl border">
|
|
98
|
-
<div className="flex items-center justify-between p-4">
|
|
99
|
-
<div className="flex items-center gap-3">
|
|
100
|
-
{globalWallet?.meta?.icon ? (
|
|
101
|
-
<img src={globalWallet.meta.icon} alt="Connected Wallet" className="h-8 w-8 rounded-full" />
|
|
102
|
-
) : (
|
|
103
|
-
<div className="wallet-icon flex h-8 w-8 items-center justify-center rounded-full bg-green-100">
|
|
104
|
-
<Wallet className="h-4 w-4 text-green-600" />
|
|
105
|
-
</div>
|
|
106
|
-
)}
|
|
107
|
-
<div className="flex flex-col">
|
|
108
|
-
<span className="text-as-primary font-semibold">Connected Wallet</span>
|
|
109
|
-
<span className="text-as-primary/60 text-sm">
|
|
110
|
-
{shortenAddress(activeWallet.getAccount()?.address || "")}
|
|
111
|
-
</span>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
<div className="flex items-center gap-2">
|
|
115
|
-
<button
|
|
116
|
-
onClick={() => {
|
|
117
|
-
setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
118
|
-
onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
119
|
-
}}
|
|
120
|
-
className="bg-as-brand hover:bg-as-brand/90 rounded-lg px-3 py-1.5 text-sm font-medium text-white transition-colors"
|
|
121
|
-
>
|
|
122
|
-
Use Wallet
|
|
123
|
-
</button>
|
|
124
|
-
<button
|
|
125
|
-
onClick={async () => {
|
|
126
|
-
disconnect();
|
|
127
|
-
disconnectThirdweb(activeWallet);
|
|
128
|
-
toast.success("Wallet disconnected");
|
|
129
|
-
if (selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET) {
|
|
130
|
-
setSelectedPaymentMethod(CryptoPaymentMethodType.NONE);
|
|
131
|
-
}
|
|
132
|
-
}}
|
|
133
|
-
className="text-as-primary/60 hover:text-as-primary/80 rounded-lg p-1.5 transition-colors"
|
|
134
|
-
>
|
|
135
|
-
<X className="h-4 w-4" />
|
|
136
|
-
</button>
|
|
137
|
-
</div>
|
|
172
|
+
<div className="flex flex-col items-start text-left">
|
|
173
|
+
<h4 className="text-as-primary font-semibold">Connect wallet</h4>
|
|
138
174
|
</div>
|
|
139
175
|
</div>
|
|
140
|
-
|
|
176
|
+
<ChevronRightCircle className="text-as-primary/40 group-hover:text-as-primary/60 h-5 w-5 transition-colors" />
|
|
177
|
+
</button>
|
|
141
178
|
|
|
142
|
-
{/* Transfer Crypto
|
|
179
|
+
{/* Transfer Crypto Section */}
|
|
143
180
|
<button
|
|
144
181
|
onClick={() => {
|
|
145
182
|
setSelectedPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
|
|
@@ -148,11 +185,73 @@ export function CryptoPaymentMethod({
|
|
|
148
185
|
disabled={isCreatingOrder}
|
|
149
186
|
className="crypto-payment-method-transfer bg-as-surface-primary border-as-border-secondary hover:border-as-secondary/80 group flex w-full items-center justify-between gap-4 rounded-xl border px-4 py-3.5 transition-all duration-200 hover:shadow-md"
|
|
150
187
|
>
|
|
151
|
-
<div className="flex
|
|
152
|
-
<
|
|
188
|
+
<div className="flex items-center gap-3">
|
|
189
|
+
<div className="wallet-icon flex h-8 w-8 items-center justify-center rounded-full bg-orange-100">
|
|
190
|
+
<ZapIcon className="h-4 w-4" />
|
|
191
|
+
</div>
|
|
192
|
+
<div className="flex flex-col items-start text-left">
|
|
193
|
+
<h4 className="text-as-primary font-semibold">Transfer crypto</h4>
|
|
194
|
+
</div>
|
|
153
195
|
</div>
|
|
154
196
|
<ChevronRightCircle className="text-as-primary/40 group-hover:text-as-primary/60 h-5 w-5 transition-colors" />
|
|
155
197
|
</button>
|
|
198
|
+
|
|
199
|
+
{/* Installed Wallets Section */}
|
|
200
|
+
{isConnected && (
|
|
201
|
+
<div className="installed-wallets">
|
|
202
|
+
<h3 className="text-as-primary/80 mb-3 text-sm font-medium">Connected wallets</h3>
|
|
203
|
+
<div className="space-y-2">
|
|
204
|
+
{/* Current Connected Wallet */}
|
|
205
|
+
<button
|
|
206
|
+
onClick={() => {
|
|
207
|
+
setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
208
|
+
onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
209
|
+
toast.success(`Selected ${connector?.name || "wallet"}`);
|
|
210
|
+
}}
|
|
211
|
+
className={cn(
|
|
212
|
+
"crypto-payment-method-connect-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md",
|
|
213
|
+
selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
|
|
214
|
+
? "connected-wallet border-as-brand bg-as-brand/5"
|
|
215
|
+
: "border-as-border-secondary bg-as-surface-primary hover:border-as-secondary/80",
|
|
216
|
+
)}
|
|
217
|
+
>
|
|
218
|
+
<div className="flex items-center justify-between">
|
|
219
|
+
<div className="flex items-center gap-3">
|
|
220
|
+
{globalWallet?.meta?.icon ? (
|
|
221
|
+
<img src={globalWallet.meta.icon} alt="Wallet" className="h-10 w-10 rounded-full" />
|
|
222
|
+
) : (
|
|
223
|
+
<div className="wallet-icon flex h-10 w-10 items-center justify-center rounded-full bg-blue-100">
|
|
224
|
+
<Wallet className="h-5 w-5 text-blue-600" />
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
<div className="flex flex-col">
|
|
228
|
+
<span className="text-as-primary font-semibold">{connector?.name || "Connected Wallet"}</span>
|
|
229
|
+
<span className="text-as-primary/60 text-sm">{shortenAddress(address || "")}</span>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
<div className="flex items-center gap-2">
|
|
233
|
+
{selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET && (
|
|
234
|
+
<div className="h-2 w-2 rounded-full bg-green-500"></div>
|
|
235
|
+
)}
|
|
236
|
+
<button
|
|
237
|
+
onClick={e => {
|
|
238
|
+
e.stopPropagation();
|
|
239
|
+
disconnect();
|
|
240
|
+
toast.success("Wallet disconnected");
|
|
241
|
+
if (selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET) {
|
|
242
|
+
setSelectedPaymentMethod(CryptoPaymentMethodType.NONE);
|
|
243
|
+
}
|
|
244
|
+
}}
|
|
245
|
+
className="text-as-primary/60 hover:text-as-primary/80 rounded-lg p-1.5 transition-colors"
|
|
246
|
+
>
|
|
247
|
+
<X className="h-4 w-4" />
|
|
248
|
+
</button>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
</button>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
)}
|
|
156
255
|
</div>
|
|
157
256
|
</div>
|
|
158
257
|
|
|
@@ -162,32 +261,119 @@ export function CryptoPaymentMethod({
|
|
|
162
261
|
<div className="pointer-events-auto fixed inset-0 z-[9999] flex items-center justify-center bg-black/50">
|
|
163
262
|
<div className="max-h-[80vh] w-[400px] max-w-[90vw] overflow-auto rounded-xl bg-white p-6 dark:bg-gray-900">
|
|
164
263
|
<div className="mb-4 flex items-center justify-between">
|
|
165
|
-
<
|
|
264
|
+
<div className="flex items-center gap-2">
|
|
265
|
+
{modalStep === "account-selection" && (
|
|
266
|
+
<button
|
|
267
|
+
onClick={() => setModalStep("wallet-selection")}
|
|
268
|
+
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
|
269
|
+
>
|
|
270
|
+
<ChevronLeft className="h-5 w-5" />
|
|
271
|
+
</button>
|
|
272
|
+
)}
|
|
273
|
+
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
|
274
|
+
{modalStep === "wallet-selection"
|
|
275
|
+
? "Select a payment method"
|
|
276
|
+
: `Connect ${selectedWalletConnector?.name}`}
|
|
277
|
+
</h3>
|
|
278
|
+
</div>
|
|
166
279
|
<button
|
|
167
|
-
onClick={
|
|
280
|
+
onClick={handleCloseModal}
|
|
168
281
|
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
|
169
282
|
>
|
|
170
283
|
<X className="h-5 w-5" />
|
|
171
284
|
</button>
|
|
172
285
|
</div>
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
286
|
+
|
|
287
|
+
<div className="space-y-4">
|
|
288
|
+
{modalStep === "wallet-selection" ? (
|
|
289
|
+
<>
|
|
290
|
+
{/* Custom wallet options */}
|
|
291
|
+
<div className="space-y-3">
|
|
292
|
+
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
293
|
+
{isConnected ? "Switch wallet or account" : "Choose wallet to connect"}
|
|
294
|
+
</h4>
|
|
295
|
+
{walletOptions.map(walletOption => {
|
|
296
|
+
const isCurrentWallet = isConnected && connector?.name === walletOption.connector?.name;
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<button
|
|
300
|
+
key={walletOption.id}
|
|
301
|
+
onClick={async () => {
|
|
302
|
+
setSelectedWalletConnector(walletOption.connector);
|
|
303
|
+
setModalStep("account-selection");
|
|
304
|
+
}}
|
|
305
|
+
disabled={isPending}
|
|
306
|
+
className={`w-full rounded-xl border p-4 text-left transition-all hover:shadow-md disabled:opacity-50 ${
|
|
307
|
+
isCurrentWallet
|
|
308
|
+
? "border-blue-500 bg-blue-50 dark:bg-blue-900/20"
|
|
309
|
+
: "border-gray-200 bg-white hover:border-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:hover:border-gray-500"
|
|
310
|
+
}`}
|
|
311
|
+
>
|
|
312
|
+
<div className="flex items-center justify-between">
|
|
313
|
+
<div className="flex items-center gap-3">
|
|
314
|
+
<div
|
|
315
|
+
className={`flex h-12 w-12 items-center justify-center rounded-xl text-xl ${
|
|
316
|
+
isCurrentWallet ? "bg-blue-100 dark:bg-blue-800" : "bg-gray-100 dark:bg-gray-700"
|
|
317
|
+
}`}
|
|
318
|
+
>
|
|
319
|
+
{walletOption.icon}
|
|
320
|
+
</div>
|
|
321
|
+
<div>
|
|
322
|
+
<div className="flex items-center gap-2">
|
|
323
|
+
<div className="text-sm font-semibold text-gray-900 dark:text-white">
|
|
324
|
+
{walletOption.name}
|
|
325
|
+
</div>
|
|
326
|
+
{isCurrentWallet && (
|
|
327
|
+
<span className="rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-700 dark:bg-blue-800 dark:text-blue-200">
|
|
328
|
+
Connected
|
|
329
|
+
</span>
|
|
330
|
+
)}
|
|
331
|
+
</div>
|
|
332
|
+
<div className="text-xs text-gray-500 dark:text-gray-400">
|
|
333
|
+
{isCurrentWallet ? "Switch account or reconnect" : walletOption.description}
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
<ChevronRightCircle className="h-5 w-5 text-gray-400" />
|
|
338
|
+
</div>
|
|
339
|
+
</button>
|
|
340
|
+
);
|
|
341
|
+
})}
|
|
342
|
+
</div>
|
|
343
|
+
</>
|
|
344
|
+
) : (
|
|
345
|
+
/* Account Selection Step */
|
|
346
|
+
<div className="space-y-4">
|
|
347
|
+
<p className="text-sm text-gray-600 dark:text-gray-400">
|
|
348
|
+
Connect to {selectedWalletConnector?.name} to view available accounts
|
|
349
|
+
</p>
|
|
350
|
+
<button
|
|
351
|
+
onClick={async () => {
|
|
352
|
+
handleCloseModal();
|
|
353
|
+
await requestWalletPermissions(selectedWalletConnector);
|
|
354
|
+
}}
|
|
355
|
+
disabled={isPending}
|
|
356
|
+
className="w-full rounded-lg border border-gray-200 bg-white p-4 text-center transition-all hover:border-gray-300 hover:shadow-md disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:hover:border-gray-500"
|
|
357
|
+
>
|
|
358
|
+
<div className="flex items-center justify-center gap-3">
|
|
359
|
+
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700">
|
|
360
|
+
<Wallet className="h-5 w-5 text-gray-600 dark:text-gray-400" />
|
|
361
|
+
</div>
|
|
362
|
+
<div>
|
|
363
|
+
<div className="text-sm font-medium text-gray-900 dark:text-white">
|
|
364
|
+
{isPending
|
|
365
|
+
? `Connecting to ${selectedWalletConnector?.name}...`
|
|
366
|
+
: `Connect ${selectedWalletConnector?.name}`}
|
|
367
|
+
</div>
|
|
368
|
+
<div className="text-xs text-gray-500 dark:text-gray-400">
|
|
369
|
+
{isPending ? "Please check your wallet" : "Click to connect and select account"}
|
|
370
|
+
</div>
|
|
371
|
+
</div>
|
|
372
|
+
</div>
|
|
373
|
+
</button>
|
|
374
|
+
</div>
|
|
375
|
+
)}
|
|
376
|
+
</div>
|
|
191
377
|
</div>
|
|
192
378
|
</div>,
|
|
193
379
|
typeof window !== "undefined" ? document.getElementById("b3-root") || document.body : document.body,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ALL_CHAINS,
|
|
5
|
+
DEPOSIT_HYPE_ACTION,
|
|
5
6
|
getChainName,
|
|
6
7
|
getErrorDisplay,
|
|
7
8
|
getExplorerTxUrl,
|
|
@@ -97,6 +98,9 @@ function getOrderSuccessText({
|
|
|
97
98
|
actionText = `funded ${tournament?.name}`;
|
|
98
99
|
return `Successfully ${actionText}`;
|
|
99
100
|
case "custom":
|
|
101
|
+
if (order.metadata.action === DEPOSIT_HYPE_ACTION) {
|
|
102
|
+
return `Successfully deposited ${formatTokenAmount(BigInt(order.payload?.amount || "0"), 18)} HYPE to ${recipient}`;
|
|
103
|
+
}
|
|
100
104
|
actionText = order.metadata.action || `executed contract`;
|
|
101
105
|
return `Successfully ${actionText}`;
|
|
102
106
|
default:
|
|
@@ -225,7 +229,7 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
225
229
|
const [showQRCode, setShowQRCode] = useState(false);
|
|
226
230
|
const { isLoading: txLoading, isSuccess: txSuccess } = useWaitForTransactionReceipt({ hash: txHash });
|
|
227
231
|
|
|
228
|
-
const {
|
|
232
|
+
const { switchChainAndExecuteWithEOA, isSwitchingOrExecuting } = useUnifiedChainSwitchAndExecute();
|
|
229
233
|
|
|
230
234
|
const { colorMode } = useColorMode();
|
|
231
235
|
|
|
@@ -260,12 +264,12 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
260
264
|
value = BigInt(0);
|
|
261
265
|
}
|
|
262
266
|
|
|
263
|
-
const txHash = await
|
|
267
|
+
const txHash = await switchChainAndExecuteWithEOA(order.srcChain, { to, data: txData, value });
|
|
264
268
|
|
|
265
269
|
if (txHash) {
|
|
266
270
|
setTxHash(txHash as `0x${string}`);
|
|
267
271
|
}
|
|
268
|
-
}, [order,
|
|
272
|
+
}, [order, switchChainAndExecuteWithEOA]);
|
|
269
273
|
|
|
270
274
|
// Main payment handler that triggers chain switch and payment
|
|
271
275
|
const handlePayment = async () => {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { Input,
|
|
1
|
+
import { Input, useProfile, useTokenData } from "@b3dotfun/sdk/global-account/react";
|
|
2
2
|
import { formatUsername } from "@b3dotfun/sdk/shared/utils";
|
|
3
3
|
import { shortenAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
|
|
4
4
|
import { formatDisplayNumber } from "@b3dotfun/sdk/shared/utils/number";
|
|
5
5
|
import { ChevronRight } from "lucide-react";
|
|
6
6
|
import { motion } from "motion/react";
|
|
7
7
|
import { useEffect, useRef } from "react";
|
|
8
|
+
import { useAccount } from "wagmi";
|
|
8
9
|
import { components } from "../../../types/api";
|
|
9
10
|
import { CryptoPaymentMethodType } from "./CryptoPaymentMethod";
|
|
10
11
|
import { FiatPaymentMethod } from "./FiatPaymentMethod";
|
|
@@ -45,8 +46,9 @@ export function PaySection({
|
|
|
45
46
|
onSelectFiatPaymentMethod,
|
|
46
47
|
anyspendQuote,
|
|
47
48
|
}: PaySectionProps) {
|
|
48
|
-
const { address:
|
|
49
|
-
const
|
|
49
|
+
const { address: connectedAddress, isConnected } = useAccount();
|
|
50
|
+
const { data: profileData } = useProfile({ address: connectedAddress });
|
|
51
|
+
const connectedName = profileData?.displayName;
|
|
50
52
|
const { data: srcTokenMetadata } = useTokenData(selectedSrcToken?.chainId, selectedSrcToken?.address);
|
|
51
53
|
|
|
52
54
|
// Add ref to track if we've applied metadata
|
|
@@ -88,12 +90,12 @@ export function PaySection({
|
|
|
88
90
|
<div className="text-as-primary/50 flex h-7 items-center text-sm">Pay</div>
|
|
89
91
|
{paymentType === "crypto" ? (
|
|
90
92
|
<button
|
|
91
|
-
className="text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors"
|
|
93
|
+
className="text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors focus:!outline-none"
|
|
92
94
|
onClick={onSelectCryptoPaymentMethod}
|
|
93
95
|
>
|
|
94
96
|
{selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (
|
|
95
97
|
<>
|
|
96
|
-
{
|
|
98
|
+
{isConnected ? (
|
|
97
99
|
<div className="flex items-center gap-1">
|
|
98
100
|
{connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "")}
|
|
99
101
|
</div>
|
|
@@ -151,7 +153,7 @@ export function PaySection({
|
|
|
151
153
|
{paymentType === "crypto" ? (
|
|
152
154
|
<>
|
|
153
155
|
<OrderTokenAmount
|
|
154
|
-
address={
|
|
156
|
+
address={connectedAddress}
|
|
155
157
|
context="from"
|
|
156
158
|
inputValue={srcAmount}
|
|
157
159
|
onChangeInput={value => {
|
|
@@ -172,7 +174,7 @@ export function PaySection({
|
|
|
172
174
|
</div>
|
|
173
175
|
<TokenBalance
|
|
174
176
|
token={selectedSrcToken}
|
|
175
|
-
walletAddress={
|
|
177
|
+
walletAddress={connectedAddress}
|
|
176
178
|
onChangeInput={value => {
|
|
177
179
|
setIsSrcInputDirty(true);
|
|
178
180
|
setSrcAmount(value);
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
useGeoOnrampOptions,
|
|
8
8
|
} from "@b3dotfun/sdk/anyspend/react";
|
|
9
9
|
import { anyspendService } from "@b3dotfun/sdk/anyspend/services/anyspend";
|
|
10
|
-
import { useAccountWallet, useProfile } from "@b3dotfun/sdk/global-account/react";
|
|
10
|
+
import { useAccountWallet, useProfile, useRouter, useSearchParamsSSR } from "@b3dotfun/sdk/global-account/react";
|
|
11
11
|
import { formatTokenAmount, formatUnits } from "@b3dotfun/sdk/shared/utils/number";
|
|
12
12
|
import { useEffect, useState } from "react";
|
|
13
13
|
import { toast } from "sonner";
|
|
@@ -35,6 +35,7 @@ interface UseAnyspendFlowProps {
|
|
|
35
35
|
onTransactionSuccess?: () => void;
|
|
36
36
|
sourceTokenAddress?: string;
|
|
37
37
|
sourceTokenChainId?: number;
|
|
38
|
+
slippage?: number;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export function useAnyspendFlow({
|
|
@@ -46,7 +47,11 @@ export function useAnyspendFlow({
|
|
|
46
47
|
onTransactionSuccess,
|
|
47
48
|
sourceTokenAddress,
|
|
48
49
|
sourceTokenChainId,
|
|
50
|
+
slippage = 0,
|
|
49
51
|
}: UseAnyspendFlowProps) {
|
|
52
|
+
const searchParams = useSearchParamsSSR();
|
|
53
|
+
const router = useRouter();
|
|
54
|
+
|
|
50
55
|
// Panel and order state
|
|
51
56
|
const [activePanel, setActivePanel] = useState<PanelView>(loadOrder ? PanelView.ORDER_DETAILS : PanelView.MAIN);
|
|
52
57
|
const [orderId, setOrderId] = useState<string | undefined>(loadOrder);
|
|
@@ -82,6 +87,12 @@ export function useAnyspendFlow({
|
|
|
82
87
|
}
|
|
83
88
|
}, [selectedRecipientAddress, globalAddress]);
|
|
84
89
|
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (paymentType === "crypto") {
|
|
92
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
93
|
+
}
|
|
94
|
+
}, [paymentType]);
|
|
95
|
+
|
|
85
96
|
// Fetch specific token when sourceTokenAddress and sourceTokenChainId are provided
|
|
86
97
|
useEffect(() => {
|
|
87
98
|
const fetchSourceToken = async () => {
|
|
@@ -135,12 +146,27 @@ export function useAnyspendFlow({
|
|
|
135
146
|
if (anyspendQuote?.data?.currencyOut?.amount && anyspendQuote.data.currencyOut.currency?.decimals) {
|
|
136
147
|
const amount = anyspendQuote.data.currencyOut.amount;
|
|
137
148
|
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
138
|
-
|
|
149
|
+
|
|
150
|
+
// Apply slippage (0-100) - reduce amount by slippage percentageFixed slippage value
|
|
151
|
+
const amountWithSlippage = (BigInt(amount) * BigInt(100 - slippage)) / BigInt(100);
|
|
152
|
+
|
|
153
|
+
const formattedAmount = formatTokenAmount(amountWithSlippage, decimals, 6, false);
|
|
139
154
|
setDstAmount(formattedAmount);
|
|
140
155
|
} else {
|
|
141
156
|
setDstAmount("");
|
|
142
157
|
}
|
|
143
|
-
}, [anyspendQuote]);
|
|
158
|
+
}, [anyspendQuote, slippage]);
|
|
159
|
+
|
|
160
|
+
// Update useEffect for URL parameter to not override loadOrder
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (loadOrder) return; // Skip if we have a loadOrder
|
|
163
|
+
|
|
164
|
+
const orderIdParam = searchParams.get("orderId");
|
|
165
|
+
if (orderIdParam) {
|
|
166
|
+
setOrderId(orderIdParam);
|
|
167
|
+
setActivePanel(PanelView.ORDER_DETAILS);
|
|
168
|
+
}
|
|
169
|
+
}, [searchParams, loadOrder]);
|
|
144
170
|
|
|
145
171
|
// Order creation hooks
|
|
146
172
|
const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
|
|
@@ -149,6 +175,18 @@ export function useAnyspendFlow({
|
|
|
149
175
|
setOrderId(newOrderId);
|
|
150
176
|
setActivePanel(PanelView.ORDER_DETAILS);
|
|
151
177
|
onOrderSuccess?.(newOrderId);
|
|
178
|
+
|
|
179
|
+
// Add orderId and payment method to URL for persistence
|
|
180
|
+
const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
|
|
181
|
+
params.set("orderId", newOrderId);
|
|
182
|
+
if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
|
|
183
|
+
console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
|
|
184
|
+
params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
|
|
185
|
+
} else {
|
|
186
|
+
console.log("Payment method is NONE, not setting in URL");
|
|
187
|
+
}
|
|
188
|
+
console.log("Final URL params:", params.toString());
|
|
189
|
+
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
152
190
|
},
|
|
153
191
|
onError: error => {
|
|
154
192
|
console.error(error);
|