@b3dotfun/sdk 0.0.16-alpha.0 → 0.0.16-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -186,8 +186,6 @@ function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", recipient
186
186
  srcToken,
187
187
  ]);
188
188
  const { anyspendQuote, isLoadingAnyspendQuote } = (0, react_1.useAnyspendQuote)(isMainnet, getRelayQuoteRequest);
189
- // Get geo data and onramp options (after quote is available)
190
- const { geoData, isOnrampSupported } = (0, react_1.useGeoOnrampOptions)(isMainnet, anyspendQuote?.data?.currencyIn?.amountUsd || "0");
191
189
  const { orderAndTransactions: oat } = (0, react_1.useAnyspendOrderAndTransactions)(isMainnet, orderId);
192
190
  const onSelectOrder = (selectedOrderId) => {
193
191
  setActivePanel(PanelView.ORDER_DETAILS);
@@ -198,7 +196,9 @@ function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", recipient
198
196
  router.push(`${window.location.pathname}?${params.toString()}`);
199
197
  };
200
198
  const [srcAmount, setSrcAmount] = (0, react_4.useState)(null);
201
- const formattedSrcAmount = srcAmount ? (0, number_1.formatTokenAmount)(srcAmount, srcToken.decimals, 6, false) : null;
199
+ const formattedSrcAmount = srcAmount ? (0, number_1.formatUnits)(srcAmount.toString(), srcToken.decimals) : null;
200
+ // Get geo data and onramp options (after quote is available)
201
+ const { geoData, isOnrampSupported } = (0, react_1.useGeoOnrampOptions)(isMainnet, formattedSrcAmount || "0");
202
202
  // Update the selected src token to USDC and chain to base when the active tab is fiat,
203
203
  // also force not to update srcToken by setting dirtySelectSrcToken to true.
