@b3dotfun/sdk 0.0.41 → 0.0.42-alpha.1

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 (116) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.d.ts +1 -0
  2. package/dist/cjs/anyspend/react/components/AnySpend.js +18 -2
  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.d.ts +1 -0
  6. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +76 -14
  7. package/dist/cjs/anyspend/react/components/AnySpendNFT.d.ts +2 -1
  8. package/dist/cjs/anyspend/react/components/AnySpendNFT.js +2 -2
  9. package/dist/cjs/anyspend/react/components/AnySpendStakeB3.js +0 -1
  10. package/dist/cjs/anyspend/react/components/AnyspendSignatureMint.js +1 -2
  11. package/dist/cjs/anyspend/react/components/common/CryptoPaySection.js +1 -1
  12. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +2 -1
  13. package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +4 -1
  14. package/dist/cjs/anyspend/react/components/common/PointsBadge.d.ts +7 -0
  15. package/dist/cjs/anyspend/react/components/common/PointsBadge.js +7 -0
  16. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +5 -3
  17. package/dist/cjs/anyspend/services/anyspend.d.ts +1 -1
  18. package/dist/cjs/anyspend/services/anyspend.js +2 -0
  19. package/dist/cjs/anyspend/types/api.d.ts +41 -1
  20. package/dist/cjs/anyspend/utils/orderPayload.js +3 -0
  21. package/dist/cjs/bondkit/components/TradingView.js +3 -4
  22. package/dist/cjs/bondkit/swapService.js +3 -0
  23. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +19 -13
  24. package/dist/cjs/global-account/react/hooks/index.d.ts +1 -0
  25. package/dist/cjs/global-account/react/hooks/index.js +3 -1
  26. package/dist/cjs/global-account/react/hooks/useAccountAssets.js +5 -2
  27. package/dist/cjs/global-account/react/hooks/useAuthentication.js +1 -1
  28. package/dist/cjs/global-account/react/hooks/useGlobalAccount.d.ts +6 -0
  29. package/dist/cjs/global-account/react/hooks/useGlobalAccount.js +32 -0
  30. package/dist/cjs/global-account/react/hooks/useQueryB3.js +5 -2
  31. package/dist/cjs/global-account/react/hooks/useQueryBSMNT.js +5 -2
  32. package/dist/cjs/global-account/react/hooks/useTokenBalancesByChain.js +7 -1
  33. package/dist/cjs/global-account/react/hooks/useTokenFromUrl.js +2 -2
  34. package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +1 -2
  35. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +1 -1
  36. package/dist/cjs/shared/utils/fetchBalances.d.ts +1 -1
  37. package/dist/esm/anyspend/react/components/AnySpend.d.ts +1 -0
  38. package/dist/esm/anyspend/react/components/AnySpend.js +18 -2
  39. package/dist/esm/anyspend/react/components/AnySpendBondKit.js +0 -1
  40. package/dist/esm/anyspend/react/components/AnySpendBuySpin.js +0 -1
  41. package/dist/esm/anyspend/react/components/AnySpendCustom.d.ts +1 -0
  42. package/dist/esm/anyspend/react/components/AnySpendCustom.js +43 -14
  43. package/dist/esm/anyspend/react/components/AnySpendNFT.d.ts +2 -1
  44. package/dist/esm/anyspend/react/components/AnySpendNFT.js +2 -2
  45. package/dist/esm/anyspend/react/components/AnySpendStakeB3.js +0 -1
  46. package/dist/esm/anyspend/react/components/AnyspendSignatureMint.js +1 -2
  47. package/dist/esm/anyspend/react/components/common/CryptoPaySection.js +1 -1
  48. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +2 -1
  49. package/dist/esm/anyspend/react/components/common/PanelOnramp.js +4 -1
  50. package/dist/esm/anyspend/react/components/common/PointsBadge.d.ts +7 -0
  51. package/dist/esm/anyspend/react/components/common/PointsBadge.js +4 -0
  52. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +5 -3
  53. package/dist/esm/anyspend/services/anyspend.d.ts +1 -1
  54. package/dist/esm/anyspend/services/anyspend.js +2 -0
  55. package/dist/esm/anyspend/types/api.d.ts +41 -1
  56. package/dist/esm/anyspend/utils/orderPayload.js +3 -0
  57. package/dist/esm/bondkit/components/TradingView.js +3 -4
  58. package/dist/esm/bondkit/swapService.js +5 -2
  59. package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +19 -13
  60. package/dist/esm/global-account/react/hooks/index.d.ts +1 -0
  61. package/dist/esm/global-account/react/hooks/index.js +1 -0
  62. package/dist/esm/global-account/react/hooks/useAccountAssets.js +2 -2
  63. package/dist/esm/global-account/react/hooks/useAuthentication.js +1 -1
  64. package/dist/esm/global-account/react/hooks/useGlobalAccount.d.ts +6 -0
  65. package/dist/esm/global-account/react/hooks/useGlobalAccount.js +29 -0
  66. package/dist/esm/global-account/react/hooks/useQueryB3.js +5 -2
  67. package/dist/esm/global-account/react/hooks/useQueryBSMNT.js +5 -2
  68. package/dist/esm/global-account/react/hooks/useTokenBalancesByChain.js +4 -1
  69. package/dist/esm/global-account/react/hooks/useTokenFromUrl.js +2 -2
  70. package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +2 -3
  71. package/dist/esm/global-account/react/stores/useModalStore.d.ts +1 -1
  72. package/dist/esm/shared/utils/fetchBalances.d.ts +1 -1
  73. package/dist/styles/index.css +1 -1
  74. package/dist/types/anyspend/react/components/AnySpend.d.ts +1 -0
  75. package/dist/types/anyspend/react/components/AnySpendCustom.d.ts +1 -0
  76. package/dist/types/anyspend/react/components/AnySpendNFT.d.ts +2 -1
  77. package/dist/types/anyspend/react/components/common/PointsBadge.d.ts +7 -0
  78. package/dist/types/anyspend/services/anyspend.d.ts +1 -1
  79. package/dist/types/anyspend/types/api.d.ts +41 -1
  80. package/dist/types/global-account/react/hooks/index.d.ts +1 -0
  81. package/dist/types/global-account/react/hooks/useGlobalAccount.d.ts +6 -0
  82. package/dist/types/global-account/react/stores/useModalStore.d.ts +1 -1
  83. package/dist/types/shared/utils/fetchBalances.d.ts +1 -1
  84. package/package.json +22 -23
  85. package/src/anyspend/react/components/AnySpend.tsx +23 -1
  86. package/src/anyspend/react/components/AnySpendBondKit.tsx +0 -1
  87. package/src/anyspend/react/components/AnySpendBuySpin.tsx +0 -1
  88. package/src/anyspend/react/components/AnySpendCustom.tsx +74 -15
  89. package/src/anyspend/react/components/AnySpendNFT.tsx +3 -0
  90. package/src/anyspend/react/components/AnySpendStakeB3.tsx +0 -1
  91. package/src/anyspend/react/components/AnyspendSignatureMint.tsx +1 -2
  92. package/src/anyspend/react/components/common/CryptoPaySection.tsx +1 -1
  93. package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +6 -8
  94. package/src/anyspend/react/components/common/PanelOnramp.tsx +10 -10
  95. package/src/anyspend/react/components/common/PointsBadge.tsx +20 -0
  96. package/src/anyspend/react/hooks/useAnyspendFlow.ts +5 -3
  97. package/src/anyspend/react/hooks/useAnyspendOrderAndTransactions.ts +1 -1
  98. package/src/anyspend/react/hooks/useCoinbaseOnrampOptions.ts +1 -1
  99. package/src/anyspend/services/anyspend.ts +3 -1
  100. package/src/anyspend/types/api.ts +41 -1
  101. package/src/anyspend/utils/orderPayload.ts +3 -0
  102. package/src/bondkit/components/TradingView.tsx +3 -5
  103. package/src/bondkit/swapService.ts +10 -7
  104. package/src/global-account/react/components/B3Provider/B3Provider.tsx +21 -17
  105. package/src/global-account/react/hooks/index.ts +1 -0
  106. package/src/global-account/react/hooks/useAccountAssets.ts +4 -3
  107. package/src/global-account/react/hooks/useAuthentication.ts +1 -1
  108. package/src/global-account/react/hooks/useGlobalAccount.tsx +36 -0
  109. package/src/global-account/react/hooks/useOneBalance.tsx +1 -1
  110. package/src/global-account/react/hooks/useQueryB3.ts +22 -15
  111. package/src/global-account/react/hooks/useQueryBSMNT.ts +22 -15
  112. package/src/global-account/react/hooks/useTokenBalancesByChain.tsx +4 -1
  113. package/src/global-account/react/hooks/useTokenFromUrl.tsx +2 -2
  114. package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +2 -3
  115. package/src/global-account/react/stores/useModalStore.ts +1 -1
  116. package/src/shared/utils/fetchBalances.ts +1 -1
