@b3dotfun/sdk 0.0.88-alpha.7 → 0.0.88-alpha.9

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 (57) hide show
  1. package/dist/cjs/anyspend/constants/index.d.ts +2 -0
  2. package/dist/cjs/anyspend/constants/index.js +3 -1
  3. package/dist/cjs/anyspend/index.d.ts +2 -0
  4. package/dist/cjs/anyspend/index.js +3 -0
  5. package/dist/cjs/anyspend/react/components/AnySpend.js +4 -1
  6. package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +22 -18
  7. package/dist/cjs/anyspend/react/components/common/GasIndicator.d.ts +6 -0
  8. package/dist/cjs/anyspend/react/components/common/GasIndicator.js +34 -0
  9. package/dist/cjs/anyspend/react/hooks/index.d.ts +1 -0
  10. package/dist/cjs/anyspend/react/hooks/index.js +1 -0
  11. package/dist/cjs/anyspend/react/hooks/useGasPrice.d.ts +37 -0
  12. package/dist/cjs/anyspend/react/hooks/useGasPrice.js +43 -0
  13. package/dist/cjs/anyspend/services/gas.d.ts +21 -0
  14. package/dist/cjs/anyspend/services/gas.js +65 -0
  15. package/dist/cjs/anyspend/types/gas.d.ts +61 -0
  16. package/dist/cjs/anyspend/types/gas.js +2 -0
  17. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +14 -2
  18. package/dist/cjs/global-account/react/hooks/useTokenBalancesByChain.js +4 -2
  19. package/dist/esm/anyspend/constants/index.d.ts +2 -0
  20. package/dist/esm/anyspend/constants/index.js +2 -0
  21. package/dist/esm/anyspend/index.d.ts +2 -0
  22. package/dist/esm/anyspend/index.js +3 -0
  23. package/dist/esm/anyspend/react/components/AnySpend.js +5 -2
  24. package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +5 -1
  25. package/dist/esm/anyspend/react/components/common/GasIndicator.d.ts +6 -0
  26. package/dist/esm/anyspend/react/components/common/GasIndicator.js +31 -0
  27. package/dist/esm/anyspend/react/hooks/index.d.ts +1 -0
  28. package/dist/esm/anyspend/react/hooks/index.js +1 -0
  29. package/dist/esm/anyspend/react/hooks/useGasPrice.d.ts +37 -0
  30. package/dist/esm/anyspend/react/hooks/useGasPrice.js +40 -0
  31. package/dist/esm/anyspend/services/gas.d.ts +21 -0
  32. package/dist/esm/anyspend/services/gas.js +59 -0
  33. package/dist/esm/anyspend/types/gas.d.ts +61 -0
  34. package/dist/esm/anyspend/types/gas.js +1 -0
  35. package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +14 -2
  36. package/dist/esm/global-account/react/hooks/useTokenBalancesByChain.js +4 -2
  37. package/dist/styles/index.css +1 -1
  38. package/dist/types/anyspend/constants/index.d.ts +2 -0
  39. package/dist/types/anyspend/index.d.ts +2 -0
  40. package/dist/types/anyspend/react/components/common/GasIndicator.d.ts +6 -0
  41. package/dist/types/anyspend/react/hooks/index.d.ts +1 -0
  42. package/dist/types/anyspend/react/hooks/useGasPrice.d.ts +37 -0
  43. package/dist/types/anyspend/services/gas.d.ts +21 -0
  44. package/dist/types/anyspend/types/gas.d.ts +61 -0
  45. package/package.json +1 -1
  46. package/src/anyspend/constants/index.ts +3 -0
  47. package/src/anyspend/index.ts +4 -0
  48. package/src/anyspend/react/components/AnySpend.tsx +10 -0
  49. package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +10 -0
  50. package/src/anyspend/react/components/common/GasIndicator.tsx +59 -0
  51. package/src/anyspend/react/hooks/index.ts +1 -0
  52. package/src/anyspend/react/hooks/useGasPrice.ts +70 -0
  53. package/src/anyspend/services/gas.test.ts +31 -0
  54. package/src/anyspend/services/gas.ts +73 -0
  55. package/src/anyspend/types/gas.ts +66 -0
  56. package/src/global-account/react/components/B3Provider/B3Provider.tsx +14 -2
  57. package/src/global-account/react/hooks/useTokenBalancesByChain.tsx +4 -2
@@ -1,6 +1,8 @@
1
1
  import { components } from "../types/api";
2
2
  export declare const ANYSPEND_MAINNET_BASE_URL: string;
3
3
  export declare const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
4
+ export declare const GAS_ORACLE_BASE_URL: string;
5
+ export declare const RELAY_ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
4
6
  export declare const RELAY_SOL_ADDRESS = "11111111111111111111111111111111";
5
7
  export declare const RELAY_SOLANA_MAINNET_CHAIN_ID = 792703809;