204
204
  (0, react_4.useEffect)(() => {
@@ -215,7 +215,8 @@ function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", recipient
215
215
  anyspendQuote.data.currencyIn?.currency?.decimals) {
216
216
  // Use toPrecision instead of toSignificant
217
217
  const amount = anyspendQuote.data.currencyIn.amount;
218
- setSrcAmount(BigInt(amount));
218
+ const roundUpAmount = (0, anyspend_1.roundUpUSDCBaseAmountToNearest)(amount);
219
+ setSrcAmount(BigInt(roundUpAmount));
219
220
  }
220
221
  else {
221
222
  setSrcAmount(null);
@@ -305,7 +306,7 @@ function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", recipient
305
306
  (0, invariant_1.default)(srcChainId === chains_1.base.id, "Selected src chain is not base");
306
307
  void createOnrampOrder({
307
308
  ...createOrderParams,
308
- srcFiatAmount: anyspendQuote?.data?.currencyIn?.amountUsd || "0",
309
+ srcFiatAmount: formattedSrcAmount || "0",
309
310
  onramp: {
310
311
  vendor: onramp.vendor,
311
312
  paymentMethod: onramp.paymentMethod,
@@ -394,7 +395,7 @@ function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", recipient
394
395
  opacity: hasMounted ? 1 : 0,
395
396
  y: hasMounted ? 0 : 20,
396
397
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
397
- }, transition: { duration: 0.3, delay: 0.3, ease: "easeInOut" }, className: "flex w-full flex-col gap-2", children: (0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", textColor: "text-white", disabled: isCreatingOrder || isLoadingAnyspendQuote || !anyspendQuote || !recipientAddress, onClick: () => handleConfirmOrder(), className: "relative w-full", children: isCreatingOrder ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "size-4 animate-spin" }), (0, jsx_runtime_1.jsx)("span", { children: "Creating order..." })] })) : isLoadingAnyspendQuote ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "size-4 animate-spin" }), (0, jsx_runtime_1.jsx)("span", { children: "Loading quote..." })] })) : anyspendQuote && recipientAddress ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { children: "Checkout" }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRightCircle, { className: "absolute right-0 top-1/2 size-6 -translate-y-1/2 opacity-70" })] })) : recipientAddress ? ("No quote found") : ("Please select a recipient") }) }) })] }) }), (0, jsx_runtime_1.jsx)(react_2.TabsContent, { value: "fiat", children: (0, jsx_runtime_1.jsx)("div", { className: "mt-6 flex w-full flex-col gap-6", children: (0, jsx_runtime_1.jsx)(PanelOnrampPayment_1.PanelOnrampPayment, { srcAmountOnRamp: anyspendQuote?.data?.currencyIn?.amountUsd || "0", recipientName: recipientEnsName, recipientAddress: recipientAddress, isMainnet: isMainnet, isBuyMode: false, selectedDstChainId: dstChainId, selectedDstToken: dstToken, anyspendQuote: anyspendQuote, globalAddress: currentWallet?.wallet?.address, onOrderCreated: (orderId) => setOrderId(orderId), onBack: () => setActiveTab("crypto"), orderType: orderType, nft: metadata.type === "mint_nft"
398
+ }, transition: { duration: 0.3, delay: 0.3, ease: "easeInOut" }, className: "flex w-full flex-col gap-2", children: (0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", textColor: "text-white", disabled: isCreatingOrder || isLoadingAnyspendQuote || !anyspendQuote || !recipientAddress, onClick: () => handleConfirmOrder(), className: "relative w-full", children: isCreatingOrder ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "size-4 animate-spin" }), (0, jsx_runtime_1.jsx)("span", { children: "Creating order..." })] })) : isLoadingAnyspendQuote ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "size-4 animate-spin" }), (0, jsx_runtime_1.jsx)("span", { children: "Loading quote..." })] })) : anyspendQuote && recipientAddress ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { children: "Checkout" }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRightCircle, { className: "absolute right-0 top-1/2 size-6 -translate-y-1/2 opacity-70" })] })) : recipientAddress ? ("No quote found") : ("Please select a recipient") }) }) })] }) }), (0, jsx_runtime_1.jsx)(react_2.TabsContent, { value: "fiat", children: (0, jsx_runtime_1.jsx)("div", { className: "mt-6 flex w-full flex-col gap-6", children: (0, jsx_runtime_1.jsx)(PanelOnrampPayment_1.PanelOnrampPayment, { srcAmountOnRamp: srcAmount ? (0, number_1.formatUnits)(srcAmount.toString(), constants_1.USDC_BASE.decimals) : "0", recipientName: recipientEnsName, recipientAddress: recipientAddress, isMainnet: isMainnet, isBuyMode: false, selectedDstChainId: dstChainId, selectedDstToken: dstToken, anyspendQuote: anyspendQuote, globalAddress: currentWallet?.wallet?.address, onOrderCreated: (orderId) => setOrderId(orderId), onBack: () => setActiveTab("crypto"), orderType: orderType, nft: metadata.type === "mint_nft"
398
399
  ? metadata.nftContract.type === "erc1155"
399
400
  ? {
400
401
  type: "erc1155",
@@ -11,7 +11,6 @@ const centerTruncate_1 = __importDefault(require("../../../../shared/utils/cente
11
11
  const invariant_1 = __importDefault(require("invariant"));
12
12
  const lucide_react_1 = require("lucide-react");
13
13
  const react_3 = require("motion/react");
14
- const react_4 = require("react");
15
14
  const sonner_1 = require("sonner");
16
15
  const AnySpendFingerprintWrapper_1 = require("../AnySpendFingerprintWrapper");
17
16
  function PanelOnrampPayment(props) {
@@ -20,17 +19,8 @@ function PanelOnrampPayment(props) {
20
19
  }
21
20
  function PanelOnrampPaymentInner(props) {
22
21
  const { srcAmountOnRamp, recipientAddress, isMainnet, isBuyMode, destinationTokenChainId, destinationTokenAddress, selectedDstChainId, selectedDstToken, anyspendQuote, globalAddress, onOrderCreated, onBack, orderType, nft, tournament, payload, recipientEnsName, recipientImageUrl, } = props;
23
- // Use a stable amount for geo onramp options to prevent unnecessary refetches
24
- const [stableAmountForGeo, setStableAmountForGeo] = (0, react_4.useState)(srcAmountOnRamp);
25
- const hasInitialized = (0, react_4.useRef)(false);
26
- // Only update the stable amount on first render or when explicitly needed
27
- (0, react_4.useEffect)(() => {
28
- if (!hasInitialized.current && srcAmountOnRamp) {
29
- setStableAmountForGeo(srcAmountOnRamp);
30
- hasInitialized.current = true;
31
- }
32
- }, [srcAmountOnRamp]);
33
- const { geoData, coinbaseOnrampOptions, coinbaseAvailablePaymentMethods, isStripeOnrampSupported, stripeWeb2Support, isLoading: isLoadingGeoOnramp, } = (0, react_1.useGeoOnrampOptions)(isMainnet, stableAmountForGeo);
22
+ console.log(`PanelOnrampPaymentInner:srcAmountOnRamp`, srcAmountOnRamp);
23
+ const { geoData, coinbaseOnrampOptions, coinbaseAvailablePaymentMethods, isStripeOnrampSupported, stripeWeb2Support, isLoading: isLoadingGeoOnramp, } = (0, react_1.useGeoOnrampOptions)(isMainnet, srcAmountOnRamp);
34
24
  const isLoading = isLoadingGeoOnramp;
35
25
  const { createOrder, isCreatingOrder } = (0, react_1.useAnyspendCreateOnrampOrder)({
36
26
  onSuccess: data => {
@@ -91,18 +91,9 @@ function StripePaymentForm({ order, onPaymentSuccess, }) {
91
91
  } }) })), error && ((0, jsx_runtime_1.jsx)("div", { className: "mt-4 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error })), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: !stripe || isProcessing, className: "mt-6 w-full rounded-xl bg-blue-600 px-4 py-3 font-medium text-white hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50", children: isProcessing ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-5 w-5 animate-spin" }), (0, jsx_runtime_1.jsx)("span", { children: "Processing..." })] })) : ((0, jsx_runtime_1.jsx)("span", { children: "Complete Payment" })) })] }) }) }));
