@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.
- package/dist/cjs/anyspend/react/components/AnySpendCustom.js +7 -6
- package/dist/cjs/anyspend/react/components/common/PanelOnrampPayment.js +2 -12
- package/dist/cjs/anyspend/react/components/webview/WebviewOnrampPayment.js +1 -10
- package/dist/cjs/anyspend/utils/number.d.ts +7 -0
- package/dist/cjs/anyspend/utils/number.js +18 -0
- package/dist/esm/anyspend/react/components/AnySpendCustom.js +9 -8
- package/dist/esm/anyspend/react/components/common/PanelOnrampPayment.js +2 -12
- package/dist/esm/anyspend/react/components/webview/WebviewOnrampPayment.js +1 -10
- package/dist/esm/anyspend/utils/number.d.ts +7 -0
- package/dist/esm/anyspend/utils/number.js +17 -0
- package/dist/types/anyspend/utils/number.d.ts +7 -0
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpendCustom.tsx +10 -12
- package/src/anyspend/react/components/common/PanelOnrampPayment.tsx +2 -13
- package/src/anyspend/react/components/webview/WebviewOnrampPayment.tsx +1 -11
- package/src/anyspend/utils/number.ts +18 -0
|
@@ -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.
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
24
|
-
const
|
|
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
|
-
|
|
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 {
|
|
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 ?
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
18
|
-
const
|
|
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
|
-
|
|
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,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 {
|
|
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 ?
|
|
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
|
-
|
|
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:
|
|
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={
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
+
}
|