6
8
  export declare const SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VENDOR_DISPLAY_NAMES = exports.PAYMENT_METHOD_ICONS = exports.STRIPE_CONFIG = exports.DEFAULT_NFT_CONTRACT = exports.NFT_CONTRACTS = exports.ETH_BASE = exports.USDC_BASE = exports.ANYSPEND_TOKEN = exports.B3_TOKEN = exports.SOLANA_TOKEN_2022_PROGRAM_ID = exports.SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = exports.RELAY_SOLANA_MAINNET_CHAIN_ID = exports.RELAY_SOL_ADDRESS = exports.ZERO_ADDRESS = exports.ANYSPEND_MAINNET_BASE_URL = void 0;
3
+ exports.VENDOR_DISPLAY_NAMES = exports.PAYMENT_METHOD_ICONS = exports.STRIPE_CONFIG = exports.DEFAULT_NFT_CONTRACT = exports.NFT_CONTRACTS = exports.ETH_BASE = exports.USDC_BASE = exports.ANYSPEND_TOKEN = exports.B3_TOKEN = exports.SOLANA_TOKEN_2022_PROGRAM_ID = exports.SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = exports.RELAY_SOLANA_MAINNET_CHAIN_ID = exports.RELAY_SOL_ADDRESS = exports.RELAY_ETH_ADDRESS = exports.GAS_ORACLE_BASE_URL = exports.ZERO_ADDRESS = exports.ANYSPEND_MAINNET_BASE_URL = void 0;
4
4
  exports.getStripePublishableKey = getStripePublishableKey;
5
5
  const chains_1 = require("viem/chains");
6
6
  exports.ANYSPEND_MAINNET_BASE_URL = process.env.NEXT_PUBLIC_ANYSPEND_BASE_URL || "https://mainnet.anyspend.com";
7
7
  exports.ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
8
+ exports.GAS_ORACLE_BASE_URL = process.env.NEXT_PUBLIC_GAS_ORACLE_URL || "https://gas-oracle.sean-430.workers.dev";
9
+ exports.RELAY_ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
8
10
  exports.RELAY_SOL_ADDRESS = "11111111111111111111111111111111";
9
11
  exports.RELAY_SOLANA_MAINNET_CHAIN_ID = 792703809;
10
12
  exports.SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
@@ -1,4 +1,5 @@
1
1
  export * from "./types/api";
2
+ export * from "./types/gas";
2
3
  export * from "./utils/address";
3
4
  export * from "./utils/chain";
4
5
  export * from "./utils/format";
@@ -8,5 +9,6 @@ export * from "./utils/string";
8
9
  export * from "./utils/token";
9
10
  export * from "./utils/validation";
10
11
  export * from "./constants";
12
+ export * from "./services/gas";
11
13
  export * from "./abis/abiUsdcBase";
12
14
  export * from "./abis/erc20Staking";
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  // Types
18
18
  __exportStar(require("./types/api"), exports);
19
+ __exportStar(require("./types/gas"), exports);
19
20
  // Utils
20
21
  __exportStar(require("./utils/address"), exports);
21
22
  __exportStar(require("./utils/chain"), exports);
@@ -27,6 +28,8 @@ __exportStar(require("./utils/token"), exports);
27
28
  __exportStar(require("./utils/validation"), exports);
28
29
  // Constants
29
30
  __exportStar(require("./constants"), exports);
31
+ // Services
32
+ __exportStar(require("./services/gas"), exports);
30
33
  // Abis
31
34
  __exportStar(require("./abis/abiUsdcBase"), exports);
32
35
  __exportStar(require("./abis/erc20Staking"), exports);
@@ -31,6 +31,7 @@ const CryptoPaySection_1 = require("./common/CryptoPaySection");
31
31
  const CryptoReceiveSection_1 = require("./common/CryptoReceiveSection");
32
32
  const FeeDetailPanel_1 = require("./common/FeeDetailPanel");
33
33
  const FiatPaymentMethod_1 = require("./common/FiatPaymentMethod");
34
+ const GasIndicator_1 = require("./common/GasIndicator");
34
35
  const OrderDetails_1 = require("./common/OrderDetails");
35
36
  const OrderHistory_1 = require("./common/OrderHistory");
36
37
  const PanelOnramp_1 = require("./common/PanelOnramp");
@@ -372,6 +373,8 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
372
373
  });
373
374
  // Get geo-based onramp options for fiat payments
374
375
  const { geoData, coinbaseAvailablePaymentMethods, stripeOnrampSupport, stripeWeb2Support } = (0, react_1.useGeoOnrampOptions)(srcAmountOnRamp);
376
+ // Get gas price for source chain (where the user pays from)
377
+ const { gasPrice: gasPriceData, isLoading: isLoadingGas } = (0, react_1.useGasPrice)(selectedSrcChainId);
375
378
  // Helper function to map payment method to onramp vendor
376
379
  const getOnrampVendor = (paymentMethod) => {
377
380
  switch (paymentMethod) {
@@ -860,7 +863,7 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
860
863
  }, children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) })), activeTab === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: isBuyMode, effectiveRecipientAddress: effectiveRecipientAddress, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward"), dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
861
864
  setIsSrcInputDirty(false);
862
865
  setDstAmount(value);