92
92
  }
93
93
  function WebviewOnrampPaymentInner({ srcAmountOnRamp, recipientAddress, destinationToken, anyspendQuote, onPaymentSuccess, userId, partnerId, }) {
94
- const [stableAmountForGeo, setStableAmountForGeo] = (0, react_3.useState)(srcAmountOnRamp);
95
- const hasInitialized = (0, react_3.useRef)(false);
96
94
  const [createdOrder, setCreatedOrder] = (0, react_3.useState)(null);
97
95
  const orderCreationAttempted = (0, react_3.useRef)(false);
98
- // Only update the stable amount on first render or when explicitly needed
99
- (0, react_3.useEffect)(() => {
100
- if (!hasInitialized.current && srcAmountOnRamp) {
101
- setStableAmountForGeo(srcAmountOnRamp);
102
- hasInitialized.current = true;
103
- }
104
- }, [srcAmountOnRamp]);
105
- const { geoData, stripeWeb2Support, isLoading: isLoadingGeoOnramp } = (0, react_1.useGeoOnrampOptions)(true, stableAmountForGeo);
96
+ const { geoData, stripeWeb2Support, isLoading: isLoadingGeoOnramp } = (0, react_1.useGeoOnrampOptions)(true, srcAmountOnRamp);
106
97
  const { createOrder, isCreatingOrder } = (0, react_1.useAnyspendCreateOnrampOrder)({
107
98
  onSuccess: data => {
108
99
  setCreatedOrder(data.data);
@@ -11,3 +11,10 @@ export declare function escapeRegExp(string: string): string;
11
11
  * For example, roundUpUSDCBaseAmountToNearest("2663988") = "2670000"
12
12
  */
13
13
  export declare function roundUpUSDCBaseAmountToNearest(value: string): string;
14
+ /**
15
+ * Round up a USD amount to the nearest multiple of 0.01 USD
16
+ * @param value - The USD amount to round up
17
+ * @returns The rounded USD amount
18
+ * For example, roundUpUsdAmountToNearest("2.663988") = "2.67"
19
+ */
20
+ export declare function roundUpUsdAmountToNearest(value: string): string;
@@ -9,6 +9,7 @@ exports.mulpowToBig = mulpowToBig;
9
9
  exports.truncateValue = truncateValue;
10
10
  exports.escapeRegExp = escapeRegExp;
11
11
  exports.roundUpUSDCBaseAmountToNearest = roundUpUSDCBaseAmountToNearest;
12
+ exports.roundUpUsdAmountToNearest = roundUpUsdAmountToNearest;
12
13
  const big_js_1 = __importDefault(require("big.js"));
13
14
  const viem_1 = require("viem");
14
15
  // Configure Big.js to use exponential notation only for very large/small numbers
@@ -88,3 +89,20 @@ function roundUpUSDCBaseAmountToNearest(value) {
88
89
  const res = srcAmountBig.plus(divisor.minus(remainder)).toString();
89
90
  return res;
90
91
  }
92
+ /**
93
+ * Round up a USD amount to the nearest multiple of 0.01 USD
94
+ * @param value - The USD amount to round up
95
+ * @returns The rounded USD amount
96
+ * For example, roundUpUsdAmountToNearest("2.663988") = "2.67"
97
+ */
98
+ function roundUpUsdAmountToNearest(value) {
99
+ const divisor = new big_js_1.default(0.01); // Round to nearest 0.01 USD
100
+ const srcAmountBig = new big_js_1.default(value);
101
+ const remainder = srcAmountBig.mod(divisor);
102
+ // If remainder is already 0 (exactly divisible by 0.01), return the original amount
103
+ if (remainder.eq(0)) {
104
+ return value;
105
+ }
106
+ const res = srcAmountBig.plus(divisor.minus(remainder)).toString();
107
+ return res;
108
+ }
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { eqci, getDefaultToken } from "../../../anyspend/index.js";
2
+ import { eqci, getDefaultToken, roundUpUSDCBaseAmountToNearest } from "../../../anyspend/index.js";
3
3
  import { RELAY_ETH_ADDRESS, USDC_BASE } from "../../../anyspend/constants/index.js";
4
4
  import { useAnyspendCreateOnrampOrder, useAnyspendCreateOrder, useAnyspendOrderAndTransactions, useAnyspendQuote, useAnyspendTokenList, useGeoOnrampOptions, } from "../../../anyspend/react/index.js";
5
5
  import { Badge, Button, Dialog, DialogContent, Input, ShinyButton, Skeleton, StyleRoot, Tabs, TabsContent, TabsList, TabTrigger, TextShimmer, Tooltip, TooltipContent, TooltipTrigger, TransitionPanel, useAccountWallet, useHasMounted, useProfile, useRouter, useSearchParamsSSR, useTokenBalancesByChain, } from "../../../global-account/react/index.js";
6
6
  import { cn } from "../../../shared/utils/index.js";
7
7
  import centerTruncate from "../../../shared/utils/centerTruncate.js";
8
- import { formatTokenAmount } from "../../../shared/utils/number.js";
8
+ import { formatUnits } from "../../../shared/utils/number.js";
9
9
  import { simpleHashChainToChainName } from "../../../shared/utils/simplehash.js";
10
10
  import invariant from "invariant";
11
11
  import { ChevronRightCircle, Loader2 } from "lucide-react";
@@ -180,8 +180,6 @@ export function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", re
180
180
  srcToken,
181
181
  ]);
182
182
  const { anyspendQuote, isLoadingAnyspendQuote } = useAnyspendQuote(isMainnet, getRelayQuoteRequest);
183
- // Get geo data and onramp options (after quote is available)
184
- const { geoData, isOnrampSupported } = useGeoOnrampOptions(isMainnet, anyspendQuote?.data?.currencyIn?.amountUsd || "0");
185
183
  const { orderAndTransactions: oat } = useAnyspendOrderAndTransactions(isMainnet, orderId);
186
184
  const onSelectOrder = (selectedOrderId) => {
187
185
  setActivePanel(PanelView.ORDER_DETAILS);
@@ -192,7 +190,9 @@ export function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", re
192
190
  router.push(`${window.location.pathname}?${params.toString()}`);
193
191
  };
194
192
  const [srcAmount, setSrcAmount] = useState(null);
195
- const formattedSrcAmount = srcAmount ? formatTokenAmount(srcAmount, srcToken.decimals, 6, false) : null;
193
+ const formattedSrcAmount = srcAmount ? formatUnits(srcAmount.toString(), srcToken.decimals) : null;
194
+ // Get geo data and onramp options (after quote is available)
195
+ const { geoData, isOnrampSupported } = useGeoOnrampOptions(isMainnet, formattedSrcAmount || "0");
196
196
  // Update the selected src token to USDC and chain to base when the active tab is fiat,
197
197
  // also force not to update srcToken by setting dirtySelectSrcToken to true.
198
198
  useEffect(() => {
@@ -209,7 +209,8 @@ export function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", re
209
209
  anyspendQuote.data.currencyIn?.currency?.decimals) {
210
210
  // Use toPrecision instead of toSignificant
211
211
  const amount = anyspendQuote.data.currencyIn.amount;
212
- setSrcAmount(BigInt(amount));
212
+ const roundUpAmount = roundUpUSDCBaseAmountToNearest(amount);
213
+ setSrcAmount(BigInt(roundUpAmount));
213
214
  }
214
215
  else {
215
216
  setSrcAmount(null);
@@ -299,7 +300,7 @@ export function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", re
299
300
  invariant(srcChainId === base.id, "Selected src chain is not base");
300
301
  void createOnrampOrder({
301
302
  ...createOrderParams,
302
- srcFiatAmount: anyspendQuote?.data?.currencyIn?.amountUsd || "0",
303
+ srcFiatAmount: formattedSrcAmount || "0",
303
304
  onramp: {
304
305
  vendor: onramp.vendor,
305
306
  paymentMethod: onramp.paymentMethod,
@@ -388,7 +389,7 @@ export function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", re
388
389
  opacity: hasMounted ? 1 : 0,
389
390
  y: hasMounted ? 0 : 20,
390
391
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
391
- }, transition: { duration: 0.3, delay: 0.3, ease: "easeInOut" }, className: "flex w-full flex-col gap-2", children: _jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", textColor: "text-white", disabled: isCreatingOrder || isLoadingAnyspendQuote || !anyspendQuote || !recipientAddress, onClick: () => handleConfirmOrder(), className: "relative w-full", children: isCreatingOrder ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), _jsx("span", { children: "Creating order..." })] })) : isLoadingAnyspendQuote ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), _jsx("span", { children: "Loading quote..." })] })) : anyspendQuote && recipientAddress ? (_jsxs(_Fragment, { children: [_jsx("span", { children: "Checkout" }), _jsx(ChevronRightCircle, { className: "absolute right-0 top-1/2 size-6 -translate-y-1/2 opacity-70" })] })) : recipientAddress ? ("No quote found") : ("Please select a recipient") }) }) })] }) }), _jsx(TabsContent, { value: "fiat", children: _jsx("div", { className: "mt-6 flex w-full flex-col gap-6", children: _jsx(PanelOnrampPayment, { srcAmountOnRamp: anyspendQuote?.data?.currencyIn?.amountUsd || "0", recipientName: recipientEnsName, recipientAddress: recipientAddress, isMainnet: isMainnet, isBuyMode: false, selectedDstChainId: dstChainId, selectedDstToken: dstToken, anyspendQuote: anyspendQuote, globalAddress: currentWallet?.wallet?.address, onOrderCreated: (orderId) => setOrderId(orderId), onBack: () => setActiveTab("crypto"), orderType: orderType, nft: metadata.type === "mint_nft"
392
+ }, transition: { duration: 0.3, delay: 0.3, ease: "easeInOut" }, className: "flex w-full flex-col gap-2", children: _jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", textColor: "text-white", disabled: isCreatingOrder || isLoadingAnyspendQuote || !anyspendQuote || !recipientAddress, onClick: () => handleConfirmOrder(), className: "relative w-full", children: isCreatingOrder ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), _jsx("span", { children: "Creating order..." })] })) : isLoadingAnyspendQuote ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), _jsx("span", { children: "Loading quote..." })] })) : anyspendQuote && recipientAddress ? (_jsxs(_Fragment, { children: [_jsx("span", { children: "Checkout" }), _jsx(ChevronRightCircle, { className: "absolute right-0 top-1/2 size-6 -translate-y-1/2 opacity-70" })] })) : recipientAddress ? ("No quote found") : ("Please select a recipient") }) }) })] }) }), _jsx(TabsContent, { value: "fiat", children: _jsx("div", { className: "mt-6 flex w-full flex-col gap-6", children: _jsx(PanelOnrampPayment, { srcAmountOnRamp: srcAmount ? formatUnits(srcAmount.toString(), USDC_BASE.decimals) : "0", recipientName: recipientEnsName, recipientAddress: recipientAddress, isMainnet: isMainnet, isBuyMode: false, selectedDstChainId: dstChainId, selectedDstToken: dstToken, anyspendQuote: anyspendQuote, globalAddress: currentWallet?.wallet?.address, onOrderCreated: (orderId) => setOrderId(orderId), onBack: () => setActiveTab("crypto"), orderType: orderType, nft: metadata.type === "mint_nft"
392
393
  ? metadata.nftContract.type === "erc1155"
393
394
  ? {
394
395
  type: "erc1155",
@@ -5,7 +5,6 @@ import centerTruncate from "../../../../shared/utils/centerTruncate.js";
5
5
  import invariant from "invariant";
6
6
  import { ChevronLeft, ChevronRight, Landmark, Loader2 } from "lucide-react";
7
7
  import { motion } from "motion/react";
8
- import { useEffect, useRef, useState } from "react";
9
8
  import { toast } from "sonner";
10
9
  import { AnySpendFingerprintWrapper, getFingerprintConfig } from "../AnySpendFingerprintWrapper.js";
11
10
  export function PanelOnrampPayment(props) {
@@ -14,17 +13,8 @@ export function PanelOnrampPayment(props) {
14
13
  }
15
14
  function PanelOnrampPaymentInner(props) {
16
15
  const { srcAmountOnRamp, recipientAddress, isMainnet, isBuyMode, destinationTokenChainId, destinationTokenAddress, selectedDstChainId, selectedDstToken, anyspendQuote, globalAddress, onOrderCreated, onBack, orderType, nft, tournament, payload, recipientEnsName, recipientImageUrl, } = props;
17
- // Use a stable amount for geo onramp options to prevent unnecessary refetches
18
- const [stableAmountForGeo, setStableAmountForGeo] = useState(srcAmountOnRamp);
19
- const hasInitialized = useRef(false);
20
- // Only update the stable amount on first render or when explicitly needed
21
- useEffect(() => {
22
- if (!hasInitialized.current && srcAmountOnRamp) {
23
- setStableAmountForGeo(srcAmountOnRamp);
24
- hasInitialized.current = true;
25
- }
26
- }, [srcAmountOnRamp]);
27
- const { geoData, coinbaseOnrampOptions, coinbaseAvailablePaymentMethods, isStripeOnrampSupported, stripeWeb2Support, isLoading: isLoadingGeoOnramp, } = useGeoOnrampOptions(isMainnet, stableAmountForGeo);
16
+ console.log(`PanelOnrampPaymentInner:srcAmountOnRamp`, srcAmountOnRamp);
17
+ const { geoData, coinbaseOnrampOptions, coinbaseAvailablePaymentMethods, isStripeOnrampSupported, stripeWeb2Support, isLoading: isLoadingGeoOnramp, } = useGeoOnrampOptions(isMainnet, srcAmountOnRamp);
28
18
  const isLoading = isLoadingGeoOnramp;
29
19
  const { createOrder, isCreatingOrder } = useAnyspendCreateOnrampOrder({
30
20
  onSuccess: data => {
@@ -85,18 +85,9 @@ function StripePaymentForm({ order, onPaymentSuccess, }) {
85
85
  } }) })), error && (_jsx("div", { className: "mt-4 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error })), _jsx("button", { type: "submit", disabled: !stripe || isProcessing, className: "mt-6 w-full rounded-xl bg-blue-600 px-4 py-3 font-medium text-white hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50", children: isProcessing ? (_jsxs("div", { className: "flex items-center justify-center gap-2", children: [_jsx(Loader2, { className: "h-5 w-5 animate-spin" }), _jsx("span", { children: "Processing..." })] })) : (_jsx("span", { children: "Complete Payment" })) })] }) }) }));
86
86
  }
87
87
  function WebviewOnrampPaymentInner({ srcAmountOnRamp, recipientAddress, destinationToken, anyspendQuote, onPaymentSuccess, userId, partnerId, }) {
88
- const [stableAmountForGeo, setStableAmountForGeo] = useState(srcAmountOnRamp);
89
- const hasInitialized = useRef(false);
90
88
  const [createdOrder, setCreatedOrder] = useState(null);
91
89
  const orderCreationAttempted = useRef(false);
92
- // Only update the stable amount on first render or when explicitly needed
93
- useEffect(() => {
94
- if (!hasInitialized.current && srcAmountOnRamp) {
95
- setStableAmountForGeo(srcAmountOnRamp);
96
- hasInitialized.current = true;
97
- }
98
- }, [srcAmountOnRamp]);
99
- const { geoData, stripeWeb2Support, isLoading: isLoadingGeoOnramp } = useGeoOnrampOptions(true, stableAmountForGeo);
90
+ const { geoData, stripeWeb2Support, isLoading: isLoadingGeoOnramp } = useGeoOnrampOptions(true, srcAmountOnRamp);
100
91
  const { createOrder, isCreatingOrder } = useAnyspendCreateOnrampOrder({
101
92
  onSuccess: data => {
102
93
  setCreatedOrder(data.data);
@@ -11,3 +11,10 @@ export declare function escapeRegExp(string: string): string;
11
11
  * For example, roundUpUSDCBaseAmountToNearest("2663988") = "2670000"
12
12
  */
13
13
  export declare function roundUpUSDCBaseAmountToNearest(value: string): string;
14
+ /**
15
+ * Round up a USD amount to the nearest multiple of 0.01 USD
16
+ * @param value - The USD amount to round up
17
+ * @returns The rounded USD amount
18
+ * For example, roundUpUsdAmountToNearest("2.663988") = "2.67"
19
+ */
20
+ export declare function roundUpUsdAmountToNearest(value: string): string;
@@ -77,3 +77,20 @@ export function roundUpUSDCBaseAmountToNearest(value) {
77
77
  const res = srcAmountBig.plus(divisor.minus(remainder)).toString();
78
78
  return res;
79
79
  }
80
+ /**
81
+ * Round up a USD amount to the nearest multiple of 0.01 USD
82
+ * @param value - The USD amount to round up
83
+ * @returns The rounded USD amount
84
+ * For example, roundUpUsdAmountToNearest("2.663988") = "2.67"
85
+ */
86
+ export function roundUpUsdAmountToNearest(value) {
87
+ const divisor = new Big(0.01); // Round to nearest 0.01 USD
88
+ const srcAmountBig = new Big(value);
89
+ const remainder = srcAmountBig.mod(divisor);
90
+ // If remainder is already 0 (exactly divisible by 0.01), return the original amount
91
+ if (remainder.eq(0)) {
92
+ return value;
93
+ }
94
+ const res = srcAmountBig.plus(divisor.minus(remainder)).toString();
95
+ return res;
96
+ }
@@ -11,3 +11,10 @@ export declare function escapeRegExp(string: string): string;
11
11
  * For example, roundUpUSDCBaseAmountToNearest("2663988") = "2670000"
12
12
  */
13
13
  export declare function roundUpUSDCBaseAmountToNearest(value: string): string;
14
+ /**
15
+ * Round up a USD amount to the nearest multiple of 0.01 USD
16
+ * @param value - The USD amount to round up
17
+ * @returns The rounded USD amount
18
+ * For example, roundUpUsdAmountToNearest("2.663988") = "2.67"
19
+ */
20
+ export declare function roundUpUsdAmountToNearest(value: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.0.16-alpha.0",
3
+ "version": "0.0.16-alpha.2",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -1,4 +1,4 @@
1
- import { eqci, getDefaultToken } from "@b3dotfun/sdk/anyspend";
1
+ import { eqci, getDefaultToken, roundUpUSDCBaseAmountToNearest } from "@b3dotfun/sdk/anyspend";
2
2
  import { RELAY_ETH_ADDRESS, USDC_BASE } from "@b3dotfun/sdk/anyspend/constants";
3
3
  import {
4
4
  CreateOrderParams,
@@ -38,7 +38,7 @@ import {
38
38
  } from "@b3dotfun/sdk/global-account/react";
39
39
  import { cn } from "@b3dotfun/sdk/shared/utils";
40
40
  import centerTruncate from "@b3dotfun/sdk/shared/utils/centerTruncate";
41
- import { formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
41
+ import { formatUnits } from "@b3dotfun/sdk/shared/utils/number";
42
42
  import { simpleHashChainToChainName } from "@b3dotfun/sdk/shared/utils/simplehash";
43
43
  import invariant from "invariant";
44
44
  import { ChevronRightCircle, Loader2 } from "lucide-react";
@@ -299,12 +299,6 @@ export function AnySpendCustom({
299
299
  ]);
300
300
  const { anyspendQuote, isLoadingAnyspendQuote } = useAnyspendQuote(isMainnet, getRelayQuoteRequest);
301
301
 
302
- // Get geo data and onramp options (after quote is available)
303
- const { geoData, isOnrampSupported } = useGeoOnrampOptions(
304
- isMainnet,
305
- anyspendQuote?.data?.currencyIn?.amountUsd || "0",
306
- );
307
-
308
302
  const { orderAndTransactions: oat } = useAnyspendOrderAndTransactions(isMainnet, orderId);
309
303
 
310
304
  const onSelectOrder = (selectedOrderId: string) => {
@@ -317,7 +311,10 @@ export function AnySpendCustom({
317
311
  };
318
312
 
319
313
  const [srcAmount, setSrcAmount] = useState<bigint | null>(null);
320
- const formattedSrcAmount = srcAmount ? formatTokenAmount(srcAmount, srcToken.decimals, 6, false) : null;
314
+ const formattedSrcAmount = srcAmount ? formatUnits(srcAmount.toString(), srcToken.decimals) : null;
315
+
316
+ // Get geo data and onramp options (after quote is available)
317
+ const { geoData, isOnrampSupported } = useGeoOnrampOptions(isMainnet, formattedSrcAmount || "0");
321
318
 
322
319
  // Update the selected src token to USDC and chain to base when the active tab is fiat,
323
320
  // also force not to update srcToken by setting dirtySelectSrcToken to true.
@@ -338,7 +335,8 @@ export function AnySpendCustom({
338
335
  ) {
339
336
  // Use toPrecision instead of toSignificant
340
337
  const amount = anyspendQuote.data.currencyIn.amount;
341
- setSrcAmount(BigInt(amount));
338
+ const roundUpAmount = roundUpUSDCBaseAmountToNearest(amount);
339
+ setSrcAmount(BigInt(roundUpAmount));
342
340
  } else {
343
341
  setSrcAmount(null);
344
342
  }
@@ -440,7 +438,7 @@ export function AnySpendCustom({
440
438
  invariant(srcChainId === base.id, "Selected src chain is not base");
441
439
  void createOnrampOrder({
442
440
  ...createOrderParams,
443
- srcFiatAmount: anyspendQuote?.data?.currencyIn?.amountUsd || "0",
441
+ srcFiatAmount: formattedSrcAmount || "0",
444
442
  onramp: {
445
443
  vendor: onramp.vendor,
446
444
  paymentMethod: onramp.paymentMethod,
@@ -816,7 +814,7 @@ export function AnySpendCustom({
816
814
  <TabsContent value="fiat">
817
815
  <div className="mt-6 flex w-full flex-col gap-6">
818
816
  <PanelOnrampPayment
819
- srcAmountOnRamp={anyspendQuote?.data?.currencyIn?.amountUsd || "0"}
817
+ srcAmountOnRamp={srcAmount ? formatUnits(srcAmount.toString(), USDC_BASE.decimals) : "0"}
820
818
  recipientName={recipientEnsName}
821
819
  recipientAddress={recipientAddress}
822
820
  isMainnet={isMainnet}
@@ -6,7 +6,6 @@ import centerTruncate from "@b3dotfun/sdk/shared/utils/centerTruncate";
6
6
  import invariant from "invariant";
7
7
  import { ChevronLeft, ChevronRight, Landmark, Loader2 } from "lucide-react";
8
8
  import { motion } from "motion/react";
9
- import { useEffect, useRef, useState } from "react";
10
9
  import { toast } from "sonner";
11
10
  import { AnySpendFingerprintWrapper, getFingerprintConfig } from "../AnySpendFingerprintWrapper";
12
11
 
@@ -64,17 +63,7 @@ function PanelOnrampPaymentInner(props: PanelOnrampPaymentProps) {
64
63
  recipientImageUrl,
65
64
  } = props;
66
65
 
67
- // Use a stable amount for geo onramp options to prevent unnecessary refetches
68
- const [stableAmountForGeo, setStableAmountForGeo] = useState(srcAmountOnRamp);
69
- const hasInitialized = useRef(false);
70
-
71
- // Only update the stable amount on first render or when explicitly needed
72
- useEffect(() => {
73
- if (!hasInitialized.current && srcAmountOnRamp) {
74
- setStableAmountForGeo(srcAmountOnRamp);
75
- hasInitialized.current = true;
76
- }
77
- }, [srcAmountOnRamp]);
66
+ console.log(`PanelOnrampPaymentInner:srcAmountOnRamp`, srcAmountOnRamp);
78
67
 
79
68
  const {
80
69
  geoData,
@@ -83,7 +72,7 @@ function PanelOnrampPaymentInner(props: PanelOnrampPaymentProps) {
83
72
  isStripeOnrampSupported,
84
73
  stripeWeb2Support,
85
74
  isLoading: isLoadingGeoOnramp,
86
- } = useGeoOnrampOptions(isMainnet, stableAmountForGeo);
75
+ } = useGeoOnrampOptions(isMainnet, srcAmountOnRamp);
87
76
 
88
77
  const isLoading = isLoadingGeoOnramp;
89
78
 
@@ -159,20 +159,10 @@ function WebviewOnrampPaymentInner({
159
159
  userId,
160
160
  partnerId,
161
161
  }: WebviewOnrampPaymentProps) {
162
- const [stableAmountForGeo, setStableAmountForGeo] = useState(srcAmountOnRamp);
163
- const hasInitialized = useRef(false);
164
162
  const [createdOrder, setCreatedOrder] = useState<components["schemas"]["Order"] | null>(null);
165
163
  const orderCreationAttempted = useRef(false);
166
164
 
167
- // Only update the stable amount on first render or when explicitly needed
168
- useEffect(() => {
169
- if (!hasInitialized.current && srcAmountOnRamp) {
170
- setStableAmountForGeo(srcAmountOnRamp);
171
- hasInitialized.current = true;
172
- }
173
- }, [srcAmountOnRamp]);
174
-
175
- const { geoData, stripeWeb2Support, isLoading: isLoadingGeoOnramp } = useGeoOnrampOptions(true, stableAmountForGeo);
165
+ const { geoData, stripeWeb2Support, isLoading: isLoadingGeoOnramp } = useGeoOnrampOptions(true, srcAmountOnRamp);
176
166
 
177
167
  const { createOrder, isCreatingOrder } = useAnyspendCreateOnrampOrder({
178
168
  onSuccess: data => {
@@ -91,3 +91,21 @@ export function roundUpUSDCBaseAmountToNearest(value: string): string {
91
91
  const res = srcAmountBig.plus(divisor.minus(remainder)).toString();
92
92
  return res;
93
93
  }
94
+
95
+ /**
96
+ * Round up a USD amount to the nearest multiple of 0.01 USD
97
+ * @param value - The USD amount to round up
98
+ * @returns The rounded USD amount
99
+ * For example, roundUpUsdAmountToNearest("2.663988") = "2.67"
100
+ */
101
+ export function roundUpUsdAmountToNearest(value: string): string {
102
+ const divisor = new Big(0.01); // Round to nearest 0.01 USD
103
+ const srcAmountBig = new Big(value);
104
+ const remainder = srcAmountBig.mod(divisor);
105
+ // If remainder is already 0 (exactly divisible by 0.01), return the original amount
106
+ if (remainder.eq(0)) {
107
+ return value;
108
+ }
109
+ const res = srcAmountBig.plus(divisor.minus(remainder)).toString();
110
+ return res;
111
+ }