@b3dotfun/sdk 0.0.40-alpha.2 → 0.0.40-alpha.20

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.
Files changed (166) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.d.ts +10 -1
  2. package/dist/cjs/anyspend/react/components/AnySpend.js +8 -4
  3. package/dist/cjs/anyspend/react/components/AnySpendBondKit.js +0 -1
  4. package/dist/cjs/anyspend/react/components/AnySpendBuySpin.js +0 -1
  5. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +5 -7
  6. package/dist/cjs/anyspend/react/components/AnySpendStakeB3.js +0 -1
  7. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.d.ts +8 -0
  8. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +6 -3
  9. package/dist/cjs/anyspend/react/components/AnyspendSignatureMint.js +0 -1
  10. package/dist/cjs/anyspend/react/components/common/ConnectWalletPayment.js +5 -3
  11. package/dist/cjs/anyspend/react/components/common/CryptoPaySection.d.ts +4 -1
  12. package/dist/cjs/anyspend/react/components/common/CryptoPaySection.js +9 -9
  13. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +80 -10
  14. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -1
  15. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +39 -37
  16. package/dist/cjs/anyspend/react/components/common/OrderDetails.js +8 -8
  17. package/dist/cjs/anyspend/react/components/common/OrderTokenAmount.d.ts +4 -1
  18. package/dist/cjs/anyspend/react/components/common/OrderTokenAmount.js +23 -9
  19. package/dist/cjs/anyspend/react/components/common/PanelOnramp.d.ts +4 -1
  20. package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +7 -6
  21. package/dist/cjs/anyspend/react/components/common/PointsDetailPanel.d.ts +6 -0
  22. package/dist/cjs/anyspend/react/components/common/PointsDetailPanel.js +14 -0
  23. package/dist/cjs/anyspend/react/contexts/FeatureFlagsContext.d.ts +11 -0
  24. package/dist/cjs/anyspend/react/contexts/FeatureFlagsContext.js +21 -0
  25. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
  26. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +1 -0
  27. package/dist/cjs/anyspend/react/providers/AnyspendProvider.d.ts +5 -2
  28. package/dist/cjs/anyspend/react/providers/AnyspendProvider.js +5 -3
  29. package/dist/cjs/anyspend/react/providers/index.d.ts +1 -0
  30. package/dist/cjs/anyspend/react/providers/index.js +3 -0
  31. package/dist/cjs/anyspend/types/api.d.ts +11 -1
  32. package/dist/cjs/anyspend/utils/orderPayload.js +1 -0
  33. package/dist/cjs/bondkit/bondkitToken.d.ts +37 -2
  34. package/dist/cjs/bondkit/bondkitToken.js +268 -2
  35. package/dist/cjs/bondkit/bondkitTokenFactory.d.ts +1 -1
  36. package/dist/cjs/bondkit/bondkitTokenFactory.js +2 -2
  37. package/dist/cjs/bondkit/config.d.ts +1 -1
  38. package/dist/cjs/bondkit/config.js +5 -2
  39. package/dist/cjs/bondkit/constants.d.ts +4 -0
  40. package/dist/cjs/bondkit/constants.js +6 -1
  41. package/dist/cjs/bondkit/index.d.ts +1 -0
  42. package/dist/cjs/bondkit/index.js +4 -1
  43. package/dist/cjs/bondkit/swapService.d.ts +43 -0
  44. package/dist/cjs/bondkit/swapService.js +373 -0
  45. package/dist/cjs/bondkit/types.d.ts +10 -4
  46. package/dist/cjs/bondkit/types.js +4 -5
  47. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.d.ts +4 -3
  48. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +35 -9
  49. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +63 -3
  50. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +35 -2
  51. package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStepCustom.js +4 -3
  52. package/dist/cjs/global-account/react/hooks/useAuthentication.js +1 -2
  53. package/dist/cjs/global-account/react/hooks/useSimBalance.js +2 -2
  54. package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +22 -20
  55. package/dist/esm/anyspend/react/components/AnySpend.d.ts +10 -1
  56. package/dist/esm/anyspend/react/components/AnySpend.js +8 -4
  57. package/dist/esm/anyspend/react/components/AnySpendBondKit.js +0 -1
  58. package/dist/esm/anyspend/react/components/AnySpendBuySpin.js +0 -1
  59. package/dist/esm/anyspend/react/components/AnySpendCustom.js +5 -7
  60. package/dist/esm/anyspend/react/components/AnySpendStakeB3.js +0 -1
  61. package/dist/esm/anyspend/react/components/AnyspendDepositHype.d.ts +8 -0
  62. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +6 -3
  63. package/dist/esm/anyspend/react/components/AnyspendSignatureMint.js +0 -1
  64. package/dist/esm/anyspend/react/components/common/ConnectWalletPayment.js +6 -4
  65. package/dist/esm/anyspend/react/components/common/CryptoPaySection.d.ts +4 -1
  66. package/dist/esm/anyspend/react/components/common/CryptoPaySection.js +9 -9
  67. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +80 -10
  68. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -1
  69. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +39 -37
  70. package/dist/esm/anyspend/react/components/common/OrderDetails.js +8 -8
  71. package/dist/esm/anyspend/react/components/common/OrderTokenAmount.d.ts +4 -1
  72. package/dist/esm/anyspend/react/components/common/OrderTokenAmount.js +23 -9
  73. package/dist/esm/anyspend/react/components/common/PanelOnramp.d.ts +4 -1
  74. package/dist/esm/anyspend/react/components/common/PanelOnramp.js +7 -6
  75. package/dist/esm/anyspend/react/components/common/PointsDetailPanel.d.ts +6 -0
  76. package/dist/esm/anyspend/react/components/common/PointsDetailPanel.js +8 -0
  77. package/dist/esm/anyspend/react/contexts/FeatureFlagsContext.d.ts +11 -0
  78. package/dist/esm/anyspend/react/contexts/FeatureFlagsContext.js +17 -0
  79. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
  80. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +1 -0
  81. package/dist/esm/anyspend/react/providers/AnyspendProvider.d.ts +5 -2
  82. package/dist/esm/anyspend/react/providers/AnyspendProvider.js +5 -3
  83. package/dist/esm/anyspend/react/providers/index.d.ts +1 -0
  84. package/dist/esm/anyspend/react/providers/index.js +1 -0
  85. package/dist/esm/anyspend/types/api.d.ts +11 -1
  86. package/dist/esm/anyspend/utils/orderPayload.js +1 -0
  87. package/dist/esm/bondkit/bondkitToken.d.ts +37 -2
  88. package/dist/esm/bondkit/bondkitToken.js +268 -2
  89. package/dist/esm/bondkit/bondkitTokenFactory.d.ts +1 -1
  90. package/dist/esm/bondkit/bondkitTokenFactory.js +2 -2
  91. package/dist/esm/bondkit/config.d.ts +1 -1
  92. package/dist/esm/bondkit/config.js +5 -2
  93. package/dist/esm/bondkit/constants.d.ts +4 -0
  94. package/dist/esm/bondkit/constants.js +5 -0
  95. package/dist/esm/bondkit/index.d.ts +1 -0
  96. package/dist/esm/bondkit/index.js +2 -0
  97. package/dist/esm/bondkit/swapService.d.ts +43 -0
  98. package/dist/esm/bondkit/swapService.js +369 -0
  99. package/dist/esm/bondkit/types.d.ts +10 -4
  100. package/dist/esm/bondkit/types.js +4 -5
  101. package/dist/esm/global-account/react/components/B3Provider/B3Provider.d.ts +4 -3
  102. package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +36 -9
  103. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +65 -5
  104. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +35 -2
  105. package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStepCustom.js +3 -2
  106. package/dist/esm/global-account/react/hooks/useAuthentication.js +1 -2
  107. package/dist/esm/global-account/react/hooks/useSimBalance.js +2 -2
  108. package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +22 -20
  109. package/dist/styles/index.css +1 -1
  110. package/dist/types/anyspend/react/components/AnySpend.d.ts +10 -1
  111. package/dist/types/anyspend/react/components/AnyspendDepositHype.d.ts +8 -0
  112. package/dist/types/anyspend/react/components/common/CryptoPaySection.d.ts +4 -1
  113. package/dist/types/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -1
  114. package/dist/types/anyspend/react/components/common/OrderTokenAmount.d.ts +4 -1
  115. package/dist/types/anyspend/react/components/common/PanelOnramp.d.ts +4 -1
  116. package/dist/types/anyspend/react/components/common/PointsDetailPanel.d.ts +6 -0
  117. package/dist/types/anyspend/react/contexts/FeatureFlagsContext.d.ts +11 -0
  118. package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
  119. package/dist/types/anyspend/react/providers/AnyspendProvider.d.ts +5 -2
  120. package/dist/types/anyspend/react/providers/index.d.ts +1 -0
  121. package/dist/types/anyspend/types/api.d.ts +11 -1
  122. package/dist/types/bondkit/bondkitToken.d.ts +37 -2
  123. package/dist/types/bondkit/bondkitTokenFactory.d.ts +1 -1
  124. package/dist/types/bondkit/config.d.ts +1 -1
  125. package/dist/types/bondkit/constants.d.ts +4 -0
  126. package/dist/types/bondkit/index.d.ts +1 -0
  127. package/dist/types/bondkit/swapService.d.ts +43 -0
  128. package/dist/types/bondkit/types.d.ts +10 -4
  129. package/dist/types/global-account/react/components/B3Provider/B3Provider.d.ts +4 -3
  130. package/package.json +6 -5
  131. package/src/anyspend/react/components/AnySpend.tsx +24 -1
  132. package/src/anyspend/react/components/AnySpendBondKit.tsx +0 -1
  133. package/src/anyspend/react/components/AnySpendBuySpin.tsx +0 -1
  134. package/src/anyspend/react/components/AnySpendCustom.tsx +5 -7
  135. package/src/anyspend/react/components/AnySpendStakeB3.tsx +0 -1
  136. package/src/anyspend/react/components/AnyspendDepositHype.tsx +22 -0
  137. package/src/anyspend/react/components/AnyspendSignatureMint.tsx +0 -1
  138. package/src/anyspend/react/components/common/ConnectWalletPayment.tsx +7 -4
  139. package/src/anyspend/react/components/common/CryptoPaySection.tsx +13 -8
  140. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +170 -44
  141. package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +63 -45
  142. package/src/anyspend/react/components/common/OrderDetails.tsx +8 -9
  143. package/src/anyspend/react/components/common/OrderTokenAmount.tsx +28 -8
  144. package/src/anyspend/react/components/common/PanelOnramp.tsx +28 -15
  145. package/src/anyspend/react/components/common/PointsDetailPanel.tsx +55 -0
  146. package/src/anyspend/react/contexts/FeatureFlagsContext.tsx +34 -0
  147. package/src/anyspend/react/hooks/useAnyspendFlow.ts +1 -0
  148. package/src/anyspend/react/providers/AnyspendProvider.tsx +11 -6
  149. package/src/anyspend/react/providers/index.ts +1 -0
  150. package/src/anyspend/types/api.ts +11 -1
  151. package/src/anyspend/types/api_req_res.ts +6 -10
  152. package/src/anyspend/utils/orderPayload.ts +1 -0
  153. package/src/bondkit/bondkitToken.ts +323 -3
  154. package/src/bondkit/bondkitTokenFactory.ts +2 -2
  155. package/src/bondkit/config.ts +5 -2
  156. package/src/bondkit/constants.ts +7 -0
  157. package/src/bondkit/index.ts +3 -0
  158. package/src/bondkit/swapService.ts +461 -0
  159. package/src/bondkit/types.ts +12 -5
  160. package/src/global-account/react/components/B3Provider/B3Provider.tsx +51 -15
  161. package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +106 -32
  162. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +60 -5
  163. package/src/global-account/react/components/SignInWithB3/steps/LoginStepCustom.tsx +4 -2
  164. package/src/global-account/react/hooks/useAuthentication.ts +1 -2
  165. package/src/global-account/react/hooks/useSimBalance.ts +2 -2
  166. package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +23 -21