863
- }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward") }))] }), (0, jsx_runtime_1.jsxs)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: [(0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (0, cn_1.cn)("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: (0, cn_1.cn)(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }), !hideTransactionHistoryButton && (globalAddress || effectiveRecipientAddress) ? ((0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "link", onClick: onClickHistory, className: "text-as-primary/50 hover:text-as-primary flex items-center gap-1 transition-colors", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.HistoryIcon, { className: "h-4 w-4" }), " ", (0, jsx_runtime_1.jsx)("span", { className: "pr-4", children: "Transaction History" })] })) : null] })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full", children: (0, jsx_runtime_1.jsx)(react_2.TabsPrimitive, { defaultValue: "swap", onValueChange: value => {
866
+ }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward") }))] }), gasPriceData && !isLoadingGas && activeTab === "crypto" && ((0, jsx_runtime_1.jsx)(GasIndicator_1.GasIndicator, { gasPrice: gasPriceData, className: "mt-2 w-full" })), (0, jsx_runtime_1.jsxs)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: [(0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (0, cn_1.cn)("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: (0, cn_1.cn)(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }), !hideTransactionHistoryButton && (globalAddress || effectiveRecipientAddress) ? ((0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "link", onClick: onClickHistory, className: "text-as-primary/50 hover:text-as-primary flex items-center gap-1 transition-colors", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.HistoryIcon, { className: "h-4 w-4" }), " ", (0, jsx_runtime_1.jsx)("span", { className: "pr-4", children: "Transaction History" })] })) : null] })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full", children: (0, jsx_runtime_1.jsx)(react_2.TabsPrimitive, { defaultValue: "swap", onValueChange: value => {
864
867
  if (value === "settings" || value === "home") {
865
868
  setB3ModalContentType({
866
869
  type: "manageAccount",
@@ -5,15 +5,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.AnySpendCustomExactIn = AnySpendCustomExactIn;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const react_1 = require("../../../anyspend/react");
8
9
  const utils_1 = require("../../../anyspend/utils");
9
- const react_1 = require("../../../global-account/react");
10
+ const react_2 = require("../../../global-account/react");
10
11
  const cn_1 = require("../../../shared/utils/cn");
11
12
  const number_1 = require("../../../shared/utils/number");
12
13
  const invariant_1 = __importDefault(require("invariant"));
13
14
  const lucide_react_1 = require("lucide-react");
14
- const react_2 = require("motion/react");
15
- const react_3 = require("react");
16
- const react_4 = require("thirdweb/react");
15
+ const react_3 = require("motion/react");
16
+ const react_4 = require("react");
17
+ const react_5 = require("thirdweb/react");
17
18
  const constants_1 = require("../../constants");
18
19
  const useAnyspendFlow_1 = require("../hooks/useAnyspendFlow");
19
20
  const AnySpendFingerprintWrapper_1 = require("./AnySpendFingerprintWrapper");
@@ -22,6 +23,7 @@ const CryptoPaymentMethod_1 = require("./common/CryptoPaymentMethod");
22
23
  const CryptoReceiveSection_1 = require("./common/CryptoReceiveSection");
23
24
  const FeeDetailPanel_1 = require("./common/FeeDetailPanel");
24
25
  const FiatPaymentMethod_1 = require("./common/FiatPaymentMethod");
26
+ const GasIndicator_1 = require("./common/GasIndicator");
25
27
  const OrderDetails_1 = require("./common/OrderDetails");
26
28
  const PanelOnramp_1 = require("./common/PanelOnramp");
27
29
  const PointsDetailPanel_1 = require("./common/PointsDetailPanel");
@@ -50,10 +52,12 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
50
52
  disableUrlParamManagement: true,
51
53
  orderType,
52
54
  });
53
- const { connectedEOAWallet } = (0, react_1.useAccountWallet)();
54
- const setActiveWallet = (0, react_4.useSetActiveWallet)();
55
- const appliedPreferEoa = (0, react_3.useRef)(false);
56
- (0, react_3.useEffect)(() => {
55
+ const { connectedEOAWallet } = (0, react_2.useAccountWallet)();
56
+ const setActiveWallet = (0, react_5.useSetActiveWallet)();
57
+ // Get gas price for source chain (where the user pays from)
58
+ const { gasPrice: gasPriceData, isLoading: isLoadingGas } = (0, react_1.useGasPrice)(selectedSrcChainId);
59
+ const appliedPreferEoa = (0, react_4.useRef)(false);
60
+ (0, react_4.useEffect)(() => {
57
61
  if (preferEoa && !appliedPreferEoa.current) {
58
62
  if (connectedEOAWallet) {
59
63
  appliedPreferEoa.current = true;
@@ -84,7 +88,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
84
88
  action: customExactInConfig.action,
85
89
  };
86
90
  };
87
- const btnInfo = (0, react_3.useMemo)(() => {
91
+ const btnInfo = (0, react_4.useMemo)(() => {
88
92
  if (activeInputAmountInWei === "0")
89
93
  return { text: "Enter an amount", disable: true, error: false, loading: false };
90
94
  if (orderType === "hype_duel" && selectedSrcToken?.address?.toLowerCase() === constants_1.B3_TOKEN.address.toLowerCase()) {
@@ -181,10 +185,10 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
181
185
  }
182
186
  };
183
187
  const headerContent = header ? (header({ anyspendPrice: anyspendQuote, isLoadingAnyspendPrice: isLoadingAnyspendQuote })) : ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-as-primary text-xl font-bold", children: actionLabel }), (0, jsx_runtime_1.jsx)("p", { className: "text-as-secondary text-sm", children: "Pay from any token to execute a custom exact-in transaction." })] }) }));
184
- const mainView = ((0, jsx_runtime_1.jsxs)("div", { className: "anyspend-custom-exact-in-container mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [headerContent, (0, jsx_runtime_1.jsx)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [paymentType === "crypto" ? ((0, jsx_runtime_1.jsx)(CryptoPaySection_1.CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(useAnyspendFlow_1.PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : ((0, jsx_runtime_1.jsx)(react_2.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: (0, jsx_runtime_1.jsx)(PanelOnramp_1.PanelOnramp, { srcAmountOnRamp: srcAmount, setSrcAmountOnRamp: setSrcAmount, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: selectedRecipientOrDefault, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, hideDstToken: true, destinationAmount: dstAmount, onDestinationTokenChange: () => { }, onDestinationChainChange: () => { }, fiatPaymentMethodIndex: useAnyspendFlow_1.PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.FEE_DETAIL), customUsdInputValues: customUsdInputValues, customRecipientLabel: customRecipientLabel }) })), (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "ghost", className: (0, cn_1.cn)("swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl"), children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: true, effectiveRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => setActivePanel(useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION), dstAmount: dstAmount, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
188
+ const mainView = ((0, jsx_runtime_1.jsxs)("div", { className: "anyspend-custom-exact-in-container mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [headerContent, (0, jsx_runtime_1.jsx)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [paymentType === "crypto" ? ((0, jsx_runtime_1.jsx)(CryptoPaySection_1.CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(useAnyspendFlow_1.PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : ((0, jsx_runtime_1.jsx)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: (0, jsx_runtime_1.jsx)(PanelOnramp_1.PanelOnramp, { srcAmountOnRamp: srcAmount, setSrcAmountOnRamp: setSrcAmount, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: selectedRecipientOrDefault, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, hideDstToken: true, destinationAmount: dstAmount, onDestinationTokenChange: () => { }, onDestinationChainChange: () => { }, fiatPaymentMethodIndex: useAnyspendFlow_1.PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.FEE_DETAIL), customUsdInputValues: customUsdInputValues, customRecipientLabel: customRecipientLabel }) })), (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: (0, jsx_runtime_1.jsx)(react_2.Button, { variant: "ghost", className: (0, cn_1.cn)("swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl"), children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: true, effectiveRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => setActivePanel(useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION), dstAmount: dstAmount, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
185
189
  setIsSrcInputDirty(false);
186
190
  setSrcAmount(value);
187
- }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.FEE_DETAIL) }))] }) }), (0, jsx_runtime_1.jsx)(react_2.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: (0, jsx_runtime_1.jsx)(react_1.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (0, cn_1.cn)("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: (0, cn_1.cn)(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }) }), mainFooter ? mainFooter : null] }));
191
+ }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.FEE_DETAIL) }))] }) }), (0, jsx_runtime_1.jsx)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: (0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (0, cn_1.cn)("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: (0, cn_1.cn)(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }) }), gasPriceData && !isLoadingGas && paymentType === "crypto" && ((0, jsx_runtime_1.jsx)(GasIndicator_1.GasIndicator, { gasPrice: gasPriceData, className: "mt-2 w-full" })), mainFooter ? mainFooter : null] }));
188
192
  const handleCryptoOrder = async () => {
189
193
  try {
190
194
  (0, invariant_1.default)(anyspendQuote, "Relay price is not found");
@@ -206,7 +210,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
206
210
  }
207
211
  catch (err) {
208
212
  console.error(err);
209
- react_1.toast.error("Failed to create order: " + err.message);
213
+ react_2.toast.error("Failed to create order: " + err.message);
210
214
  }
211
215
  };
212
216
  const handleFiatOrder = async () => {
@@ -214,14 +218,14 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
214
218
  (0, invariant_1.default)(anyspendQuote, "Relay price is not found");
215
219
  (0, invariant_1.default)(selectedRecipientOrDefault, "Recipient address is not found");
216
220
  if (!srcAmount || parseFloat(srcAmount) <= 0) {
217
- react_1.toast.error("Please enter a valid amount");
221
+ react_2.toast.error("Please enter a valid amount");
218
222
  return;
219
223
  }
220
224
  let vendor;
221
225
  let paymentMethodString = "";
222
226
  if (selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.COINBASE_PAY) {
223
227
  if (coinbaseAvailablePaymentMethods.length === 0) {
224
- react_1.toast.error("Coinbase Pay not available");
228
+ react_2.toast.error("Coinbase Pay not available");
225
229
  return;
226
230
  }
227
231
  vendor = "coinbase";
@@ -229,13 +233,13 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
229
233
  }
230
234
  else if (selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.STRIPE) {
231
235
  if (!stripeWeb2Support || !stripeWeb2Support.isSupport) {
232
- react_1.toast.error("Stripe not available");
236
+ react_2.toast.error("Stripe not available");
233
237
  return;
234
238
  }
235
239
  vendor = "stripe-web2";
236
240
  }
237
241
  else {
238
- react_1.toast.error("Please select a payment method");
242
+ react_2.toast.error("Please select a payment method");
239
243
  return;
240
244
  }
241
245
  const payload = buildCustomPayload(selectedRecipientOrDefault);
@@ -258,7 +262,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
258
262
  }
259
263
  catch (err) {
260
264
  console.error(err);
261
- react_1.toast.error("Failed to create order: " + err.message);
265
+ react_2.toast.error("Failed to create order: " + err.message);
262
266
  }
263
267
  };
264
268
  const orderDetailsView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto w-[460px] max-w-full", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex flex-col gap-4", children: oat && ((0, jsx_runtime_1.jsx)(OrderDetails_1.OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: paymentType === "fiat" ? CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE : effectiveCryptoPaymentMethod, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onPaymentMethodChange: setSelectedCryptoPaymentMethod, onBack: () => {
@@ -284,7 +288,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
284
288
  : anyspendQuote.data.currencyIn?.amountUsd
285
289
  ? Number(anyspendQuote.data.currencyIn.amountUsd)
286
290
  : undefined, onBack: () => setActivePanel(useAnyspendFlow_1.PanelView.MAIN) })) : null;
287
- return ((0, jsx_runtime_1.jsx)(react_1.StyleRoot, { children: (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("anyspend-container font-inter bg-as-surface-primary mx-auto w-full max-w-[460px] p-6", mode === "page" && "border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: (0, jsx_runtime_1.jsx)(react_1.TransitionPanel, { activeIndex: orderId
291
+ return ((0, jsx_runtime_1.jsx)(react_2.StyleRoot, { children: (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("anyspend-container font-inter bg-as-surface-primary mx-auto w-full max-w-[460px] p-6", mode === "page" && "border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: (0, jsx_runtime_1.jsx)(react_2.TransitionPanel, { activeIndex: orderId
288
292
  ? oat
289
293
  ? useAnyspendFlow_1.PanelView.ORDER_DETAILS
290
294
  : useAnyspendFlow_1.PanelView.LOADING
@@ -0,0 +1,6 @@
1
+ import type { GasPriceData } from "../../../types/gas";
2
+ export interface GasIndicatorProps {
3
+ gasPrice: GasPriceData;
4
+ className?: string;
5
+ }
6
+ export declare function GasIndicator({ gasPrice, className }: GasIndicatorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ "use client";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.GasIndicator = GasIndicator;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const cn_1 = require("../../../../shared/utils/cn");
7
+ const react_1 = require("motion/react");
8
+ const LEVEL_LABELS = {
9
+ low: "Low",
10
+ normal: "Normal",
11
+ elevated: "Elevated",
12
+ high: "High",
13
+ spike: "Spike",
14
+ };
15
+ const LEVEL_STYLES = {
16
+ low: "bg-green-500/20 text-green-500",
17
+ normal: "bg-as-surface-tertiary text-as-secondary",
18
+ elevated: "bg-yellow-500/20 text-yellow-600",
19
+ high: "bg-orange-500/20 text-orange-500",
20
+ spike: "bg-red-500/20 text-red-500",
21
+ };
22
+ function formatGasPrice(gweiString) {
23
+ const gwei = parseFloat(gweiString);
24
+ if (gwei < 0.001)
25
+ return "<0.001";
26
+ if (gwei < 1)
27
+ return gwei.toFixed(3);
28
+ if (gwei < 10)
29
+ return gwei.toFixed(2);
30
+ return gwei.toFixed(1);
31
+ }
32
+ function GasIndicator({ gasPrice, className }) {
33
+ return ((0, jsx_runtime_1.jsxs)(react_1.motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.2 }, className: (0, cn_1.cn)("flex items-center justify-between rounded-lg px-3 py-2", gasPrice.isSpike ? "bg-yellow-500/10" : "bg-as-surface-secondary", className), children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsxs)("span", { className: "text-as-secondary text-xs", children: ["Gas on ", gasPrice.chainName] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: (0, cn_1.cn)("rounded px-1.5 py-0.5 text-xs font-medium", LEVEL_STYLES[gasPrice.level]), children: LEVEL_LABELS[gasPrice.level] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-as-primary text-xs font-medium", children: [formatGasPrice(gasPrice.gasPriceGwei), " Gwei"] })] })] }));
34
+ }
@@ -7,6 +7,7 @@ export * from "./useAnyspendQuote";
7
7
  export * from "./useAnyspendTokens";
8
8
  export * from "./useCoinbaseOnrampOptions";
9
9
  export * from "./useConnectedUserProfile";
10
+ export * from "./useGasPrice";
10
11
  export * from "./useGeoOnrampOptions";
11
12
  export * from "./useGetGeo";
12
13
  export * from "./useHyperliquidTransfer";
@@ -23,6 +23,7 @@ __exportStar(require("./useAnyspendQuote"), exports);
23
23
  __exportStar(require("./useAnyspendTokens"), exports);
24
24
  __exportStar(require("./useCoinbaseOnrampOptions"), exports);
25
25
  __exportStar(require("./useConnectedUserProfile"), exports);
26
+ __exportStar(require("./useGasPrice"), exports);
26
27
  __exportStar(require("./useGeoOnrampOptions"), exports);
27
28
  __exportStar(require("./useGetGeo"), exports);
28
29
  __exportStar(require("./useHyperliquidTransfer"), exports);
@@ -0,0 +1,37 @@
1
+ import type { GasPriceData } from "../../types/gas";
2
+ export interface UseGasPriceOptions {
3
+ /** Refetch interval in ms (default: 10000 = 10s) */
4
+ refetchInterval?: number;
5
+ /** Whether to enable the query (default: true if chainId is supported) */
6
+ enabled?: boolean;
7
+ }
8
+ export interface UseGasPriceResult {
9
+ /** Gas price data */
10
+ gasPrice: GasPriceData | undefined;
11
+ /** Whether the query is loading */
12
+ isLoading: boolean;
13
+ /** Whether there's an error */
14
+ isError: boolean;
15
+ /** Error object if any */
16
+ error: Error | null;
17
+ /** Whether gas is currently spiking */
18
+ isSpike: boolean;
19
+ /** Refetch function */
20
+ refetch: () => void;
21
+ }
22
+ /**
23
+ * React hook to fetch current gas price for a chain.
24
+ *
25
+ * @param chainId - The chain ID to fetch gas price for
26
+ * @param options - Optional configuration
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * const { gasPrice, isSpike, isLoading } = useGasPrice(8453); // Base
31
+ *
32
+ * if (isSpike) {
33
+ * return <Warning>Gas prices are high: {gasPrice?.recommendation}</Warning>;
34
+ * }
35
+ * ```
36
+ */
37
+ export declare function useGasPrice(chainId: number | undefined, options?: UseGasPriceOptions): UseGasPriceResult;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useGasPrice = useGasPrice;
4
+ const react_query_1 = require("@tanstack/react-query");
5
+ const react_1 = require("react");
6
+ const gas_1 = require("../../services/gas");
7
+ /**
8
+ * React hook to fetch current gas price for a chain.
9
+ *
10
+ * @param chainId - The chain ID to fetch gas price for
11
+ * @param options - Optional configuration
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * const { gasPrice, isSpike, isLoading } = useGasPrice(8453); // Base
16
+ *
17
+ * if (isSpike) {
18
+ * return <Warning>Gas prices are high: {gasPrice?.recommendation}</Warning>;
19
+ * }
20
+ * ```
21
+ */
22
+ function useGasPrice(chainId, options = {}) {
23
+ const { refetchInterval = 10000, enabled } = options;
24
+ const isSupported = chainId !== undefined && (0, gas_1.isGasOracleSupported)(chainId);
25
+ const queryEnabled = enabled ?? isSupported;
26
+ const { data, isLoading, isError, error, refetch } = (0, react_query_1.useQuery)({
27
+ queryKey: ["gasPrice", chainId],
28
+ queryFn: () => gas_1.gasService.fetch(chainId),
29
+ enabled: queryEnabled && chainId !== undefined,
30
+ refetchInterval,
31
+ staleTime: 5000, // Consider data fresh for 5s
32
+ retry: 2,
33
+ refetchOnWindowFocus: true,
34
+ });
35
+ return (0, react_1.useMemo)(() => ({
36
+ gasPrice: data,
37
+ isLoading,
38
+ isError,
39
+ error: error,
40
+ isSpike: data?.isSpike ?? false,
41
+ refetch,
42
+ }), [data, isLoading, isError, error, refetch]);
43
+ }
@@ -0,0 +1,21 @@
1
+ import type { GasOracleResponse, GasPriceData } from "../types/gas";
2
+ /** Supported chain IDs for gas oracle */
3
+ export declare const GAS_ORACLE_SUPPORTED_CHAINS: readonly [1, 137, 42161, 8453, 56, 10, 43114, 8333, 2741, 4689, 3338, 1329];
4
+ export type GasOracleSupportedChainId = (typeof GAS_ORACLE_SUPPORTED_CHAINS)[number];
5
+ /** Check if a chain is supported by the gas oracle */
6
+ export declare function isGasOracleSupported(chainId: number): chainId is GasOracleSupportedChainId;
7
+ /** Fetch gas price data from the gas oracle */
8
+ export declare function fetchGasPrice(chainId: number): Promise<GasOracleResponse>;
9
+ /** Transform raw oracle response to simplified UI data */
10
+ export declare function toGasPriceData(response: GasOracleResponse): GasPriceData;
11
+ /** Gas service for fetching and transforming gas data */
12
+ export declare const gasService: {
13
+ /** Fetch raw gas oracle response */
14
+ fetchRaw: typeof fetchGasPrice;
15
+ /** Fetch and transform to UI-friendly format */
16
+ fetch: (chainId: number) => Promise<GasPriceData>;
17
+ /** Check if chain is supported */
18
+ isSupported: typeof isGasOracleSupported;
19
+ /** List of supported chain IDs */
20
+ supportedChains: readonly [1, 137, 42161, 8453, 56, 10, 43114, 8333, 2741, 4689, 3338, 1329];
21
+ };
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.gasService = exports.GAS_ORACLE_SUPPORTED_CHAINS = void 0;
4
+ exports.isGasOracleSupported = isGasOracleSupported;
5
+ exports.fetchGasPrice = fetchGasPrice;
6
+ exports.toGasPriceData = toGasPriceData;
7
+ const constants_1 = require("../constants");
8
+ /** Supported chain IDs for gas oracle */
9
+ exports.GAS_ORACLE_SUPPORTED_CHAINS = [
10
+ 1, // Ethereum
11
+ 137, // Polygon
12
+ 42161, // Arbitrum
13
+ 8453, // Base
14
+ 56, // BSC
15
+ 10, // Optimism
16
+ 43114, // Avalanche
17
+ 8333, // B3
18
+ 2741, // Abstract
19
+ 4689, // IoTeX
20
+ 3338, // Peaq
21
+ 1329, // Sei
22
+ ];
23
+ /** Check if a chain is supported by the gas oracle */
24
+ function isGasOracleSupported(chainId) {
25
+ return exports.GAS_ORACLE_SUPPORTED_CHAINS.includes(chainId);
26
+ }
27
+ /** Fetch gas price data from the gas oracle */
28
+ async function fetchGasPrice(chainId) {
29
+ const response = await fetch(`${constants_1.GAS_ORACLE_BASE_URL}/gas/${chainId}`);
30
+ if (!response.ok) {
31
+ throw new Error(`Failed to fetch gas price for chain ${chainId}: ${response.status}`);
32
+ }
33
+ return response.json();
34
+ }
35
+ /** Transform raw oracle response to simplified UI data */
36
+ function toGasPriceData(response) {
37
+ const { analysis } = response;
38
+ const isSpike = analysis.level === "elevated" || analysis.level === "high" || analysis.level === "spike";
39
+ return {
40
+ chainId: response.chainId,
41
+ chainName: response.chainName,
42
+ gasPriceGwei: response.gasPrice.standard,
43
+ baseFeeGwei: response.eip1559?.baseFee,
44
+ level: analysis.level,
45
+ isSpike,
46
+ recommendation: analysis.recommendation,
47
+ vsMedian: analysis.vs1h, // Use 1h as primary comparison
48
+ source: response.source,
49
+ timestamp: response.timestamp,
50
+ };
51
+ }
52
+ /** Gas service for fetching and transforming gas data */
53
+ exports.gasService = {
54
+ /** Fetch raw gas oracle response */
55
+ fetchRaw: fetchGasPrice,
56
+ /** Fetch and transform to UI-friendly format */
57
+ fetch: async (chainId) => {
58
+ const response = await fetchGasPrice(chainId);
59
+ return toGasPriceData(response);
60
+ },
61
+ /** Check if chain is supported */
62
+ isSupported: isGasOracleSupported,
63
+ /** List of supported chain IDs */
64
+ supportedChains: exports.GAS_ORACLE_SUPPORTED_CHAINS,
65
+ };
@@ -0,0 +1,61 @@
1
+ /** Gas level classification based on historical percentiles */
2
+ export type GasLevel = "low" | "normal" | "elevated" | "high" | "spike";
3
+ /** Gas prices in Gwei for different speed tiers */
4
+ export interface GasPrices {
5
+ low: string;
6
+ standard: string;
7
+ fast: string;
8
+ instant?: string;
9
+ }
10
+ /** EIP-1559 specific gas data */
11
+ export interface Eip1559Data {
12
+ baseFee: string;
13
+ maxPriorityFee: GasPrices;
14
+ maxFee: GasPrices;
15
+ }
16
+ /** Spike analysis comparing current gas to historical data */
17
+ export interface GasSpikeAnalysis {
18
+ level: GasLevel;
19
+ percentile: number;
20
+ /** Ratio to 1h median (primary spike detection) */
21
+ vs1h: number;
22
+ /** Ratio to 4h median (short-term context) */
23
+ vs4h: number;
24
+ /** Ratio to 24h median (daily context) */
25
+ vs24h: number;
26
+ recommendation: string;
27
+ }
28
+ /** Full gas response from the gas oracle */
29
+ export interface GasOracleResponse {
30
+ chainId: number;
31
+ chainName: string;
32
+ timestamp: string;
33
+ blockNumber?: number;
34
+ source: "blocknative" | "rpc";
35
+ gasPrice: GasPrices;
36
+ eip1559?: Eip1559Data;
37
+ analysis: GasSpikeAnalysis;
38
+ cached: boolean;
39
+ cacheAge?: number;
40
+ }
41
+ /** Simplified gas data for UI display */
42
+ export interface GasPriceData {
43
+ chainId: number;
44
+ chainName: string;
45
+ /** Standard gas price in Gwei */
46
+ gasPriceGwei: string;
47
+ /** Base fee in Gwei (EIP-1559 chains) */
48
+ baseFeeGwei?: string;
49
+ /** Gas level classification */
50
+ level: GasLevel;
51
+ /** Whether gas is currently spiking (elevated, high, or spike) */
52
+ isSpike: boolean;
53
+ /** Human-readable recommendation */
54
+ recommendation: string;
55
+ /** Ratio to recent median (1 = normal, >1.5 = elevated) */
56
+ vsMedian: number;
57
+ /** Data source */
58
+ source: "blocknative" | "rpc";
59
+ /** Timestamp of the data */
60
+ timestamp: string;
61
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -28,7 +28,7 @@ function B3Provider({ theme = "light", children, accountOverride, environment, a
28
28
  // deprecated since v0.0.87
29
29
  toaster: _toaster, clientType = "rest", rpcUrls, partnerId, stripePublishableKey, onConnect, connectors, overrideDefaultConnectors = false, createClientReferenceId, enableTurnkey = false, defaultPermissions, }) {
30
30
  const setConfig = (0, configStore_1.useB3ConfigStore)(state => state.setConfig);
31
- // Initialize config store on mount - props are static and never change
31
+ // Initialize config store on mount
32
32
  (0, react_2.useEffect)(() => {
33
33
  setConfig({
34
34
  accountOverride,
@@ -42,7 +42,19 @@ toaster: _toaster, clientType = "rest", rpcUrls, partnerId, stripePublishableKey
42
42
  enableTurnkey,
43
43
  defaultPermissions,
44
44
  });
45
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
45
+ }, [
46
+ accountOverride,
47
+ environment,
48
+ automaticallySetFirstEoa,
49
+ theme,
50
+ clientType,
51
+ partnerId,
52
+ stripePublishableKey,
53
+ createClientReferenceId,
54
+ enableTurnkey,
55
+ defaultPermissions,
56
+ setConfig,
57
+ ]); // eslint-disable-line react-hooks/exhaustive-deps
46
58
  // Initialize Google Analytics on mount
47
59
  (0, react_2.useEffect)(() => {
48
60
  (0, analytics_1.loadGA4Script)();
@@ -10,8 +10,8 @@ const react_query_1 = require("@tanstack/react-query");
10
10
  const b3Chain_1 = require("../../../shared/constants/chains/b3Chain");
11
11
  const chains_1 = require("../../../shared/utils/chains");
12
12
  const thirdweb_1 = require("../../../shared/utils/thirdweb");
13
- const wallets_1 = require("thirdweb/wallets");
14
13
  const invariant_1 = __importDefault(require("invariant"));
14
+ const wallets_1 = require("thirdweb/wallets");
15
15
  function useTokenBalancesByChain({ address, chainsIds, enabled = true, }) {
16
16
  // Normalize chains to array
17
17
  const chainIds = Array.isArray(chainsIds) ? chainsIds : [chainsIds];
@@ -52,7 +52,9 @@ function useTokenBalancesByChain({ address, chainsIds, enabled = true, }) {
52
52
  staleTime: 30000, // Consider data fresh for 30 seconds
53
53
  gcTime: 5 * 60 * 1000, // Keep in cache for 5 minutes
54
54
  retry: 2, // Limit retries on failure
55
- structuralSharing: false,
55
+ // Enable structural sharing to prevent infinite loops
56
+ // This ensures we only get new references when data actually changes
57
+ structuralSharing: true,
56
58
  });
57
59
  return {
58
60
  nativeTokens: combinedData?.nativeTokens ?? [],
@@ -1,6 +1,8 @@
1
1
  import { components } from "../types/api";
2
2
  export declare const ANYSPEND_MAINNET_BASE_URL: string;
3
3
  export declare const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
4
+ export declare const GAS_ORACLE_BASE_URL: string;
5
+ export declare const RELAY_ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
4
6
  export declare const RELAY_SOL_ADDRESS = "11111111111111111111111111111111";
5
7
  export declare const RELAY_SOLANA_MAINNET_CHAIN_ID = 792703809;
6
8
  export declare const SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
@@ -1,6 +1,8 @@
1
1
  import { base } from "viem/chains";
2
2
  export const ANYSPEND_MAINNET_BASE_URL = process.env.NEXT_PUBLIC_ANYSPEND_BASE_URL || "https://mainnet.anyspend.com";
3
3
  export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
4
+ export const GAS_ORACLE_BASE_URL = process.env.NEXT_PUBLIC_GAS_ORACLE_URL || "https://gas-oracle.sean-430.workers.dev";
5
+ export const RELAY_ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
4
6
  export const RELAY_SOL_ADDRESS = "11111111111111111111111111111111";
5
7
  export const RELAY_SOLANA_MAINNET_CHAIN_ID = 792703809;
6
8
  export const SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
@@ -1,4 +1,5 @@
1
1
  export * from "./types/api";
2
+ export * from "./types/gas";
2
3
  export * from "./utils/address";
3
4
  export * from "./utils/chain";
4
5
  export * from "./utils/format";
@@ -8,5 +9,6 @@ export * from "./utils/string";
8
9
  export * from "./utils/token";
9
10
  export * from "./utils/validation";
10
11
  export * from "./constants";
12
+ export * from "./services/gas";
11
13
  export * from "./abis/abiUsdcBase";
12
14
  export * from "./abis/erc20Staking";