@@ -7,6 +7,7 @@ import { motion } from "motion/react";
7
7
  import { components } from "../../../types/api";
8
8
  import { useFeatureFlags } from "../../contexts/FeatureFlagsContext";
9
9
  import { OrderTokenAmount } from "./OrderTokenAmount";
10
+ import { PointsBadge } from "./PointsBadge";
10
11
 
11
12
  interface CryptoReceiveSectionProps {
12
13
  isDepositMode?: boolean;
@@ -163,15 +164,12 @@ export function CryptoReceiveSection({
163
164
  );
164
165
  })()}
165
166
  </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"
167
+ {featureFlags.showPoints && anyspendQuote?.data?.pointsAmount > 0 && (
168
+ <PointsBadge
169
+ pointsAmount={anyspendQuote.data.pointsAmount}
170
+ pointsMultiplier={anyspendQuote.data.pointsMultiplier}
170
171
  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>
172
+ />
175
173
  )}
176
174
  </div>
177
175
  </motion.div>
@@ -11,6 +11,7 @@ import { toast } from "sonner";
11
11
  import { useFeatureFlags } from "../../contexts/FeatureFlagsContext";
12
12
  import { FiatPaymentMethod } from "./FiatPaymentMethod";
13
13
  import { OrderTokenAmountFiat } from "./OrderTokenAmountFiat";