@@ -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 { wallet: globalWallet, address: globalAddress } = useAccountWallet();
42
- const { address, isConnected, connector } = useAccount();
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),
@@ -161,57 +220,79 @@ export function CryptoPaymentMethod({
161
220
  </div>
162
221
 
163
222
  {/* Payment Methods */}
164
- <div className="crypto-payment-methods flex flex-col gap-6">
165
- {/* Connect Wallet Section */}
166
- <button
167
- onClick={() => {
168
- // Always show wallet selection modal first
169
- setShowWalletModal(true);
170
- }}
171
- 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"
172
- >
173
- <div className="flex items-center gap-3">
174
- <div className="wallet-icon flex h-8 w-8 items-center justify-center rounded-full bg-blue-100">
175
- <Wallet className="h-4 w-4 text-blue-600" />
176
- </div>
177
- <div className="flex flex-col items-start text-left">
178
- <h4 className="text-as-primary font-semibold">Connect wallet</h4>
179
- </div>
180
- </div>
181
- <ChevronRightCircle className="text-as-primary/40 group-hover:text-as-primary/60 h-5 w-5 transition-colors" />
182
- </button>
183
-
184
- {/* Transfer Crypto Section */}
185
- <button
186
- onClick={() => {
187
- setSelectedPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
188
- onSelectPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
189
- }}
190
- disabled={isCreatingOrder}
191
- 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"
192
- >
193
- <div className="flex items-center gap-3">
194
- <div className="wallet-icon flex h-8 w-8 items-center justify-center rounded-full bg-orange-100">
195
- <ZapIcon className="h-4 w-4" />
196
- </div>
197
- <div className="flex flex-col items-start text-left">
198
- <h4 className="text-as-primary font-semibold">Transfer crypto</h4>
199
- </div>
200
- </div>
201
- <ChevronRightCircle className="text-as-primary/40 group-hover:text-as-primary/60 h-5 w-5 transition-colors" />
202
- </button>
203
-
223
+ <div className="crypto-payment-methods flex flex-col gap-4">
204
224
  {/* Installed Wallets Section */}
205
- {(isConnected || globalAddress) && (
225
+ {(shouldShowConnectedEOA || shouldShowWagmiWallet || globalAddress) && (
206
226
  <div className="installed-wallets">
207
227
  <h3 className="text-as-primary/80 mb-3 text-sm font-medium">Connected wallets</h3>
208
228
  <div className="space-y-2">
209
229
  {/* Current Connected Wallet */}
210
- {isConnected && (
230
+
231
+ {shouldShowConnectedEOA && (
211
232
  <button
212
233
  onClick={() => {
213
234
  setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
214
235
  onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
236
+ setActiveWallet(connectedEOAWallet);
237
+ toast.success(`Selected ${eoaWalletInfo?.name || connector?.name || "wallet"}`);
238
+ }}
239
+ className={cn(
240
+ "crypto-payment-method-connect-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md",
241
+ selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
242
+ ? "connected-wallet border-as-brand bg-as-brand/5"
243
+ : "border-as-border-secondary bg-as-surface-primary hover:border-as-secondary/80",
244
+ )}
245
+ >
246
+ <div className="flex items-center justify-between">
247
+ <div className="flex items-center gap-3">
248
+ <div className="wallet-icon flex h-10 w-10 items-center justify-center rounded-full bg-blue-100">
249
+ <Wallet className="h-5 w-5 text-blue-600" />
250
+ </div>
251
+ <div className="flex flex-col">
252
+ <span className="text-as-primary font-semibold">
253
+ {eoaWalletInfo?.name || connector?.name || "Connected Wallet"}
254
+ </span>
255
+ <span className="text-as-primary/60 text-sm">
256
+ {shortenAddress(connectedEOAWallet?.getAccount()?.address || "")}
257
+ </span>
258
+ </div>
259
+ </div>
260
+ <div className="flex items-center gap-2">
261
+ {selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET && (
262
+ <div className="h-2 w-2 rounded-full bg-green-500"></div>
263
+ )}
264
+ <button
265
+ onClick={e => {
266
+ e.stopPropagation();
267
+ disconnect();
268
+ toast.success("Wallet disconnected");
269
+ if (selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET) {
270
+ setSelectedPaymentMethod(CryptoPaymentMethodType.NONE);
271
+ }
272
+ }}
273
+ className="text-as-primary/60 hover:text-as-primary/80 rounded-lg p-1.5 transition-colors"
274
+ >
275
+ <X className="h-4 w-4" />
276
+ </button>
277
+ </div>
278
+ </div>
279
+ </button>
280
+ )}
281
+
282
+ {shouldShowWagmiWallet && (
283
+ <button
284
+ onClick={async () => {
285
+ setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
286
+ onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
287
+
288
+ // Create thirdweb wallet from wagmi connector
289
+ if (connector?.name) {
290
+ const thirdwebWallet = await createThirdwebWalletFromConnector(connector.name);
291
+ if (thirdwebWallet) {
292
+ setActiveWallet(thirdwebWallet);
293
+ }
294
+ }
295
+
215
296
  toast.success(`Selected ${connector?.name || "wallet"}`);
216
297
  }}
217
298
  className={cn(
@@ -293,6 +374,51 @@ export function CryptoPaymentMethod({
293
374
  </div>
294
375
  </div>
295
376
  )}
377
+
378
+ {/* Other Payment Methods Section */}
379
+ <div className="other-payment-methods">
380
+ <h3 className="text-as-primary/80 mb-3 text-sm font-medium">Payment methods</h3>
381
+ <div className="space-y-3">
382
+ {/* Connect Wallet Section */}
383
+ <button
384
+ onClick={() => {
385
+ // Always show wallet selection modal first
386
+ setShowWalletModal(true);
387
+ }}
388
+ 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"
389
+ >
390
+ <div className="flex items-center gap-3">
391
+ <div className="wallet-icon flex h-8 w-8 items-center justify-center rounded-full bg-blue-100">
392
+ <Wallet className="h-4 w-4 text-blue-600" />
393
+ </div>
394
+ <div className="flex flex-col items-start text-left">
395
+ <h4 className="text-as-primary font-semibold">Connect wallet</h4>
396
+ </div>
397
+ </div>
398
+ <ChevronRightCircle className="text-as-primary/40 group-hover:text-as-primary/60 h-5 w-5 transition-colors" />
399
+ </button>
400
+
401
+ {/* Transfer Crypto Section */}
402
+ <button
403
+ onClick={() => {
404
+ setSelectedPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
405
+ onSelectPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
406
+ }}
407
+ disabled={isCreatingOrder}
408
+ 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"
409
+ >
410
+ <div className="flex items-center gap-3">
411
+ <div className="wallet-icon flex h-8 w-8 items-center justify-center rounded-full bg-orange-100">
412
+ <ZapIcon className="h-4 w-4" />
413
+ </div>
414
+ <div className="flex flex-col items-start text-left">
415
+ <h4 className="text-as-primary font-semibold">Transfer crypto</h4>
416
+ </div>
417
+ </div>
418
+ <ChevronRightCircle className="text-as-primary/40 group-hover:text-as-primary/60 h-5 w-5 transition-colors" />
419
+ </button>
420
+ </div>
421
+ </div>
296
422
  </div>
297
423
  </div>
298
424
 
@@ -5,6 +5,7 @@ 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 { components } from "../../../types/api";
8
+ import { useFeatureFlags } from "../../contexts/FeatureFlagsContext";
8
9
  import { OrderTokenAmount } from "./OrderTokenAmount";
9
10
 
10
11
  interface CryptoReceiveSectionProps {
@@ -27,6 +28,8 @@ interface CryptoReceiveSectionProps {
27
28
  // custom dst token data
28
29
  dstTokenSymbol?: string;
29
30
  dstTokenLogoURI?: string;
31
+ // Points navigation
32
+ onShowPointsDetail?: () => void;
30
33
  }
31
34
 
32
35
  export function CryptoReceiveSection({
@@ -44,7 +47,10 @@ export function CryptoReceiveSection({
44
47
  anyspendQuote,
45
48
  dstTokenSymbol,
46
49
  dstTokenLogoURI,
50
+ onShowPointsDetail,
47
51
  }: CryptoReceiveSectionProps) {
52
+ const featureFlags = useFeatureFlags();
53
+
48
54
  return (
49
55
  <motion.div
50
56
  initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
@@ -100,61 +106,73 @@ export function CryptoReceiveSection({
100
106
  setToken={setSelectedDstToken || (() => {})}
101
107
  />
102
108
  )}
103
- <div className="text-as-primary/50 flex h-5 items-center text-sm">
104
- {formatDisplayNumber(anyspendQuote?.data?.currencyOut?.amountUsd, {
105
- style: "currency",
106
- fallback: "",
107
- })}
108
- {anyspendQuote?.data?.currencyIn?.amountUsd &&
109
- anyspendQuote?.data?.currencyOut?.amountUsd &&
110
- (() => {
111
- const calculatePriceImpact = (inputUsd?: string | number, outputUsd?: string | number) => {
112
- if (!inputUsd || !outputUsd) {
113
- return { percentage: "0.00", isNegative: false };
114
- }
109
+ <div className="text-as-primary/50 flex h-5 items-center justify-start gap-2 text-sm">
110
+ <div className="flex items-center gap-2">
111
+ {formatDisplayNumber(anyspendQuote?.data?.currencyOut?.amountUsd, {
112
+ style: "currency",
113
+ fallback: "",
114
+ })}
115
+ {anyspendQuote?.data?.currencyIn?.amountUsd &&
116
+ anyspendQuote?.data?.currencyOut?.amountUsd &&
117
+ (() => {
118
+ const calculatePriceImpact = (inputUsd?: string | number, outputUsd?: string | number) => {
119
+ if (!inputUsd || !outputUsd) {
120
+ return { percentage: "0.00", isNegative: false };
121
+ }
115
122
 
116
- const input = Number(inputUsd);
117
- const output = Number(outputUsd);
123
+ const input = Number(inputUsd);
124
+ const output = Number(outputUsd);
118
125
 
119
- // Handle edge cases
120
- if (input === 0 || isNaN(input) || isNaN(output) || input <= output) {
121
- return { percentage: "0.00", isNegative: false };
122
- }
126
+ // Handle edge cases
127
+ if (input === 0 || isNaN(input) || isNaN(output) || input <= output) {
128
+ return { percentage: "0.00", isNegative: false };
129
+ }
123
130
 
124
- const percentageValue = ((output - input) / input) * 100;
131
+ const percentageValue = ((output - input) / input) * 100;
125
132
 
126
- // Handle the -0.00% case
127
- if (percentageValue > -0.005 && percentageValue < 0) {
128
- return { percentage: "0.00", isNegative: false };
129
- }
133
+ // Handle the -0.00% case
134
+ if (percentageValue > -0.005 && percentageValue < 0) {
135
+ return { percentage: "0.00", isNegative: false };
136
+ }
130
137
 
131
- return {
132
- percentage: Math.abs(percentageValue).toFixed(2),
133
- isNegative: percentageValue < 0,
138
+ return {
139
+ percentage: Math.abs(percentageValue).toFixed(2),
140
+ isNegative: percentageValue < 0,
141
+ };
134
142
  };
135
- };
136
143
 
137
- const { percentage, isNegative } = calculatePriceImpact(
138
- anyspendQuote.data.currencyIn.amountUsd,
139
- anyspendQuote.data.currencyOut.amountUsd,
140
- );
144
+ const { percentage, isNegative } = calculatePriceImpact(
145
+ anyspendQuote.data.currencyIn.amountUsd,
146
+ anyspendQuote.data.currencyOut.amountUsd,
147
+ );
141
148
 
142
- // Parse the percentage as a number for comparison
143
- const percentageNum = parseFloat(percentage);
149
+ // Parse the percentage as a number for comparison
150
+ const percentageNum = parseFloat(percentage);
144
151
 
145
- // Don't show if less than 1%
146
- if (percentageNum < 1) {
147
- return null;
148
- }
152
+ // Don't show if less than 1%
153
+ if (percentageNum < 1) {
154
+ return null;
155
+ }
149
156
 
150
- // Using inline style to ensure color displays
151
- return (
152
- <span className="ml-2" style={{ color: percentageNum >= 10 ? "red" : "#FFD700" }}>
153
- ({isNegative ? "-" : ""}
154
- {percentage}%)
155
- </span>
156
- );
157
- })()}
157
+ // Using inline style to ensure color displays
158
+ return (
159
+ <span className="ml-2" style={{ color: percentageNum >= 10 ? "red" : "#FFD700" }}>
160
+ ({isNegative ? "-" : ""}
161
+ {percentage}%)
162
+ </span>
163
+ );
164
+ })()}
165
+ </div>
166
+ {featureFlags.showPoints && anyspendQuote?.data?.pointsAmount && anyspendQuote.data.pointsAmount > 0 && (
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>
175
+ )}
158
176
  </div>
159
177
  </motion.div>
160
178
  );
@@ -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
- cryptoPaymentMethod || cryptoPaymentMethodFromUrl || CryptoPaymentMethodType.NONE;
227
-
228
- // Use selectedCryptoPaymentMethod for OrderStatus if provided, otherwise fall back to effective method
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={orderStatusPaymentMethod} />
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={orderStatusPaymentMethod} />
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={orderStatusPaymentMethod} />
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={orderStatusPaymentMethod} />
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={orderStatusPaymentMethod} />
1010
+ <OrderStatus order={order} selectedCryptoPaymentMethod={effectiveCryptoPaymentMethod} />
1012
1011
  {statusDisplay === "processing" && (
1013
1012
  <>
1014
1013
  {order.onrampMetadata ? (
@@ -27,6 +27,7 @@ export function OrderTokenAmount({
27
27
  innerClassName,
28
28
  amountClassName,
29
29
  tokenSelectClassName,
30
+ onTokenSelect,
30
31
  }: {
31
32
  disabled?: boolean;
32
33
  inputValue: string;
@@ -43,6 +44,7 @@ export function OrderTokenAmount({
43
44
  innerClassName?: string;
44
45
  amountClassName?: string;
45
46
  tokenSelectClassName?: string;
47
+ onTokenSelect?: (token: components["schemas"]["Token"], event: { preventDefault: () => void }) => void;
46
48
  }) {
47
49
  // Track previous token to detect changes
48
50
  const prevTokenRef = useRef<string>(token.address);
@@ -64,6 +66,31 @@ export function OrderTokenAmount({
64
66
  }, [token.address, chainId, context, onChangeInput]);
65
67
 
66
68
  const handleTokenSelect = (newToken: any) => {
69
+ const token: components["schemas"]["Token"] = {
70
+ address: newToken.address,
71
+ chainId: newToken.chainId,
72
+ decimals: newToken.decimals,
73
+ metadata: { logoURI: newToken.logoURI },
74
+ name: newToken.name,
75
+ symbol: newToken.symbol,
76
+ };
77
+
78
+ // Call the onTokenSelect callback if provided
79
+ if (onTokenSelect) {
80
+ let isDefaultPrevented = false;
81
+ const event = {
82
+ preventDefault: () => {
83
+ isDefaultPrevented = true;
84
+ },
85
+ };
86
+
87
+ onTokenSelect(token, event);
88
+
89
+ if (isDefaultPrevented) {
90
+ return; // Early return if callback prevented default behavior
91
+ }
92
+ }
93
+
67
94
  // Mark that we're about to change tokens
68
95
  prevTokenRef.current = "changing"; // Temporary value to force effect
69
96
 
@@ -71,14 +98,7 @@ export function OrderTokenAmount({
71
98
  setChainId(newToken.chainId);
72
99
 
73
100
  // Then set the new token
74
- setToken({
75
- address: newToken.address,
76
- chainId: newToken.chainId, // Use the new chain ID
77
- decimals: newToken.decimals,
78
- metadata: { logoURI: newToken.logoURI },
79
- name: newToken.name,
80
- symbol: newToken.symbol,
81
- });
101
+ setToken(token);
82
102
 
83
103
  // If this is the source token, reset the amount immediately
84
104
  if (context === "from") {
@@ -1,5 +1,6 @@
1
1
  import { useCoinbaseOnrampOptions, useGeoOnrampOptions } from "@b3dotfun/sdk/anyspend/react";
2
2
  import { components } from "@b3dotfun/sdk/anyspend/types/api";
3
+ import { GetQuoteResponse } from "@b3dotfun/sdk/anyspend/types/api_req_res";
3
4
  import { ALL_CHAINS } from "@b3dotfun/sdk/anyspend/utils/chain";
4
5
  import { Input, useGetGeo, useProfile } from "@b3dotfun/sdk/global-account/react";
5
6
  import { cn, formatUsername } from "@b3dotfun/sdk/shared/utils";
@@ -7,6 +8,7 @@ import { formatAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
7
8
  import { ChevronRight, Wallet } from "lucide-react";
8
9
  import { useRef } from "react";
9
10
  import { toast } from "sonner";
11
+ import { useFeatureFlags } from "../../contexts/FeatureFlagsContext";
10
12
  import { FiatPaymentMethod } from "./FiatPaymentMethod";
11
13
  import { OrderTokenAmountFiat } from "./OrderTokenAmountFiat";
12
14
 
@@ -25,6 +27,8 @@ export function PanelOnramp({
25
27
  recipientSelectionPanelIndex,
26
28
  dstTokenSymbol,
27
29
  hideDstToken = false,
30
+ anyspendQuote,
31
+ onShowPointsDetail,
28
32
  }: {
29
33
  srcAmountOnRamp: string;
30
34
  setSrcAmountOnRamp: (amount: string) => void;
@@ -40,7 +44,10 @@ export function PanelOnramp({
40
44
  recipientSelectionPanelIndex: number;
41
45
  dstTokenSymbol?: string;
42
46
  hideDstToken?: boolean;
47
+ anyspendQuote?: GetQuoteResponse;
48
+ onShowPointsDetail?: () => void;
43
49
  }) {
50
+ const featureFlags = useFeatureFlags();
44
51
  // Get geo-based onramp options to access fee information
45
52
  const { stripeWeb2Support } = useGeoOnrampOptions(srcAmountOnRamp);
46
53
 
@@ -245,21 +252,27 @@ export function PanelOnramp({
245
252
 
246
253
  <div className="">
247
254
  <div className="flex items-center justify-between">
248
- {(() => {
249
- const currentPaymentMethod = selectedPaymentMethod || FiatPaymentMethod.NONE;
250
- const fee = getFeeFromApi(currentPaymentMethod);
251
-
252
- return (
253
- <>
254
- <span className="text-as-tertiarry text-sm">
255
- {fee !== null ? `Total (included $${fee.toFixed(2)} fee)` : "Total"}
256
- </span>
257
- <span className="text-as-primary font-semibold">
258
- ${getTotalAmount(currentPaymentMethod).toFixed(2)}
259
- </span>
260
- </>
261
- );
262
- })()}
255
+ <div className="flex items-center gap-2">
256
+ <span className="text-as-tertiarry text-sm">
257
+ {(() => {
258
+ const fee = getFeeFromApi(selectedPaymentMethod || FiatPaymentMethod.NONE);
259
+ return fee !== null ? `Total (included $${fee.toFixed(2)} fee)` : "Total";
260
+ })()}
261
+ </span>
262
+ {featureFlags.showPoints && anyspendQuote?.data?.pointsAmount && anyspendQuote.data.pointsAmount > 0 && (
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>
271
+ )}
272
+ </div>
273
+ <span className="text-as-primary font-semibold">
274
+ ${getTotalAmount(selectedPaymentMethod || FiatPaymentMethod.NONE).toFixed(2)}
275
+ </span>
263
276
  </div>
264
277
  </div>
265
278
  </div>
@@ -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
+ }