@b3dotfun/sdk 0.0.28-alpha.0 → 0.0.28-alpha.2
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/abis/escrow.d.ts +987 -0
- package/dist/cjs/anyspend/abis/escrow.js +1275 -0
- package/dist/cjs/anyspend/react/components/AnySpend.js +10 -168
- package/dist/cjs/anyspend/react/components/AnySpendCustom.js +2 -2
- package/dist/cjs/anyspend/react/components/AnyspendDepositHype.d.ts +10 -0
- package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +263 -0
- package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.d.ts +17 -0
- package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +53 -0
- package/dist/cjs/anyspend/react/components/common/ErrorSection.d.ts +6 -0
- package/dist/cjs/anyspend/react/components/common/ErrorSection.js +12 -0
- 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/PaySection.d.ts +20 -0
- package/dist/cjs/anyspend/react/components/common/PaySection.js +58 -0
- package/dist/cjs/anyspend/react/components/common/TabSection.d.ts +10 -0
- package/dist/cjs/anyspend/react/components/common/TabSection.js +18 -0
- package/dist/cjs/anyspend/react/components/index.d.ts +2 -0
- package/dist/cjs/anyspend/react/components/index.js +5 -1
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +165 -0
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +184 -0
- package/dist/cjs/anyspend/react/hooks/useSigMint.d.ts +2 -2
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +3 -0
- package/dist/cjs/global-account/react/components/custom/Button.d.ts +1 -1
- package/dist/cjs/global-account/react/components/ui/button.d.ts +1 -1
- package/dist/cjs/global-account/react/components/ui/command.d.ts +2 -2
- package/dist/cjs/global-account/react/hooks/useSiwe.native.d.ts +4 -0
- package/dist/cjs/global-account/react/hooks/useSiwe.native.js +40 -0
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +17 -1
- package/dist/cjs/shared/constants/chains/b3Chain.d.ts +1 -1
- package/dist/cjs/shared/constants/chains/supported.d.ts +3 -3
- package/dist/esm/anyspend/abis/escrow.d.ts +987 -0
- package/dist/esm/anyspend/abis/escrow.js +1272 -0
- package/dist/esm/anyspend/react/components/AnySpend.js +12 -170
- package/dist/esm/anyspend/react/components/AnySpendCustom.js +3 -3
- package/dist/esm/anyspend/react/components/AnyspendDepositHype.d.ts +10 -0
- package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +257 -0
- package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.d.ts +17 -0
- package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +50 -0
- package/dist/esm/anyspend/react/components/common/ErrorSection.d.ts +6 -0
- package/dist/esm/anyspend/react/components/common/ErrorSection.js +9 -0
- 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/PaySection.d.ts +20 -0
- package/dist/esm/anyspend/react/components/common/PaySection.js +55 -0
- package/dist/esm/anyspend/react/components/common/TabSection.d.ts +10 -0
- package/dist/esm/anyspend/react/components/common/TabSection.js +15 -0
- package/dist/esm/anyspend/react/components/index.d.ts +2 -0
- package/dist/esm/anyspend/react/components/index.js +2 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +165 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +180 -0
- package/dist/esm/anyspend/react/hooks/useSigMint.d.ts +2 -2
- package/dist/esm/global-account/react/components/B3DynamicModal.js +3 -0
- package/dist/esm/global-account/react/components/custom/Button.d.ts +1 -1
- package/dist/esm/global-account/react/components/ui/button.d.ts +1 -1
- package/dist/esm/global-account/react/components/ui/command.d.ts +2 -2
- package/dist/esm/global-account/react/hooks/useSiwe.native.d.ts +4 -0
- package/dist/esm/global-account/react/hooks/useSiwe.native.js +34 -0
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +17 -1
- package/dist/esm/shared/constants/chains/b3Chain.d.ts +1 -1
- package/dist/esm/shared/constants/chains/supported.d.ts +3 -3
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/abis/escrow.d.ts +987 -0
- package/dist/types/anyspend/react/components/AnyspendDepositHype.d.ts +10 -0
- package/dist/types/anyspend/react/components/common/CryptoReceiveSection.d.ts +17 -0
- package/dist/types/anyspend/react/components/common/ErrorSection.d.ts +6 -0
- package/dist/types/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
- package/dist/types/anyspend/react/components/common/PaySection.d.ts +20 -0
- package/dist/types/anyspend/react/components/common/TabSection.d.ts +10 -0
- package/dist/types/anyspend/react/components/index.d.ts +2 -0
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +165 -0
- package/dist/types/anyspend/react/hooks/useSigMint.d.ts +2 -2
- package/dist/types/global-account/react/components/custom/Button.d.ts +1 -1
- package/dist/types/global-account/react/components/ui/button.d.ts +1 -1
- package/dist/types/global-account/react/components/ui/command.d.ts +2 -2
- package/dist/types/global-account/react/hooks/useSiwe.native.d.ts +4 -0
- package/dist/types/global-account/react/stores/useModalStore.d.ts +17 -1
- package/dist/types/shared/constants/chains/b3Chain.d.ts +1 -1
- package/dist/types/shared/constants/chains/supported.d.ts +3 -3
- package/package.json +13 -1
- package/src/anyspend/abis/escrow.ts +1272 -0
- package/src/anyspend/react/components/AnySpend.tsx +48 -389
- package/src/anyspend/react/components/AnySpendCustom.tsx +2 -10
- package/src/anyspend/react/components/AnyspendDepositHype.tsx +525 -0
- package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +152 -0
- package/src/anyspend/react/components/common/ErrorSection.tsx +21 -0
- package/src/anyspend/react/components/common/PanelOnramp.tsx +4 -2
- package/src/anyspend/react/components/common/PaySection.tsx +222 -0
- package/src/anyspend/react/components/common/TabSection.tsx +58 -0
- package/src/anyspend/react/components/index.ts +2 -0
- package/src/anyspend/react/hooks/useAnyspendFlow.ts +226 -0
- package/src/global-account/react/components/B3DynamicModal.tsx +3 -0
- package/src/global-account/react/hooks/useSiwe.native.tsx +40 -0
- package/src/global-account/react/stores/useModalStore.ts +19 -1
|
@@ -21,6 +21,7 @@ export function PanelOnramp({
|
|
|
21
21
|
destinationAmount,
|
|
22
22
|
onDestinationTokenChange,
|
|
23
23
|
onDestinationChainChange,
|
|
24
|
+
fiatPaymentMethodIndex,
|
|
24
25
|
}: {
|
|
25
26
|
srcAmountOnRamp: string;
|
|
26
27
|
setSrcAmountOnRamp: (amount: string) => void;
|
|
@@ -32,6 +33,7 @@ export function PanelOnramp({
|
|
|
32
33
|
destinationAmount?: string;
|
|
33
34
|
onDestinationTokenChange?: (token: components["schemas"]["Token"]) => void;
|
|
34
35
|
onDestinationChainChange?: (chainId: number) => void;
|
|
36
|
+
fiatPaymentMethodIndex: number;
|
|
35
37
|
}) {
|
|
36
38
|
// Get geo-based onramp options to access fee information
|
|
37
39
|
const { stripeWeb2Support } = useGeoOnrampOptions(srcAmountOnRamp);
|
|
@@ -102,14 +104,14 @@ export function PanelOnramp({
|
|
|
102
104
|
};
|
|
103
105
|
|
|
104
106
|
return (
|
|
105
|
-
<div className="bg-as-surface-primary flex w-full flex-col">
|
|
107
|
+
<div className="panel-onramp bg-as-surface-primary flex w-full flex-col">
|
|
106
108
|
{/* Pay Section */}
|
|
107
109
|
<div className="border-as-border-secondary bg-as-surface-secondary relative flex w-full flex-col rounded-2xl border p-4">
|
|
108
110
|
<div className="flex h-7 w-full items-center justify-between">
|
|
109
111
|
<span className="text-as-tertiarry flex items-center text-sm font-bold">Pay</span>
|
|
110
112
|
<button
|
|
111
113
|
className="text-as-tertiarry flex h-7 items-center gap-1 text-sm"
|
|
112
|
-
onClick={() => setActivePanel(
|
|
114
|
+
onClick={() => setActivePanel(fiatPaymentMethodIndex)} // PanelView.FIAT_PAYMENT_METHOD
|
|
113
115
|
>
|
|
114
116
|
{selectedPaymentMethod === FiatPaymentMethod.COINBASE_PAY ? (
|
|
115
117
|
<>
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { Input, useAccountWallet, useTokenData } from "@b3dotfun/sdk/global-account/react";
|
|
2
|
+
import { formatUsername } from "@b3dotfun/sdk/shared/utils";
|
|
3
|
+
import { shortenAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
|
|
4
|
+
import { formatDisplayNumber } from "@b3dotfun/sdk/shared/utils/number";
|
|
5
|
+
import { ChevronRight } from "lucide-react";
|
|
6
|
+
import { motion } from "motion/react";
|
|
7
|
+
import { useEffect, useRef } from "react";
|
|
8
|
+
import { components } from "../../../types/api";
|
|
9
|
+
import { CryptoPaymentMethodType } from "./CryptoPaymentMethod";
|
|
10
|
+
import { FiatPaymentMethod } from "./FiatPaymentMethod";
|
|
11
|
+
import { OrderTokenAmount } from "./OrderTokenAmount";
|
|
12
|
+
import { TokenBalance } from "./TokenBalance";
|
|
13
|
+
|
|
14
|
+
interface PaySectionProps {
|
|
15
|
+
paymentType: "crypto" | "fiat";
|
|
16
|
+
// Token state
|
|
17
|
+
selectedSrcChainId: number;
|
|
18
|
+
setSelectedSrcChainId: (chainId: number) => void;
|
|
19
|
+
selectedSrcToken: components["schemas"]["Token"];
|
|
20
|
+
setSelectedSrcToken: (token: components["schemas"]["Token"]) => void;
|
|
21
|
+
srcAmount: string;
|
|
22
|
+
setSrcAmount: (amount: string) => void;
|
|
23
|
+
setIsSrcInputDirty: (dirty: boolean) => void;
|
|
24
|
+
// Payment method state
|
|
25
|
+
selectedCryptoPaymentMethod: CryptoPaymentMethodType;
|
|
26
|
+
selectedFiatPaymentMethod: FiatPaymentMethod;
|
|
27
|
+
onSelectCryptoPaymentMethod: () => void;
|
|
28
|
+
onSelectFiatPaymentMethod: () => void;
|
|
29
|
+
// Quote data
|
|
30
|
+
anyspendQuote?: any;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function PaySection({
|
|
34
|
+
paymentType,
|
|
35
|
+
selectedSrcChainId,
|
|
36
|
+
setSelectedSrcChainId,
|
|
37
|
+
selectedSrcToken,
|
|
38
|
+
setSelectedSrcToken,
|
|
39
|
+
srcAmount,
|
|
40
|
+
setSrcAmount,
|
|
41
|
+
setIsSrcInputDirty,
|
|
42
|
+
selectedCryptoPaymentMethod,
|
|
43
|
+
selectedFiatPaymentMethod,
|
|
44
|
+
onSelectCryptoPaymentMethod,
|
|
45
|
+
onSelectFiatPaymentMethod,
|
|
46
|
+
anyspendQuote,
|
|
47
|
+
}: PaySectionProps) {
|
|
48
|
+
const { address: globalAddress, wallet: globalWallet, ensName: connectedName } = useAccountWallet();
|
|
49
|
+
const connectedAddress = globalWallet?.address;
|
|
50
|
+
const { data: srcTokenMetadata } = useTokenData(selectedSrcToken?.chainId, selectedSrcToken?.address);
|
|
51
|
+
|
|
52
|
+
// Add ref to track if we've applied metadata
|
|
53
|
+
const appliedSrcMetadataRef = useRef(false);
|
|
54
|
+
|
|
55
|
+
// Update source token with metadata
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (selectedSrcToken && srcTokenMetadata && !appliedSrcMetadataRef.current) {
|
|
58
|
+
// Mark as applied
|
|
59
|
+
appliedSrcMetadataRef.current = true;
|
|
60
|
+
|
|
61
|
+
const enhancedToken = {
|
|
62
|
+
...selectedSrcToken,
|
|
63
|
+
decimals: srcTokenMetadata.decimals || selectedSrcToken.decimals,
|
|
64
|
+
symbol: srcTokenMetadata.symbol || selectedSrcToken.symbol,
|
|
65
|
+
name: srcTokenMetadata.name || selectedSrcToken.name,
|
|
66
|
+
metadata: {
|
|
67
|
+
...selectedSrcToken.metadata,
|
|
68
|
+
logoURI: srcTokenMetadata?.logoURI || selectedSrcToken.metadata.logoURI,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
setSelectedSrcToken(enhancedToken);
|
|
72
|
+
}
|
|
73
|
+
}, [srcTokenMetadata, selectedSrcToken, setSelectedSrcToken]);
|
|
74
|
+
|
|
75
|
+
// Reset source token ref when address/chain changes
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
appliedSrcMetadataRef.current = false;
|
|
78
|
+
}, [selectedSrcToken.address, selectedSrcToken.chainId]);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<motion.div
|
|
82
|
+
initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
|
|
83
|
+
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
|
84
|
+
transition={{ duration: 0.3, delay: 0, ease: "easeInOut" }}
|
|
85
|
+
className="bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6"
|
|
86
|
+
>
|
|
87
|
+
<div className="flex items-center justify-between">
|
|
88
|
+
<div className="text-as-primary/50 flex h-7 items-center text-sm">Pay</div>
|
|
89
|
+
{paymentType === "crypto" ? (
|
|
90
|
+
<button
|
|
91
|
+
className="text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors"
|
|
92
|
+
onClick={onSelectCryptoPaymentMethod}
|
|
93
|
+
>
|
|
94
|
+
{selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (
|
|
95
|
+
<>
|
|
96
|
+
{globalAddress ? (
|
|
97
|
+
<div className="flex items-center gap-1">
|
|
98
|
+
{connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "")}
|
|
99
|
+
</div>
|
|
100
|
+
) : (
|
|
101
|
+
"Connect wallet"
|
|
102
|
+
)}
|
|
103
|
+
<ChevronRight className="h-4 w-4" />
|
|
104
|
+
</>
|
|
105
|
+
) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (
|
|
106
|
+
<>
|
|
107
|
+
Transfer crypto
|
|
108
|
+
<ChevronRight className="h-4 w-4" />
|
|
109
|
+
</>
|
|
110
|
+
) : (
|
|
111
|
+
<>
|
|
112
|
+
Select payment method
|
|
113
|
+
<ChevronRight className="h-4 w-4" />
|
|
114
|
+
</>
|
|
115
|
+
)}
|
|
116
|
+
</button>
|
|
117
|
+
) : (
|
|
118
|
+
<button
|
|
119
|
+
className="text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors"
|
|
120
|
+
onClick={onSelectFiatPaymentMethod}
|
|
121
|
+
>
|
|
122
|
+
{selectedFiatPaymentMethod === FiatPaymentMethod.COINBASE_PAY ? (
|
|
123
|
+
<>
|
|
124
|
+
<div className="flex items-center gap-2">
|
|
125
|
+
<div className="flex h-5 w-5 items-center justify-center rounded-full bg-blue-600">
|
|
126
|
+
<span className="text-xs font-bold text-white">C</span>
|
|
127
|
+
</div>
|
|
128
|
+
Coinbase Pay
|
|
129
|
+
</div>
|
|
130
|
+
<ChevronRight className="h-4 w-4" />
|
|
131
|
+
</>
|
|
132
|
+
) : selectedFiatPaymentMethod === FiatPaymentMethod.STRIPE ? (
|
|
133
|
+
<>
|
|
134
|
+
<div className="flex items-center gap-2">
|
|
135
|
+
<div className="flex h-5 w-5 items-center justify-center rounded-full bg-blue-600">
|
|
136
|
+
<span className="text-xs font-bold text-white">S</span>
|
|
137
|
+
</div>
|
|
138
|
+
Credit/Debit Card
|
|
139
|
+
</div>
|
|
140
|
+
<ChevronRight className="h-4 w-4" />
|
|
141
|
+
</>
|
|
142
|
+
) : (
|
|
143
|
+
<>
|
|
144
|
+
Select payment method
|
|
145
|
+
<ChevronRight className="h-4 w-4" />
|
|
146
|
+
</>
|
|
147
|
+
)}
|
|
148
|
+
</button>
|
|
149
|
+
)}
|
|
150
|
+
</div>
|
|
151
|
+
{paymentType === "crypto" ? (
|
|
152
|
+
<>
|
|
153
|
+
<OrderTokenAmount
|
|
154
|
+
address={globalAddress}
|
|
155
|
+
context="from"
|
|
156
|
+
inputValue={srcAmount}
|
|
157
|
+
onChangeInput={value => {
|
|
158
|
+
setIsSrcInputDirty(true);
|
|
159
|
+
setSrcAmount(value);
|
|
160
|
+
}}
|
|
161
|
+
chainId={selectedSrcChainId}
|
|
162
|
+
setChainId={setSelectedSrcChainId}
|
|
163
|
+
token={selectedSrcToken}
|
|
164
|
+
setToken={setSelectedSrcToken}
|
|
165
|
+
/>
|
|
166
|
+
<div className="flex items-center justify-between">
|
|
167
|
+
<div className="text-as-primary/50 flex h-5 items-center text-sm">
|
|
168
|
+
{formatDisplayNumber(anyspendQuote?.data?.currencyIn?.amountUsd, {
|
|
169
|
+
style: "currency",
|
|
170
|
+
fallback: "",
|
|
171
|
+
})}
|
|
172
|
+
</div>
|
|
173
|
+
<TokenBalance
|
|
174
|
+
token={selectedSrcToken}
|
|
175
|
+
walletAddress={globalAddress}
|
|
176
|
+
onChangeInput={value => {
|
|
177
|
+
setIsSrcInputDirty(true);
|
|
178
|
+
setSrcAmount(value);
|
|
179
|
+
}}
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
</>
|
|
183
|
+
) : (
|
|
184
|
+
<>
|
|
185
|
+
{/* Fiat amount input - styled like PanelOnramp */}
|
|
186
|
+
<div className="flex items-center justify-center pb-2 pt-8">
|
|
187
|
+
<div className="flex gap-1">
|
|
188
|
+
<span className="text-as-tertiarry text-2xl font-bold">$</span>
|
|
189
|
+
<Input
|
|
190
|
+
type="text"
|
|
191
|
+
value={srcAmount}
|
|
192
|
+
onChange={e => setSrcAmount(e.target.value.replace(/[^0-9.]/g, ""))}
|
|
193
|
+
placeholder="5"
|
|
194
|
+
className="text-as-primary placeholder:text-as-primary/50 h-auto min-w-[70px] border-0 bg-transparent p-0 px-3 pt-1 text-4xl font-bold focus-visible:ring-0 focus-visible:ring-offset-0"
|
|
195
|
+
style={{
|
|
196
|
+
width: `${Math.max(50, srcAmount.length * 34)}px`,
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
{/* Quick Amount Buttons */}
|
|
203
|
+
<div className="mx-auto mb-6 inline-grid grid-cols-4 gap-2">
|
|
204
|
+
{["5", "10", "20", "25"].map(value => (
|
|
205
|
+
<button
|
|
206
|
+
key={value}
|
|
207
|
+
onClick={() => setSrcAmount(value)}
|
|
208
|
+
className={`bg-as-surface-secondary border-as-border-secondary hover:border-as-border-secondary h-7 w-14 rounded-lg border text-sm font-medium transition-all duration-200 ${
|
|
209
|
+
srcAmount === value
|
|
210
|
+
? "border-as-border-secondary bg-as-surface-secondary"
|
|
211
|
+
: "bg-as-surface-secondary hover:bg-as-surface-secondary"
|
|
212
|
+
}`}
|
|
213
|
+
>
|
|
214
|
+
${value}
|
|
215
|
+
</button>
|
|
216
|
+
))}
|
|
217
|
+
</div>
|
|
218
|
+
</>
|
|
219
|
+
)}
|
|
220
|
+
</motion.div>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
2
|
+
import { CryptoPaymentMethodType } from "./CryptoPaymentMethod";
|
|
3
|
+
import { FiatPaymentMethod } from "./FiatPaymentMethod";
|
|
4
|
+
|
|
5
|
+
interface TabSectionProps {
|
|
6
|
+
activeTab: "crypto" | "fiat";
|
|
7
|
+
setActiveTab: (tab: "crypto" | "fiat") => void;
|
|
8
|
+
setSelectedCryptoPaymentMethod: (method: CryptoPaymentMethodType) => void;
|
|
9
|
+
setSelectedFiatPaymentMethod: (method: FiatPaymentMethod) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function TabSection({
|
|
13
|
+
activeTab,
|
|
14
|
+
setActiveTab,
|
|
15
|
+
setSelectedCryptoPaymentMethod,
|
|
16
|
+
setSelectedFiatPaymentMethod,
|
|
17
|
+
}: TabSectionProps) {
|
|
18
|
+
return (
|
|
19
|
+
<div className="tab-section w-full">
|
|
20
|
+
<div className="bg-as-surface-secondary relative mb-4 grid h-10 grid-cols-2 rounded-xl">
|
|
21
|
+
<div
|
|
22
|
+
className={cn(
|
|
23
|
+
"bg-as-brand absolute bottom-0 left-0 top-0 z-0 rounded-xl transition-transform duration-100",
|
|
24
|
+
"h-full w-1/2",
|
|
25
|
+
activeTab === "fiat" ? "translate-x-full" : "translate-x-0",
|
|
26
|
+
)}
|
|
27
|
+
style={{ willChange: "transform" }}
|
|
28
|
+
/>
|
|
29
|
+
<button
|
|
30
|
+
className={cn(
|
|
31
|
+
"relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100",
|
|
32
|
+
activeTab === "crypto" ? "text-white" : "text-as-primary/70 hover:bg-as-on-surface-2 bg-transparent",
|
|
33
|
+
)}
|
|
34
|
+
onClick={() => {
|
|
35
|
+
setActiveTab("crypto");
|
|
36
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE); // Reset payment method when switching to crypto
|
|
37
|
+
setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE); // Reset fiat payment method when switching to crypto
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
Pay with crypto
|
|
41
|
+
</button>
|
|
42
|
+
<button
|
|
43
|
+
className={cn(
|
|
44
|
+
"relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100",
|
|
45
|
+
activeTab === "fiat" ? "text-white" : "text-as-primary/70 hover:bg-as-on-surface-2 bg-transparent",
|
|
46
|
+
)}
|
|
47
|
+
onClick={() => {
|
|
48
|
+
setActiveTab("fiat");
|
|
49
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE); // Reset crypto payment method when switching to fiat
|
|
50
|
+
setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE); // Reset fiat payment method when switching to fiat
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
Pay with Fiat
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -12,6 +12,7 @@ export { AnySpendNFTButton } from "./common/AnySpendNFTButton";
|
|
|
12
12
|
|
|
13
13
|
// Common Components
|
|
14
14
|
export { ChainTokenIcon } from "./common/ChainTokenIcon";
|
|
15
|
+
export { CryptoReceiveSection } from "./common/CryptoReceiveSection";
|
|
15
16
|
export { OrderDetails } from "./common/OrderDetails";
|
|
16
17
|
export { OrderDetailsCollapsible } from "./common/OrderDetailsCollapsible";
|
|
17
18
|
export { OrderHistory } from "./common/OrderHistory";
|
|
@@ -19,6 +20,7 @@ export { OrderHistoryItem } from "./common/OrderHistoryItem";
|
|
|
19
20
|
export { OrderStatus } from "./common/OrderStatus";
|
|
20
21
|
export { OrderToken } from "./common/OrderToken";
|
|
21
22
|
export { OrderTokenAmount } from "./common/OrderTokenAmount";
|
|
23
|
+
export { PaySection } from "./common/PaySection";
|
|
22
24
|
export { RecipientSelection } from "./common/RecipientSelection";
|
|
23
25
|
export { StepProgress } from "./common/StepProgress";
|
|
24
26
|
export { TokenBalance } from "./common/TokenBalance";
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { B3_TOKEN, getDefaultToken, USDC_BASE } from "@b3dotfun/sdk/anyspend";
|
|
2
|
+
import {
|
|
3
|
+
useAnyspendCreateOnrampOrder,
|
|
4
|
+
useAnyspendCreateOrder,
|
|
5
|
+
useAnyspendOrderAndTransactions,
|
|
6
|
+
useAnyspendQuote,
|
|
7
|
+
useGeoOnrampOptions,
|
|
8
|
+
} from "@b3dotfun/sdk/anyspend/react";
|
|
9
|
+
import { anyspendService } from "@b3dotfun/sdk/anyspend/services/anyspend";
|
|
10
|
+
import { useAccountWallet, useProfile } from "@b3dotfun/sdk/global-account/react";
|
|
11
|
+
import { formatTokenAmount, formatUnits } from "@b3dotfun/sdk/shared/utils/number";
|
|
12
|
+
import { useEffect, useState } from "react";
|
|
13
|
+
import { toast } from "sonner";
|
|
14
|
+
import { parseUnits } from "viem";
|
|
15
|
+
import { base, mainnet } from "viem/chains";
|
|
16
|
+
import { components } from "../../types/api";
|
|
17
|
+
import { CryptoPaymentMethodType } from "../components/common/CryptoPaymentMethod";
|
|
18
|
+
import { FiatPaymentMethod } from "../components/common/FiatPaymentMethod";
|
|
19
|
+
|
|
20
|
+
export enum PanelView {
|
|
21
|
+
MAIN,
|
|
22
|
+
CRYPTO_PAYMENT_METHOD,
|
|
23
|
+
FIAT_PAYMENT_METHOD,
|
|
24
|
+
RECIPIENT_SELECTION,
|
|
25
|
+
ORDER_DETAILS,
|
|
26
|
+
LOADING,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface UseAnyspendFlowProps {
|
|
30
|
+
paymentType?: "crypto" | "fiat";
|
|
31
|
+
recipientAddress?: string;
|
|
32
|
+
loadOrder?: string;
|
|
33
|
+
isDepositMode?: boolean;
|
|
34
|
+
onOrderSuccess?: (orderId: string) => void;
|
|
35
|
+
onTransactionSuccess?: () => void;
|
|
36
|
+
sourceTokenAddress?: string;
|
|
37
|
+
sourceTokenChainId?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function useAnyspendFlow({
|
|
41
|
+
paymentType = "crypto",
|
|
42
|
+
recipientAddress,
|
|
43
|
+
loadOrder,
|
|
44
|
+
isDepositMode = false,
|
|
45
|
+
onOrderSuccess,
|
|
46
|
+
onTransactionSuccess,
|
|
47
|
+
sourceTokenAddress,
|
|
48
|
+
sourceTokenChainId,
|
|
49
|
+
}: UseAnyspendFlowProps) {
|
|
50
|
+
// Panel and order state
|
|
51
|
+
const [activePanel, setActivePanel] = useState<PanelView>(loadOrder ? PanelView.ORDER_DETAILS : PanelView.MAIN);
|
|
52
|
+
const [orderId, setOrderId] = useState<string | undefined>(loadOrder);
|
|
53
|
+
const { orderAndTransactions: oat } = useAnyspendOrderAndTransactions(orderId);
|
|
54
|
+
|
|
55
|
+
// Token selection state - use provided sourceTokenChainId if available
|
|
56
|
+
const [selectedSrcChainId, setSelectedSrcChainId] = useState<number>(
|
|
57
|
+
sourceTokenChainId || (paymentType === "fiat" ? base.id : mainnet.id),
|
|
58
|
+
);
|
|
59
|
+
const [selectedDstChainId, setSelectedDstChainId] = useState<number>(base.id); // Default to Base for cross-chain swaps
|
|
60
|
+
const defaultSrcToken = paymentType === "fiat" ? USDC_BASE : getDefaultToken(selectedSrcChainId);
|
|
61
|
+
const [selectedSrcToken, setSelectedSrcToken] = useState<components["schemas"]["Token"]>(defaultSrcToken);
|
|
62
|
+
const [srcAmount, setSrcAmount] = useState<string>(paymentType === "fiat" ? "5" : "0.1");
|
|
63
|
+
const [dstAmount, setDstAmount] = useState<string>("");
|
|
64
|
+
const [isSrcInputDirty, setIsSrcInputDirty] = useState(true);
|
|
65
|
+
|
|
66
|
+
// Payment method state
|
|
67
|
+
const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = useState<CryptoPaymentMethodType>(
|
|
68
|
+
CryptoPaymentMethodType.NONE,
|
|
69
|
+
);
|
|
70
|
+
const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState<FiatPaymentMethod>(FiatPaymentMethod.NONE);
|
|
71
|
+
|
|
72
|
+
// Recipient state
|
|
73
|
+
const { address: globalAddress } = useAccountWallet();
|
|
74
|
+
const [selectedRecipientAddress, setSelectedRecipientAddress] = useState<string | undefined>(recipientAddress);
|
|
75
|
+
const recipientProfile = useProfile({ address: selectedRecipientAddress, fresh: true });
|
|
76
|
+
const recipientName = recipientProfile.data?.name;
|
|
77
|
+
|
|
78
|
+
// Set default recipient address when wallet changes
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!selectedRecipientAddress && globalAddress) {
|
|
81
|
+
setSelectedRecipientAddress(globalAddress);
|
|
82
|
+
}
|
|
83
|
+
}, [selectedRecipientAddress, globalAddress]);
|
|
84
|
+
|
|
85
|
+
// Fetch specific token when sourceTokenAddress and sourceTokenChainId are provided
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const fetchSourceToken = async () => {
|
|
88
|
+
if (sourceTokenAddress && sourceTokenChainId) {
|
|
89
|
+
try {
|
|
90
|
+
const token = await anyspendService.getToken(sourceTokenChainId, sourceTokenAddress);
|
|
91
|
+
setSelectedSrcToken(token);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error("Failed to fetch source token:", error);
|
|
94
|
+
toast.error(`Failed to load token ${sourceTokenAddress} on chain ${sourceTokenChainId}`);
|
|
95
|
+
// Keep the default token on error
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
fetchSourceToken();
|
|
101
|
+
}, [sourceTokenAddress, sourceTokenChainId]);
|
|
102
|
+
|
|
103
|
+
// Helper function for onramp vendor mapping
|
|
104
|
+
const getOnrampVendor = (paymentMethod: FiatPaymentMethod): "coinbase" | "stripe" | "stripe-web2" | undefined => {
|
|
105
|
+
switch (paymentMethod) {
|
|
106
|
+
case FiatPaymentMethod.COINBASE_PAY:
|
|
107
|
+
return "coinbase";
|
|
108
|
+
case FiatPaymentMethod.STRIPE:
|
|
109
|
+
return "stripe-web2";
|
|
110
|
+
default:
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Get quote
|
|
116
|
+
const activeInputAmountInWei = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals).toString();
|
|
117
|
+
const { anyspendQuote, isLoadingAnyspendQuote, getAnyspendQuoteError } = useAnyspendQuote({
|
|
118
|
+
srcChain: paymentType === "fiat" ? base.id : selectedSrcChainId,
|
|
119
|
+
dstChain: isDepositMode ? base.id : selectedDstChainId, // For deposits, always Base; for swaps, use selected destination
|
|
120
|
+
srcTokenAddress: paymentType === "fiat" ? USDC_BASE.address : selectedSrcToken.address,
|
|
121
|
+
dstTokenAddress: isDepositMode ? B3_TOKEN.address : selectedSrcToken.address, // For deposits, always B3
|
|
122
|
+
type: "swap",
|
|
123
|
+
tradeType: "EXACT_INPUT",
|
|
124
|
+
amount: activeInputAmountInWei,
|
|
125
|
+
onrampVendor: paymentType === "fiat" ? getOnrampVendor(selectedFiatPaymentMethod) : undefined,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Get geo options for fiat
|
|
129
|
+
const { geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support } = useGeoOnrampOptions(
|
|
130
|
+
paymentType === "fiat" ? formatUnits(activeInputAmountInWei, USDC_BASE.decimals) : "0",
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// Update destination amount when quote changes
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
if (anyspendQuote?.data?.currencyOut?.amount && anyspendQuote.data.currencyOut.currency?.decimals) {
|
|
136
|
+
const amount = anyspendQuote.data.currencyOut.amount;
|
|
137
|
+
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
138
|
+
const formattedAmount = formatTokenAmount(BigInt(amount), decimals, 6, false);
|
|
139
|
+
setDstAmount(formattedAmount);
|
|
140
|
+
} else {
|
|
141
|
+
setDstAmount("");
|
|
142
|
+
}
|
|
143
|
+
}, [anyspendQuote]);
|
|
144
|
+
|
|
145
|
+
// Order creation hooks
|
|
146
|
+
const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
|
|
147
|
+
onSuccess: data => {
|
|
148
|
+
const newOrderId = data.data.id;
|
|
149
|
+
setOrderId(newOrderId);
|
|
150
|
+
setActivePanel(PanelView.ORDER_DETAILS);
|
|
151
|
+
onOrderSuccess?.(newOrderId);
|
|
152
|
+
},
|
|
153
|
+
onError: error => {
|
|
154
|
+
console.error(error);
|
|
155
|
+
toast.error("Failed to create order: " + error.message);
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const { createOrder: createOnrampOrder, isCreatingOrder: isCreatingOnrampOrder } = useAnyspendCreateOnrampOrder({
|
|
160
|
+
onSuccess: data => {
|
|
161
|
+
const newOrderId = data.data.id;
|
|
162
|
+
setOrderId(newOrderId);
|
|
163
|
+
setActivePanel(PanelView.ORDER_DETAILS);
|
|
164
|
+
onOrderSuccess?.(newOrderId);
|
|
165
|
+
},
|
|
166
|
+
onError: error => {
|
|
167
|
+
console.error(error);
|
|
168
|
+
toast.error("Failed to create order: " + error.message);
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Handle order completion
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
if (oat?.data?.order.status === "executed") {
|
|
175
|
+
console.log("Order executed successfully");
|
|
176
|
+
onTransactionSuccess?.();
|
|
177
|
+
}
|
|
178
|
+
}, [oat?.data?.order.status, onTransactionSuccess]);
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
// State
|
|
182
|
+
activePanel,
|
|
183
|
+
setActivePanel,
|
|
184
|
+
orderId,
|
|
185
|
+
setOrderId,
|
|
186
|
+
oat,
|
|
187
|
+
// Token state
|
|
188
|
+
selectedSrcChainId,
|
|
189
|
+
setSelectedSrcChainId,
|
|
190
|
+
selectedDstChainId,
|
|
191
|
+
setSelectedDstChainId,
|
|
192
|
+
selectedSrcToken,
|
|
193
|
+
setSelectedSrcToken,
|
|
194
|
+
srcAmount,
|
|
195
|
+
setSrcAmount,
|
|
196
|
+
dstAmount,
|
|
197
|
+
setDstAmount,
|
|
198
|
+
isSrcInputDirty,
|
|
199
|
+
setIsSrcInputDirty,
|
|
200
|
+
// Payment methods
|
|
201
|
+
selectedCryptoPaymentMethod,
|
|
202
|
+
setSelectedCryptoPaymentMethod,
|
|
203
|
+
selectedFiatPaymentMethod,
|
|
204
|
+
setSelectedFiatPaymentMethod,
|
|
205
|
+
// Recipient
|
|
206
|
+
selectedRecipientAddress,
|
|
207
|
+
setSelectedRecipientAddress,
|
|
208
|
+
recipientName,
|
|
209
|
+
globalAddress,
|
|
210
|
+
// Quote data
|
|
211
|
+
anyspendQuote,
|
|
212
|
+
isLoadingAnyspendQuote,
|
|
213
|
+
getAnyspendQuoteError,
|
|
214
|
+
activeInputAmountInWei,
|
|
215
|
+
// Geo/onramp data
|
|
216
|
+
geoData,
|
|
217
|
+
coinbaseAvailablePaymentMethods,
|
|
218
|
+
stripeWeb2Support,
|
|
219
|
+
getOnrampVendor,
|
|
220
|
+
// Order creation
|
|
221
|
+
createOrder,
|
|
222
|
+
isCreatingOrder,
|
|
223
|
+
createOnrampOrder,
|
|
224
|
+
isCreatingOnrampOrder,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
AnySpendTournament,
|
|
9
9
|
OrderHistory,
|
|
10
10
|
} from "@b3dotfun/sdk/anyspend/react";
|
|
11
|
+
import { AnySpendDepositHype } from "@b3dotfun/sdk/anyspend/react/components/AnyspendDepositHype";
|
|
11
12
|
import { useIsMobile, useModalStore } from "@b3dotfun/sdk/global-account/react";
|
|
12
13
|
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
13
14
|
import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
|
|
@@ -107,6 +108,8 @@ export function B3DynamicModal() {
|
|
|
107
108
|
return <AnySpendBondKit {...contentType} />;
|
|
108
109
|
case "linkAccount":
|
|
109
110
|
return <LinkAccount {...contentType} />;
|
|
111
|
+
case "anySpendDepositHype":
|
|
112
|
+
return <AnySpendDepositHype {...contentType} mode="modal" />;
|
|
110
113
|
// Add other modal types here
|
|
111
114
|
default:
|
|
112
115
|
return null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import app from "@b3dotfun/sdk/global-account/app";
|
|
2
|
+
import debug from "@b3dotfun/sdk/shared/utils/debug";
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { Account } from "thirdweb/wallets";
|
|
5
|
+
|
|
6
|
+
export function useSiwe() {
|
|
7
|
+
const authenticate = useCallback(async (account: Account, partnerId: string) => {
|
|
8
|
+
if (!account || !account.signMessage) throw new Error("Account not found");
|
|
9
|
+
// generate challenge
|
|
10
|
+
const challenge = await app.service("global-accounts-challenge").create({
|
|
11
|
+
address: account.address,
|
|
12
|
+
});
|
|
13
|
+
debug("@@useAuthenticate:challenge", challenge);
|
|
14
|
+
|
|
15
|
+
// sign challenge
|
|
16
|
+
const signature = await account.signMessage({
|
|
17
|
+
message: challenge.message,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
debug("@@useAuthenticate:signature", signature);
|
|
21
|
+
|
|
22
|
+
// authenticate
|
|
23
|
+
const response = await app.authenticate({
|
|
24
|
+
strategy: "smart-account-siwe",
|
|
25
|
+
message: challenge.message,
|
|
26
|
+
signature,
|
|
27
|
+
serverSignature: challenge.serverSignature,
|
|
28
|
+
nonce: challenge.nonce,
|
|
29
|
+
// http://localhost:5173/?referrerId=cd8fda06-3840-43d3-8f35-ae9472a13759
|
|
30
|
+
partnerId: partnerId,
|
|
31
|
+
});
|
|
32
|
+
debug("@@useAuthenticate:response", response);
|
|
33
|
+
|
|
34
|
+
return response;
|
|
35
|
+
}, []);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
authenticate,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -305,6 +305,23 @@ export interface LinkAccountModalProps extends BaseModalProps {
|
|
|
305
305
|
chain: Chain;
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
+
export interface AnySpendDepositHypeProps extends BaseModalProps {
|
|
309
|
+
/** Modal type identifier */
|
|
310
|
+
type: "anySpendDepositHype";
|
|
311
|
+
/** Recipient address to receive the tokens */
|
|
312
|
+
recipientAddress: string;
|
|
313
|
+
/** Destination token address */
|
|
314
|
+
sourceTokenAddress?: string;
|
|
315
|
+
/** Source token chain ID */
|
|
316
|
+
sourceTokenChainId?: number;
|
|
317
|
+
/** Payment type - crypto or fiat */
|
|
318
|
+
paymentType?: "crypto" | "fiat";
|
|
319
|
+
/** Deposit contract address */
|
|
320
|
+
depositContractAddress: string;
|
|
321
|
+
/** Callback function called when the deposit is successful */
|
|
322
|
+
onSuccess?: () => void;
|
|
323
|
+
}
|
|
324
|
+
|
|
308
325
|
/**
|
|
309
326
|
* Union type of all possible modal content types
|
|
310
327
|
*/
|
|
@@ -323,7 +340,8 @@ export type ModalContentType =
|
|
|
323
340
|
| AnySpendBuySpinProps
|
|
324
341
|
| AnySpendSignatureMintProps
|
|
325
342
|
| AnySpendBondKitProps
|
|
326
|
-
| LinkAccountModalProps
|
|
343
|
+
| LinkAccountModalProps
|
|
344
|
+
| AnySpendDepositHypeProps;
|
|
327
345
|
// Add other modal types here like: | OtherModalProps | AnotherModalProps
|
|
328
346
|
|
|
329
347
|
/**
|