14
+ import { PointsBadge } from "./PointsBadge";
14
15
 
15
16
  export function PanelOnramp({
16
17
  srcAmountOnRamp,
@@ -259,16 +260,15 @@ export function PanelOnramp({
259
260
  return fee !== null ? `Total (included $${fee.toFixed(2)} fee)` : "Total";
260
261
  })()}
261
262
  </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
- )}
263
+ {featureFlags.showPoints &&
264
+ anyspendQuote?.data?.pointsAmount &&
265
+ anyspendQuote?.data?.pointsAmount > 0 && (
266
+ <PointsBadge
267
+ pointsAmount={anyspendQuote.data.pointsAmount}
268
+ pointsMultiplier={anyspendQuote.data.pointsMultiplier}
269
+ onClick={() => onShowPointsDetail?.()}
270
+ />
271
+ )}
272
272
  </div>
273
273
  <span className="text-as-primary font-semibold">
274
274
  ${getTotalAmount(selectedPaymentMethod || FiatPaymentMethod.NONE).toFixed(2)}
@@ -0,0 +1,20 @@
1
+ interface PointsBadgeProps {
2
+ pointsAmount: number;
3
+ pointsMultiplier?: number;
4
+ onClick?: () => void;
5
+ }
6
+
7
+ export function PointsBadge({ pointsAmount, pointsMultiplier, onClick }: PointsBadgeProps) {
8
+ return (
9
+ <button
10
+ 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"
11
+ onClick={onClick}
12
+ >
13
+ <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" />
14
+ <span className="relative text-xs text-white">
15
+ +{pointsAmount.toLocaleString()} pts
16
+ {pointsMultiplier && pointsMultiplier > 1 && <span className="ml-1 opacity-80">({pointsMultiplier}x)</span>}
17
+ </span>
18
+ </button>
19
+ );
20
+ }
@@ -157,15 +157,17 @@ export function useAnyspendFlow({
157
157
  };
158
158
 
159
159
  // Get quote
160
- const activeInputAmountInWei = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals).toString();
160
+ // For fiat payments, always use USDC decimals (6) regardless of selectedSrcToken
161
+ const effectiveDecimals = paymentType === "fiat" ? USDC_BASE.decimals : selectedSrcToken.decimals;
162
+ const activeInputAmountInWei = parseUnits(srcAmount.replace(/,/g, ""), effectiveDecimals).toString();
161
163
  const { anyspendQuote, isLoadingAnyspendQuote, getAnyspendQuoteError } = useAnyspendQuote({
162
164
  srcChain: paymentType === "fiat" ? base.id : selectedSrcChainId,
163
165
  dstChain: isDepositMode ? base.id : selectedDstChainId, // For deposits, always Base; for swaps, use selected destination
164
166
  srcTokenAddress: paymentType === "fiat" ? USDC_BASE.address : selectedSrcToken.address,
165
167
  dstTokenAddress: isDepositMode ? B3_TOKEN.address : selectedSrcToken.address, // For deposits, always B3
166
- type: "swap",
167
- tradeType: "EXACT_INPUT",
168
+ type: "hype_duel",
168
169
  amount: activeInputAmountInWei,
170
+ recipientAddress: selectedRecipientAddress,
169
171
  onrampVendor: paymentType === "fiat" ? getOnrampVendor(selectedFiatPaymentMethod) : undefined,
170
172
  });
171
173
 
@@ -35,7 +35,7 @@ export function useAnyspendOrderAndTransactions(orderId: string | undefined) {
35
35
 
36
36
  const { data, isLoading, refetch, error } = useQuery<GetOrderAndTxsResponse>({
37
37
  queryKey: ["getAnyspendOrderAndTransactions", orderId],
38
- queryFn: () => anyspendService.getOrderAndTransactions(orderId!),
38
+ queryFn: () => anyspendService.getOrderAndTransactions(orderId),
39
39
  enabled: !!orderId,
40
40
  refetchInterval: 3000,
41
41
  staleTime: 1000,
@@ -6,7 +6,7 @@ import { useMemo } from "react";
6
6
  export function useCoinbaseOnrampOptions(country?: string, visitorData?: VisitorData, isLoadingVisitorData?: boolean) {
7
7
  const { data, isLoading, error, refetch } = useQuery({
8
8
  queryKey: ["getCoinbaseOnrampOptions", country, visitorData],
9
- queryFn: () => anyspendService.getCoinbaseOnrampOptions(country!, visitorData),
9
+ queryFn: () => anyspendService.getCoinbaseOnrampOptions(country, visitorData),
10
10
  enabled: Boolean(country) && !isLoadingVisitorData,
11
11
  });
12
12
 
@@ -111,6 +111,7 @@ export const anyspendService = {
111
111
  },
112
112
 
113
113
  getOrderAndTransactions: async (orderId: string | undefined): Promise<GetOrderAndTxsResponse> => {
114
+ invariant(orderId, "orderId is required");
114
115
  const response = await fetch(`${ANYSPEND_MAINNET_BASE_URL}/orders/${orderId}`);
115
116
  const data: GetOrderAndTxsResponse = await response.json();
116
117
  return data;
@@ -134,9 +135,10 @@ export const anyspendService = {
134
135
  },
135
136
 
136
137
  getCoinbaseOnrampOptions: async (
137
- country: string,
138
+ country: string | undefined,
138
139
  visitorData?: VisitorData,
139
140
  ): Promise<GetCoinbaseOnrampOptionsResponse> => {
141
+ invariant(country, "country is required");
140
142
  const params = new URLSearchParams({
141
143
  country,
142
144
  // include fingerprintId and requestId in the query params
@@ -505,11 +505,16 @@ export interface paths {
505
505
  * @example 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
506
506
  */
507
507
  dstTokenAddress: string;
508
+ /**
509
+ * @description Recipient address
510
+ * @example 0x55c71fca5e01cf246718748ae540473e608d0282
511
+ */
512
+ recipientAddress?: string;
508
513
  /**
509
514
  * @description Type of trade execution
510
515
  * @enum {string}
511
516
  */
512
- tradeType: "EXACT_INPUT" | "EXPECTED_OUTPUT" | "EXACT_OUTPUT";
517
+ tradeType: "EXACT_INPUT" | "EXACT_OUTPUT";
513
518
  /**
514
519
  * @description Amount to quote
515
520
  * @example 1000000000000000000
@@ -547,6 +552,11 @@ export interface paths {
547
552
  * @example 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
548
553
  */
549
554
  dstTokenAddress: string;
555
+ /**
556
+ * @description Recipient address
557
+ * @example 0x55c71fca5e01cf246718748ae540473e608d0282
558
+ */
559
+ recipientAddress?: string;
550
560
  /** @description Custom payload for execution */
551
561
  payload: {
552
562
  /** @description Encoded transaction data */
@@ -571,6 +581,11 @@ export interface paths {
571
581
  dstChain: number;
572
582
  srcTokenAddress: string;
573
583
  dstTokenAddress: string;
584
+ /**
585
+ * @description Recipient address
586
+ * @example 0x55c71fca5e01cf246718748ae540473e608d0282
587
+ */
588
+ recipientAddress?: string;
574
589
  /** @enum {string} */
575
590
  onrampVendor?: "coinbase" | "stripe" | "stripe-web2";
576
591
  contractAddress: string;
@@ -586,6 +601,11 @@ export interface paths {
586
601
  dstChain: number;
587
602
  srcTokenAddress: string;
588
603
  dstTokenAddress: string;
604
+ /**
605
+ * @description Recipient address
606
+ * @example 0x55c71fca5e01cf246718748ae540473e608d0282
607
+ */
608
+ recipientAddress?: string;
589
609
  /** @enum {string} */
590
610
  onrampVendor?: "coinbase" | "stripe" | "stripe-web2";
591
611
  contractAddress: string;
@@ -598,6 +618,11 @@ export interface paths {
598
618
  dstChain: number;
599
619
  srcTokenAddress: string;
600
620
  dstTokenAddress: string;
621
+ /**
622
+ * @description Recipient address
623
+ * @example 0x55c71fca5e01cf246718748ae540473e608d0282
624
+ */
625
+ recipientAddress?: string;
601
626
  /** @enum {string} */
602
627
  onrampVendor?: "coinbase" | "stripe" | "stripe-web2";
603
628
  contractAddress: string;
@@ -629,6 +654,11 @@ export interface paths {
629
654
  * @example 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
630
655
  */
631
656
  dstTokenAddress: string;
657
+ /**
658
+ * @description Recipient address
659
+ * @example 0x55c71fca5e01cf246718748ae540473e608d0282
660
+ */
661
+ recipientAddress?: string;
632
662
  /**
633
663
  * @description Amount to quote
634
664
  * @example 1000000000000000000
@@ -1094,6 +1124,11 @@ export interface components {
1094
1124
  * @example 990000
1095
1125
  */
1096
1126
  actualDstAmount: string | null;
1127
+ /**
1128
+ * @description Amount in after fee
1129
+ * @example 990000
1130
+ */
1131
+ amountInAfterFee: string | null;
1097
1132
  };
1098
1133
  /** @description HypeDuel-specific payload */
1099
1134
  HypeDuelPayload: {
@@ -1107,6 +1142,11 @@ export interface components {
1107
1142
  * @example 990000
1108
1143
  */
1109
1144
  actualDstAmount: string | null;
1145
+ /**
1146
+ * @description Amount in after fee
1147
+ * @example 990000
1148
+ */
1149
+ amountInAfterFee: string | null;
1110
1150
  };
1111
1151
  /** @description Custom execution payload */
1112
1152
  CustomPayload: {
@@ -18,6 +18,7 @@ export const buildPayload = (orderType: components["schemas"]["Order"]["type"],
18
18
  return {
19
19
  expectedDstAmount,
20
20
  actualDstAmount: null,
21
+ amountInAfterFee: null,
21
22
  };
22
23
  case "mint_nft":
23
24
  if (nft?.type === "erc1155") {
@@ -31,6 +32,7 @@ export const buildPayload = (orderType: components["schemas"]["Order"]["type"],
31
32
  return {
32
33
  contractAddress: normalizeAddress(nft.contractAddress),
33
34
  nftPrice: nft?.price || "",
35
+ tokenId: null,
34
36
  contractType: nft?.type,
35
37
  };
36
38
  } else {
@@ -52,6 +54,7 @@ export const buildPayload = (orderType: components["schemas"]["Order"]["type"],
52
54
  return {
53
55
  expectedDstAmount,
54
56
  actualDstAmount: null,
57
+ amountInAfterFee: null,
55
58
  };
56
59
  default:
57
60
  throw new Error(`Invalid order type: ${orderType}`);
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
 
3
- import { loadScriptFromCDN } from "./utils/cdn-loader";
4
- import { formatNumberSmall } from "./utils/format";
5
3
  import { Loader2 } from "lucide-react";
6
4
  import { useEffect, useRef, useState } from "react";
7
5
  import { TradingViewProps } from "./types";
6
+ import { loadScriptFromCDN } from "./utils/cdn-loader";
7
+ import { formatNumberSmall } from "./utils/format";
8
8
 
9
9
  // TypeScript types - these will be loaded from CDN at runtime
10
10
  type ChartingLibraryWidgetOptions = any;
@@ -24,8 +24,6 @@ const GifLoadingOverlay = ({ className }: { className?: string }) => (
24
24
  );
25
25
 
26
26
  const TradingView = ({ className, tokenAddress, tokenSymbol }: TradingViewProps) => {
27
- const theme = "light";
28
-
29
27
  // Use token info for the current trade
30
28
  const currentTrade = {
31
29
  product_id: tokenAddress && tokenSymbol ? `${tokenSymbol}-${tokenAddress}` : "BONDKIT",
@@ -282,7 +280,7 @@ const TradingView = ({ className, tokenAddress, tokenSymbol }: TradingViewProps)
282
280
  tvWidgetRef.current = null;
283
281
  }
284
282
  };
285
- }, [theme, librariesLoaded]);
283
+ }, [librariesLoaded, currentTrade?.product_id, tradingViewDefaultInterval, tradingViewTimezone]);
286
284
 
287
285
  useEffect(() => {
288
286
  if (
@@ -1,15 +1,15 @@
1
- import type { Address, Hex, WalletClient, PublicClient } from "viem";
1
+ import type { Address, Hex, PublicClient, WalletClient } from "viem";
2
2
  import {
3
- parseUnits,
4
- formatUnits,
3
+ createPublicClient,
5
4
  encodeAbiParameters,
6
- parseAbiParameters,
5
+ formatUnits,
7
6
  getContract,
8
- createPublicClient,
9
7
  http,
8
+ parseAbiParameters,
9
+ parseUnits,
10
10
  } from "viem";
11
11
  import { base } from "viem/chains";
12
- import { UniversalRouterAddress, QuoterAddress, Permit2Address, BaseMainnetRpcUrl } from "./constants";
12
+ import { BaseMainnetRpcUrl, Permit2Address, QuoterAddress, UniversalRouterAddress } from "./constants";
13
13
  import type { SwapQuote } from "./types";
14
14
 
15
15
  // Minimal ABIs needed for swap functionality
@@ -230,7 +230,10 @@ export class BondkitSwapService {
230
230
  */
231
231
  private async getV4Config(): Promise<V4PoolConfig> {
232
232
  await this.initializeV4Config();
233
- return this.v4Config!;
233
+ if (!this.v4Config) {
234
+ throw new Error("Failed to initialize V4 configuration");
235
+ }
236
+ return this.v4Config;
234
237
  }
235
238
 
236
239
  /**
@@ -88,30 +88,34 @@ export function B3Provider({
88
88
  };
89
89
  }, [partnerId]);
90
90
 
91
+ // Stringify rpcUrls for stable comparison to prevent wagmiConfig recreation
92
+ // when parent component passes new object references with same content
93
+ const rpcUrlsString = useMemo(() => (rpcUrls ? JSON.stringify(rpcUrls) : undefined), [rpcUrls]);
94
+
91
95
  /**
92
96
  * Creates wagmi config with optional custom RPC URLs
93
97
  * @param rpcUrls - Optional mapping of chain IDs to RPC URLs
94
98
  */
95
- const wagmiConfig = useMemo(
96
- () =>
97
- createConfig({
98
- chains: [supportedChains[0], ...supportedChains.slice(1)],
99
- transports: Object.fromEntries(supportedChains.map(chain => [chain.id, http(rpcUrls?.[chain.id])])) as any,
100
- connectors: [
101
- inAppWalletConnector({
102
- ...(ecocystemConfig || {}),
103
- client,
104
- }),
105
- // injected(),
106
- // coinbaseWallet({ appName: "HypeDuel" }),
107
- ],
108
- }),
109
- [partnerId],
110
- );
99
+ const wagmiConfig = useMemo(() => {
100
+ const parsedRpcUrls = rpcUrlsString ? JSON.parse(rpcUrlsString) : undefined;
101
+
102
+ return createConfig({
103
+ chains: [supportedChains[0], ...supportedChains.slice(1)],
104
+ transports: Object.fromEntries(supportedChains.map(chain => [chain.id, http(parsedRpcUrls?.[chain.id])])),
105
+ connectors: [
106
+ inAppWalletConnector({
107
+ ...(ecocystemConfig || {}),
108
+ client,
109
+ }),
110
+ // injected(),
111
+ // coinbaseWallet({ appName: "HypeDuel" }),
112
+ ],
113
+ });
114
+ }, [ecocystemConfig, rpcUrlsString]);
111
115
 
112
116
  return (
113
117
  <ThirdwebProvider>
114
- <WagmiProvider config={wagmiConfig} reconnectOnMount={false}>
118
+ <WagmiProvider config={wagmiConfig}>
115
119
  <QueryClientProvider client={queryClient}>
116
120
  <TooltipProvider>
117
121
  <InnerProvider
@@ -14,6 +14,7 @@ export { useExchangeRate } from "./useExchangeRate";
14
14
  export { useFirstEOA } from "./useFirstEOA";
15
15
  export { useGetAllTWSigners, type TWSignerWithMetadata } from "./useGetAllTWSigners";
16
16
  export { useGetGeo } from "./useGetGeo";
17
+ export { useGlobalAccount } from "./useGlobalAccount";
17
18
  export { useHandleConnectWithPrivy } from "./useHandleConnectWithPrivy";
18
19
  export { useHasMounted } from "./useHasMounted";
19
20
  export { useIsMobile } from "./useIsMobile";
@@ -1,8 +1,9 @@
1
1
  import { fetchSimpleHashData } from "@b3dotfun/sdk/shared/utils/simplehash";
2
2
  import { useQuery } from "@tanstack/react-query";
3
+ import invariant from "invariant";
3
4
 
4
- async function fetchAccountAssets(address: string) {
5
- if (!address) throw new Error("Address is required");
5
+ async function fetchAccountAssets(address: string | undefined) {
6
+ invariant(address, "Address is required");
6
7
 
7
8
  const [nftResponse] = await Promise.all([
8
9
  fetchSimpleHashData(`/v0/nfts/owners`, {
@@ -27,7 +28,7 @@ async function fetchAccountAssets(address: string) {
27
28
  export function useAccountAssets(address?: string) {
28
29
  return useQuery({
29
30
  queryKey: ["accountAssets", address],
30
- queryFn: () => fetchAccountAssets(address!),
31
+ queryFn: () => fetchAccountAssets(address),
31
32
  enabled: Boolean(address),
32
33
  staleTime: 30 * 1000, // Consider data fresh for 30 seconds
33
34
  gcTime: 5 * 60 * 1000, // Keep unused data in cache for 5 minutes
@@ -100,7 +100,7 @@ export function useAuthentication(partnerId: string, loginWithSiwe?: boolean) {
100
100
  setIsAuthenticating(false);
101
101
  }
102
102
  useAutoConnectLoadingPrevious.current = useAutoConnectLoading;
103
- }, [useAutoConnectLoading]);
103
+ }, [useAutoConnectLoading, hasStartedConnecting, setIsAuthenticating]);
104
104
 
105
105
  // Ensure isAuthenticating stays true until we're fully ready
106
106
  useEffect(() => {
@@ -0,0 +1,36 @@
1
+ import { useAuthStore } from "@b3dotfun/sdk/global-account/react";
2
+ import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
3
+ import { useEffect, useState } from "react";
4
+ import { useConnectedWallets, useWalletInfo } from "thirdweb/react";
5
+ import { Wallet } from "thirdweb/wallets";
6
+
7
+ const debug = debugB3React("useGlobalAccount");
8
+
9
+ export function useGlobalAccount() {
10
+ const wallets = useConnectedWallets();
11
+ const isConnected = useAuthStore(state => state.isConnected);
12
+ const [globalAccount, setGlobalAccount] = useState<Wallet | undefined>(undefined);
13
+ const [address, setAddress] = useState<string | undefined>(undefined);
14
+ const walletInfo = useWalletInfo(globalAccount?.id);
15
+
16
+ useEffect(() => {
17
+ if (!isConnected) {
18
+ debug("Not connected");
19
+ setGlobalAccount(undefined);
20
+ setAddress(undefined);
21
+ return;
22
+ }
23
+
24
+ const globalAccountWallet = wallets.find(wallet => wallet.id.startsWith("ecosystem."));
25
+
26
+ const account = globalAccountWallet?.getAccount();
27
+ setGlobalAccount(globalAccountWallet);
28
+ setAddress(account?.address);
29
+ }, [isConnected, wallets]);
30
+
31
+ return {
32
+ account: globalAccount,
33
+ address,
34
+ info: walletInfo,
35
+ };
36
+ }
@@ -30,7 +30,7 @@ export const useOneBalance = (bypassCache = false) => {
30
30
 
31
31
  const { data, isLoading, refetch } = useQuery({
32
32
  queryKey: ["balances", address, `testnet-${sprinterTestnet}`],
33
- queryFn: () => fetchBalances(address!, sprinterTestnet),
33
+ queryFn: () => fetchBalances(address, sprinterTestnet),
34
34
  enabled: !!address,
35
35
  staleTime: 1000 * 60 * 1, // 1 minute
36
36
  gcTime: 1000 * 60 * 5, // 5 minutes (renamed from cacheTime in v5)
@@ -47,26 +47,33 @@ export function useQueryB3<
47
47
  const [error, setError] = useState<Error | null>(null);
48
48
  const [isLoading, setIsLoading] = useState<boolean>(false);
49
49
 
50
- const runQuery = useCallback(async (queryParams: ParamsType<T, M>) => {
51
- setIsLoading(true);
52
- try {
53
- // Cast the service to avoid TypeScript issues with dynamic services
54
- const serviceInstance = app.service(service) as any;
55
- const result = await serviceInstance[method](queryParams);
56
- setData(result); // Now `data` is correctly typed!
57
- return result;
58
- } catch (err) {
59
- setError(err instanceof Error ? err : new Error("An error occurred"));
60
- } finally {
61
- setIsLoading(false);
62
- }
63
- }, []);
50
+ const runQuery = useCallback(
51
+ async (queryParams: ParamsType<T, M>) => {
52
+ setIsLoading(true);
53
+ try {
54
+ // Cast the service to avoid TypeScript issues with dynamic services
55
+ const serviceInstance = app.service(service) as any;
56
+ const result = await serviceInstance[method](queryParams);
57
+ setData(result); // Now `data` is correctly typed!
58
+ return result;
59
+ } catch (err) {
60
+ setError(err instanceof Error ? err : new Error("An error occurred"));
61
+ } finally {
62
+ setIsLoading(false);
63
+ }
64
+ },
65
+ [service, method],
66
+ );
67
+
68
+ // Serialize params for stable comparison
69
+ const paramsJson = JSON.stringify(params);
64
70
 
65
71
  useEffect(() => {
66
72
  if (fetchInitially) {
67
73
  runQuery(params);
68
74
  }
69
- }, [runQuery, fetchInitially, JSON.stringify(params)]);
75
+ // eslint-disable-next-line react-hooks/exhaustive-deps
76
+ }, [runQuery, fetchInitially, paramsJson]);
70
77
 
71
78
  return { data, error, isLoading, runQuery };
72
79
  }
@@ -47,26 +47,33 @@ export function useQueryBSMNT<
47
47
  const [error, setError] = useState<Error | null>(null);
48
48
  const [isLoading, setIsLoading] = useState<boolean>(false);
49
49
 
50
- const runQuery = useCallback(async (queryParams: ParamsType<T, M>) => {
51
- setIsLoading(true);
52
- try {
53
- // Cast the service to avoid TypeScript issues with dynamic services
54
- const serviceInstance = app.service(service) as any;
55
- const result = await serviceInstance[method](queryParams);
56
- setData(result); // Now `data` is correctly typed!
57
- return result;
58
- } catch (err) {
59
- setError(err instanceof Error ? err : new Error("An error occurred"));
60
- } finally {
61
- setIsLoading(false);
62
- }
63
- }, []);
50
+ const runQuery = useCallback(
51
+ async (queryParams: ParamsType<T, M>) => {
52
+ setIsLoading(true);
53
+ try {
54
+ // Cast the service to avoid TypeScript issues with dynamic services
55
+ const serviceInstance = app.service(service) as any;
56
+ const result = await serviceInstance[method](queryParams);
57
+ setData(result); // Now `data` is correctly typed!
58
+ return result;
59
+ } catch (err) {
60
+ setError(err instanceof Error ? err : new Error("An error occurred"));
61
+ } finally {
62
+ setIsLoading(false);
63
+ }
64
+ },
65
+ [service, method],
66
+ );
67
+
68
+ // Serialize params for stable comparison
69
+ const paramsJson = JSON.stringify(params);
64
70
 
65
71
  useEffect(() => {
66
72
  if (fetchInitially) {
67
73
  runQuery(params);
68
74
  }
69
- }, [runQuery, fetchInitially, JSON.stringify(params)]);
75
+ // eslint-disable-next-line react-hooks/exhaustive-deps
76
+ }, [runQuery, fetchInitially, paramsJson]);
70
77
 
71
78
  return { data, error, isLoading, runQuery };
72
79
  }
@@ -7,6 +7,7 @@ import { viemToThirdwebChain } from "@b3dotfun/sdk/shared/constants/chains/b3Cha
7
7
  import { getChainById } from "@b3dotfun/sdk/shared/utils/chains";
8
8
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
9
9
  import { getWalletBalance } from "thirdweb/wallets";
10
+ import invariant from "invariant";
10
11
 
11
12
  type GetWalletBalanceResult = {
12
13
  value: bigint;
@@ -51,10 +52,12 @@ export function useTokenBalancesByChain({
51
52
  // Fetch native token balances
52
53
  Promise.all(
53
54
  chainIds.map(async chainId => {
55
+ const chain = getChainById(chainId);
56
+ invariant(chain, "Chain is required");
54
57
  const walletBalance = await getWalletBalance({
55
58
  address,
56
59
  client,
57
- chain: viemToThirdwebChain(getChainById(chainId)!),
60
+ chain: viemToThirdwebChain(chain),
58
61
  });
59
62
 
60
63
  return {
@@ -69,7 +69,7 @@ export function useTokenFromUrl({ defaultToken, prefix }: UseTokenFromUrlOptions
69
69
 
70
70
  const { data: tokenInfo, isError } = useQuery({
71
71
  queryKey: ["tokenInfo", network, currencyParam],
72
- queryFn: () => fetchTokenInfo(network, currencyParam!),
72
+ queryFn: () => fetchTokenInfo(network, currencyParam || ""),
73
73
  enabled: shouldFetchToken,
74
74
  staleTime: Infinity,
75
75
  gcTime: Infinity,
@@ -84,7 +84,7 @@ export function useTokenFromUrl({ defaultToken, prefix }: UseTokenFromUrlOptions
84
84
  if (isError || !tokenInfo) {
85
85
  return {
86
86
  ...defaultToken,
87
- address: currencyParam!,
87
+ address: currencyParam || "",
88
88
  chainId: Number(chainIdParam),
89
89
  };
90
90
  }
@@ -8,7 +8,7 @@ import { toast } from "sonner";
8
8
  import { prepareTransaction, sendTransaction as twSendTransaction } from "thirdweb";
9
9
  import { useActiveWallet } from "thirdweb/react";
10
10
  import { isAddress } from "viem";
11
- import { useSwitchChain, useWalletClient } from "wagmi";
11
+ import { useSwitchChain } from "wagmi";
12
12
  import { useB3 } from "../components";
13
13
  import { useAccountWallet } from "./useAccountWallet";
14
14
 
@@ -27,7 +27,6 @@ const partnerId = String(
27
27
  invariant(partnerId, "Partner ID is required");
28
28
 
29
29
  export function useUnifiedChainSwitchAndExecute() {
30
- const { data: walletClient } = useWalletClient();
31
30
  const { switchChainAsync } = useSwitchChain();
32
31
  const [isSwitchingOrExecuting, setIsSwitchingOrExecuting] = useState(false);
33
32
  const activeWallet = useActiveWallet();
@@ -122,7 +121,7 @@ export function useUnifiedChainSwitchAndExecute() {
122
121
  setIsSwitchingOrExecuting(false);
123
122
  }
124
123
  },
125
- [walletClient, switchChainAsync],
124
+ [connectedEOAWallet, activeWallet, switchChainAsync],
126
125
  );
127
126
 
128
127
  // Handle AA wallet transaction (no chain switch needed for AA)