@b3dotfun/sdk 0.0.40-alpha.7 → 0.0.40-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.
- package/dist/cjs/anyspend/react/components/AnySpend.js +1 -1
- package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +1 -1
- package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +38 -36
- package/dist/cjs/anyspend/react/components/common/PanelOnramp.d.ts +3 -1
- package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +7 -6
- package/dist/cjs/anyspend/react/contexts/FeatureFlagsContext.d.ts +11 -0
- package/dist/cjs/anyspend/react/contexts/FeatureFlagsContext.js +21 -0
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +1 -65
- package/dist/cjs/anyspend/react/providers/AnyspendProvider.d.ts +5 -2
- package/dist/cjs/anyspend/react/providers/AnyspendProvider.js +5 -3
- package/dist/cjs/anyspend/react/providers/index.d.ts +1 -0
- package/dist/cjs/anyspend/react/providers/index.js +3 -0
- package/dist/cjs/anyspend/types/api_req_res.d.ts +8 -1
- package/dist/esm/anyspend/react/components/AnySpend.js +1 -1
- package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +1 -1
- package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +38 -36
- package/dist/esm/anyspend/react/components/common/PanelOnramp.d.ts +3 -1
- package/dist/esm/anyspend/react/components/common/PanelOnramp.js +7 -6
- package/dist/esm/anyspend/react/contexts/FeatureFlagsContext.d.ts +11 -0
- package/dist/esm/anyspend/react/contexts/FeatureFlagsContext.js +17 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +1 -65
- package/dist/esm/anyspend/react/providers/AnyspendProvider.d.ts +5 -2
- package/dist/esm/anyspend/react/providers/AnyspendProvider.js +5 -3
- package/dist/esm/anyspend/react/providers/index.d.ts +1 -0
- package/dist/esm/anyspend/react/providers/index.js +1 -0
- package/dist/esm/anyspend/types/api_req_res.d.ts +8 -1
- package/dist/types/anyspend/react/components/common/PanelOnramp.d.ts +3 -1
- package/dist/types/anyspend/react/contexts/FeatureFlagsContext.d.ts +11 -0
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +1 -65
- package/dist/types/anyspend/react/providers/AnyspendProvider.d.ts +5 -2
- package/dist/types/anyspend/react/providers/index.d.ts +1 -0
- package/dist/types/anyspend/types/api_req_res.d.ts +8 -1
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpend.tsx +1 -0
- package/src/anyspend/react/components/AnyspendDepositHype.tsx +1 -0
- package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +55 -45
- package/src/anyspend/react/components/common/PanelOnramp.tsx +21 -15
- package/src/anyspend/react/contexts/FeatureFlagsContext.tsx +34 -0
- package/src/anyspend/react/providers/AnyspendProvider.tsx +11 -6
- package/src/anyspend/react/providers/index.ts +1 -0
- package/src/anyspend/types/api_req_res.ts +10 -1
|
@@ -7,9 +7,11 @@ import { formatAddress } from "../../../../shared/utils/formatAddress.js";
|
|
|
7
7
|
import { ChevronRight, Wallet } from "lucide-react";
|
|
8
8
|
import { useRef } from "react";
|
|
9
9
|
import { toast } from "sonner";
|
|
10
|
+
import { useFeatureFlags } from "../../contexts/FeatureFlagsContext.js";
|
|
10
11
|
import { FiatPaymentMethod } from "./FiatPaymentMethod.js";
|
|
11
12
|
import { OrderTokenAmountFiat } from "./OrderTokenAmountFiat.js";
|
|
12
|
-
export function PanelOnramp({ srcAmountOnRamp, setSrcAmountOnRamp, selectedPaymentMethod, setActivePanel, _recipientAddress, destinationToken, destinationChainId, destinationAmount, onDestinationTokenChange, onDestinationChainChange, fiatPaymentMethodIndex, recipientSelectionPanelIndex, dstTokenSymbol, hideDstToken = false, }) {
|
|
13
|
+
export function PanelOnramp({ srcAmountOnRamp, setSrcAmountOnRamp, selectedPaymentMethod, setActivePanel, _recipientAddress, destinationToken, destinationChainId, destinationAmount, onDestinationTokenChange, onDestinationChainChange, fiatPaymentMethodIndex, recipientSelectionPanelIndex, dstTokenSymbol, hideDstToken = false, anyspendQuote, }) {
|
|
14
|
+
const featureFlags = useFeatureFlags();
|
|
13
15
|
// Get geo-based onramp options to access fee information
|
|
14
16
|
const { stripeWeb2Support } = useGeoOnrampOptions(srcAmountOnRamp);
|
|
15
17
|
// Helper function to get fees from API data
|
|
@@ -70,9 +72,8 @@ export function PanelOnramp({ srcAmountOnRamp, setSrcAmountOnRamp, selectedPayme
|
|
|
70
72
|
width: `${Math.max(50, srcAmountOnRamp.length * 34)}px`,
|
|
71
73
|
} })] }) }), _jsx("div", { className: cn("mx-auto mb-6 inline-grid grid-cols-4 gap-2", hideDstToken && "mb-0"), children: ["5", "10", "20", "25"].map(value => (_jsxs("button", { onClick: () => handleQuickAmount(value), className: `bg-as-surface-secondary border-as-border-secondary hover:border-as-border-secondary h-7 w-14 rounded-lg border text-sm font-medium transition-all duration-200 ${srcAmountOnRamp === value
|
|
72
74
|
? "border-as-border-secondary bg-as-surface-secondary"
|
|
73
|
-
: "bg-as-surface-secondary hover:bg-as-surface-secondary"}`, children: ["$", value] }, value))) }), destinationToken && destinationChainId && !hideDstToken && (_jsx(OrderTokenAmountFiat, { address: _recipientAddress, context: "to", inputValue: destinationAmount || "0", onChangeInput: () => { }, chainId: destinationChainId, setChainId: onDestinationChainChange || (() => { }), token: destinationToken, setToken: onDestinationTokenChange || (() => { }) }))] }), _jsxs("div", { className: "border-as-border-secondary bg-as-surface-secondary mt-4 flex w-full flex-col gap-3 rounded-xl border p-4", children: [_jsxs("div", { className: "flex w-full items-center justify-between gap-2", children: [_jsx("span", { className: "text-as-tertiarry flex items-center text-sm", children: "Recipient" }), _recipientAddress ? (_jsxs("button", { className: "text-as-tertiarry flex h-7 items-center gap-1 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(recipientSelectionPanelIndex), children: [_jsx("span", { className: "text-sm", children: recipientName ? formatUsername(recipientName) : formatAddress(_recipientAddress) }), _jsx(ChevronRight, { size: 16 })] })) : (_jsxs("button", { className: "text-as-tertiarry flex h-7 items-center gap-1 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(5), children: [_jsx(Wallet, { className: "text-as-brand", size: 16 }), "Select recipient", _jsx(ChevronRight, { size: 16 })] }))] }), _jsx("div", { className: "divider w-full" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-as-tertiarry text-sm", children: "Expected to receive" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("span", { className: "text-as-primary font-semibold", children: [destinationAmount || "0", " ", dstTokenSymbol || destinationToken?.symbol || ""] }), _jsxs("span", { className: "text-as-tertiarry text-sm", children: ["on ", destinationChainId ? ALL_CHAINS[destinationChainId]?.name : ""] }), destinationToken && destinationChainId && destinationToken.metadata?.logoURI && (_jsx("img", { src: ALL_CHAINS[destinationChainId]?.logoUrl, alt: "Chain", className: "h-4 w-4 rounded-full" }))] })] }), _jsx("div", { className: "divider w-full" }), _jsx("div", { className: "", children:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
})() }) })] })] }));
|
|
75
|
+
: "bg-as-surface-secondary hover:bg-as-surface-secondary"}`, children: ["$", value] }, value))) }), destinationToken && destinationChainId && !hideDstToken && (_jsx(OrderTokenAmountFiat, { address: _recipientAddress, context: "to", inputValue: destinationAmount || "0", onChangeInput: () => { }, chainId: destinationChainId, setChainId: onDestinationChainChange || (() => { }), token: destinationToken, setToken: onDestinationTokenChange || (() => { }) }))] }), _jsxs("div", { className: "border-as-border-secondary bg-as-surface-secondary mt-4 flex w-full flex-col gap-3 rounded-xl border p-4", children: [_jsxs("div", { className: "flex w-full items-center justify-between gap-2", children: [_jsx("span", { className: "text-as-tertiarry flex items-center text-sm", children: "Recipient" }), _recipientAddress ? (_jsxs("button", { className: "text-as-tertiarry flex h-7 items-center gap-1 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(recipientSelectionPanelIndex), children: [_jsx("span", { className: "text-sm", children: recipientName ? formatUsername(recipientName) : formatAddress(_recipientAddress) }), _jsx(ChevronRight, { size: 16 })] })) : (_jsxs("button", { className: "text-as-tertiarry flex h-7 items-center gap-1 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(5), children: [_jsx(Wallet, { className: "text-as-brand", size: 16 }), "Select recipient", _jsx(ChevronRight, { size: 16 })] }))] }), _jsx("div", { className: "divider w-full" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-as-tertiarry text-sm", children: "Expected to receive" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("span", { className: "text-as-primary font-semibold", children: [destinationAmount || "0", " ", dstTokenSymbol || destinationToken?.symbol || ""] }), _jsxs("span", { className: "text-as-tertiarry text-sm", children: ["on ", destinationChainId ? ALL_CHAINS[destinationChainId]?.name : ""] }), destinationToken && destinationChainId && destinationToken.metadata?.logoURI && (_jsx("img", { src: ALL_CHAINS[destinationChainId]?.logoUrl, alt: "Chain", className: "h-4 w-4 rounded-full" }))] })] }), _jsx("div", { className: "divider w-full" }), _jsx("div", { className: "", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-as-tertiarry text-sm", children: (() => {
|
|
76
|
+
const fee = getFeeFromApi(selectedPaymentMethod || FiatPaymentMethod.NONE);
|
|
77
|
+
return fee !== null ? `Total (included $${fee.toFixed(2)} fee)` : "Total";
|
|
78
|
+
})() }), featureFlags.showPoints && anyspendQuote?.data?.pointsAmount && anyspendQuote.data.pointsAmount > 0 && (_jsxs("span", { className: "text-as-brand text-sm font-medium", children: ["+", anyspendQuote.data.pointsAmount.toLocaleString(), " pts"] }, `points-${anyspendQuote.data.pointsAmount}`))] }), _jsxs("span", { className: "text-as-primary font-semibold", children: ["$", getTotalAmount(selectedPaymentMethod || FiatPaymentMethod.NONE).toFixed(2)] })] }) })] })] }));
|
|
78
79
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
export interface FeatureFlags {
|
|
3
|
+
showPoints?: boolean;
|
|
4
|
+
}
|
|
5
|
+
interface FeatureFlagsProviderProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
featureFlags?: FeatureFlags;
|
|
8
|
+
}
|
|
9
|
+
export declare function FeatureFlagsProvider({ children, featureFlags }: FeatureFlagsProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function useFeatureFlags(): FeatureFlags;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext } from "react";
|
|
4
|
+
const FeatureFlagsContext = createContext(undefined);
|
|
5
|
+
const defaultFeatureFlags = {
|
|
6
|
+
showPoints: false,
|
|
7
|
+
};
|
|
8
|
+
export function FeatureFlagsProvider({ children, featureFlags = defaultFeatureFlags }) {
|
|
9
|
+
return _jsx(FeatureFlagsContext.Provider, { value: { featureFlags }, children: children });
|
|
10
|
+
}
|
|
11
|
+
export function useFeatureFlags() {
|
|
12
|
+
const context = useContext(FeatureFlagsContext);
|
|
13
|
+
if (!context) {
|
|
14
|
+
return defaultFeatureFlags;
|
|
15
|
+
}
|
|
16
|
+
return context.featureFlags;
|
|
17
|
+
}
|
|
@@ -78,71 +78,7 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
78
78
|
globalAddress: string | undefined;
|
|
79
79
|
hasEnoughBalance: boolean;
|
|
80
80
|
isBalanceLoading: boolean;
|
|
81
|
-
anyspendQuote:
|
|
82
|
-
success: boolean;
|
|
83
|
-
message: string;
|
|
84
|
-
data: {
|
|
85
|
-
operation?: string;
|
|
86
|
-
sender?: string;
|
|
87
|
-
recipient?: string;
|
|
88
|
-
currencyIn?: {
|
|
89
|
-
currency?: {
|
|
90
|
-
chainId?: number;
|
|
91
|
-
address?: string;
|
|
92
|
-
symbol?: string;
|
|
93
|
-
name?: string;
|
|
94
|
-
decimals?: number;
|
|
95
|
-
metadata?: {
|
|
96
|
-
logoURI?: string;
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
amount?: string;
|
|
100
|
-
amountFormatted?: string;
|
|
101
|
-
amountUsd?: string;
|
|
102
|
-
minimumAmount?: string;
|
|
103
|
-
};
|
|
104
|
-
currencyOut?: {
|
|
105
|
-
currency?: {
|
|
106
|
-
chainId?: number;
|
|
107
|
-
address?: string;
|
|
108
|
-
symbol?: string;
|
|
109
|
-
name?: string;
|
|
110
|
-
decimals?: number;
|
|
111
|
-
metadata?: {
|
|
112
|
-
logoURI?: string;
|
|
113
|
-
};
|
|
114
|
-
};
|
|
115
|
-
amount?: string;
|
|
116
|
-
amountFormatted?: string;
|
|
117
|
-
amountUsd?: string;
|
|
118
|
-
minimumAmount?: string;
|
|
119
|
-
};
|
|
120
|
-
totalImpact?: {
|
|
121
|
-
usd?: string;
|
|
122
|
-
percent?: string;
|
|
123
|
-
};
|
|
124
|
-
swapImpact?: {
|
|
125
|
-
usd?: string;
|
|
126
|
-
percent?: string;
|
|
127
|
-
};
|
|
128
|
-
rate?: string;
|
|
129
|
-
slippageTolerance?: {
|
|
130
|
-
origin?: {
|
|
131
|
-
usd?: string;
|
|
132
|
-
value?: string;
|
|
133
|
-
percent?: string;
|
|
134
|
-
};
|
|
135
|
-
destination?: {
|
|
136
|
-
usd?: string;
|
|
137
|
-
value?: string;
|
|
138
|
-
percent?: string;
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
|
-
timeEstimate?: number;
|
|
142
|
-
userBalance?: string;
|
|
143
|
-
};
|
|
144
|
-
statusCode: number;
|
|
145
|
-
} | undefined;
|
|
81
|
+
anyspendQuote: import("../../types/api_req_res").GetQuoteResponse | undefined;
|
|
146
82
|
isLoadingAnyspendQuote: boolean;
|
|
147
83
|
getAnyspendQuoteError: Error | null;
|
|
148
84
|
activeInputAmountInWei: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
+
import { FeatureFlags } from "../contexts/FeatureFlagsContext";
|
|
2
3
|
interface AnyspendProviderProps {
|
|
3
4
|
children: ReactNode;
|
|
5
|
+
featureFlags?: FeatureFlags;
|
|
4
6
|
}
|
|
5
7
|
/**
|
|
6
8
|
* AnyspendProvider is a top-level provider that wraps your application to provide
|
|
@@ -12,17 +14,18 @@ interface AnyspendProviderProps {
|
|
|
12
14
|
* - Safe to use at the application root
|
|
13
15
|
* - Configures sensible defaults for query caching
|
|
14
16
|
* - Handles Stripe payment redirects and modal state
|
|
17
|
+
* - Provides feature flags configuration
|
|
15
18
|
*
|
|
16
19
|
* @example
|
|
17
20
|
* ```tsx
|
|
18
21
|
* function App() {
|
|
19
22
|
* return (
|
|
20
|
-
* <AnyspendProvider>
|
|
23
|
+
* <AnyspendProvider featureFlags={{ showPoints: true }}>
|
|
21
24
|
* <YourApp />
|
|
22
25
|
* </AnyspendProvider>
|
|
23
26
|
* );
|
|
24
27
|
* }
|
|
25
28
|
* ```
|
|
26
29
|
*/
|
|
27
|
-
export declare const AnyspendProvider: ({ children }: AnyspendProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
export declare const AnyspendProvider: ({ children, featureFlags }: AnyspendProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
28
31
|
export {};
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { TooltipProvider } from "../../../global-account/react/index.js";
|
|
4
4
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
5
5
|
import { useState } from "react";
|
|
6
|
+
import { FeatureFlagsProvider } from "../contexts/FeatureFlagsContext.js";
|
|
6
7
|
import { StripeRedirectHandler } from "./StripeRedirectHandler.js";
|
|
7
8
|
const defaultQueryClientConfig = {
|
|
8
9
|
defaultOptions: {
|
|
@@ -23,19 +24,20 @@ const defaultQueryClientConfig = {
|
|
|
23
24
|
* - Safe to use at the application root
|
|
24
25
|
* - Configures sensible defaults for query caching
|
|
25
26
|
* - Handles Stripe payment redirects and modal state
|
|
27
|
+
* - Provides feature flags configuration
|
|
26
28
|
*
|
|
27
29
|
* @example
|
|
28
30
|
* ```tsx
|
|
29
31
|
* function App() {
|
|
30
32
|
* return (
|
|
31
|
-
* <AnyspendProvider>
|
|
33
|
+
* <AnyspendProvider featureFlags={{ showPoints: true }}>
|
|
32
34
|
* <YourApp />
|
|
33
35
|
* </AnyspendProvider>
|
|
34
36
|
* );
|
|
35
37
|
* }
|
|
36
38
|
* ```
|
|
37
39
|
*/
|
|
38
|
-
export const AnyspendProvider = function AnyspendProvider({ children }) {
|
|
40
|
+
export const AnyspendProvider = function AnyspendProvider({ children, featureFlags }) {
|
|
39
41
|
const [queryClient] = useState(() => new QueryClient(defaultQueryClientConfig));
|
|
40
|
-
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsxs(TooltipProvider, { children: [_jsx(StripeRedirectHandler, {}), children] }) }));
|
|
42
|
+
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(FeatureFlagsProvider, { featureFlags: featureFlags, children: _jsxs(TooltipProvider, { children: [_jsx(StripeRedirectHandler, {}), children] }) }) }));
|
|
41
43
|
};
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { paths } from "./api";
|
|
2
2
|
export type GetOrderAndTxsResponse = paths["/orders/{orderId}"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
3
3
|
export type GetQuoteRequest = paths["/orders/quote"]["post"]["requestBody"]["content"]["application/json"];
|
|
4
|
-
|
|
4
|
+
type BaseGetQuoteResponse = paths["/orders/quote"]["post"]["responses"]["200"]["content"]["application/json"];
|
|
5
|
+
export type GetQuoteResponse = BaseGetQuoteResponse & {
|
|
6
|
+
data: BaseGetQuoteResponse["data"] & {
|
|
7
|
+
pointsAmount?: number;
|
|
8
|
+
pointsMultiplier?: number;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
5
11
|
export type GetCoinbaseOnrampOptionsResponse = paths["/onramp/coinbase/options"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
6
12
|
export type GetOrderHistoryResponse = paths["/orders"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
7
13
|
export type GetTokenListResponse = paths["/chains/{chainId}/tokens"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
8
14
|
export type CreateOrderResponse = paths["/orders"]["post"]["responses"]["200"]["content"]["application/json"];
|
|
9
15
|
export type GetStripeSupportedResponse = paths["/onramp/stripe/supported"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
10
16
|
export type GetStripeClientSecret = paths["/stripe/clientSecret"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
17
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { components } from "@b3dotfun/sdk/anyspend/types/api";
|
|
2
|
+
import { GetQuoteResponse } from "@b3dotfun/sdk/anyspend/types/api_req_res";
|
|
2
3
|
import { FiatPaymentMethod } from "./FiatPaymentMethod";
|
|
3
|
-
export declare function PanelOnramp({ srcAmountOnRamp, setSrcAmountOnRamp, selectedPaymentMethod, setActivePanel, _recipientAddress, destinationToken, destinationChainId, destinationAmount, onDestinationTokenChange, onDestinationChainChange, fiatPaymentMethodIndex, recipientSelectionPanelIndex, dstTokenSymbol, hideDstToken, }: {
|
|
4
|
+
export declare function PanelOnramp({ srcAmountOnRamp, setSrcAmountOnRamp, selectedPaymentMethod, setActivePanel, _recipientAddress, destinationToken, destinationChainId, destinationAmount, onDestinationTokenChange, onDestinationChainChange, fiatPaymentMethodIndex, recipientSelectionPanelIndex, dstTokenSymbol, hideDstToken, anyspendQuote, }: {
|
|
4
5
|
srcAmountOnRamp: string;
|
|
5
6
|
setSrcAmountOnRamp: (amount: string) => void;
|
|
6
7
|
selectedPaymentMethod?: FiatPaymentMethod;
|
|
@@ -15,4 +16,5 @@ export declare function PanelOnramp({ srcAmountOnRamp, setSrcAmountOnRamp, selec
|
|
|
15
16
|
recipientSelectionPanelIndex: number;
|
|
16
17
|
dstTokenSymbol?: string;
|
|
17
18
|
hideDstToken?: boolean;
|
|
19
|
+
anyspendQuote?: GetQuoteResponse;
|
|
18
20
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
export interface FeatureFlags {
|
|
3
|
+
showPoints?: boolean;
|
|
4
|
+
}
|
|
5
|
+
interface FeatureFlagsProviderProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
featureFlags?: FeatureFlags;
|
|
8
|
+
}
|
|
9
|
+
export declare function FeatureFlagsProvider({ children, featureFlags }: FeatureFlagsProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function useFeatureFlags(): FeatureFlags;
|
|
11
|
+
export {};
|
|
@@ -78,71 +78,7 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
78
78
|
globalAddress: string | undefined;
|
|
79
79
|
hasEnoughBalance: boolean;
|
|
80
80
|
isBalanceLoading: boolean;
|
|
81
|
-
anyspendQuote:
|
|
82
|
-
success: boolean;
|
|
83
|
-
message: string;
|
|
84
|
-
data: {
|
|
85
|
-
operation?: string;
|
|
86
|
-
sender?: string;
|
|
87
|
-
recipient?: string;
|
|
88
|
-
currencyIn?: {
|
|
89
|
-
currency?: {
|
|
90
|
-
chainId?: number;
|
|
91
|
-
address?: string;
|
|
92
|
-
symbol?: string;
|
|
93
|
-
name?: string;
|
|
94
|
-
decimals?: number;
|
|
95
|
-
metadata?: {
|
|
96
|
-
logoURI?: string;
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
amount?: string;
|
|
100
|
-
amountFormatted?: string;
|
|
101
|
-
amountUsd?: string;
|
|
102
|
-
minimumAmount?: string;
|
|
103
|
-
};
|
|
104
|
-
currencyOut?: {
|
|
105
|
-
currency?: {
|
|
106
|
-
chainId?: number;
|
|
107
|
-
address?: string;
|
|
108
|
-
symbol?: string;
|
|
109
|
-
name?: string;
|
|
110
|
-
decimals?: number;
|
|
111
|
-
metadata?: {
|
|
112
|
-
logoURI?: string;
|
|
113
|
-
};
|
|
114
|
-
};
|
|
115
|
-
amount?: string;
|
|
116
|
-
amountFormatted?: string;
|
|
117
|
-
amountUsd?: string;
|
|
118
|
-
minimumAmount?: string;
|
|
119
|
-
};
|
|
120
|
-
totalImpact?: {
|
|
121
|
-
usd?: string;
|
|
122
|
-
percent?: string;
|
|
123
|
-
};
|
|
124
|
-
swapImpact?: {
|
|
125
|
-
usd?: string;
|
|
126
|
-
percent?: string;
|
|
127
|
-
};
|
|
128
|
-
rate?: string;
|
|
129
|
-
slippageTolerance?: {
|
|
130
|
-
origin?: {
|
|
131
|
-
usd?: string;
|
|
132
|
-
value?: string;
|
|
133
|
-
percent?: string;
|
|
134
|
-
};
|
|
135
|
-
destination?: {
|
|
136
|
-
usd?: string;
|
|
137
|
-
value?: string;
|
|
138
|
-
percent?: string;
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
|
-
timeEstimate?: number;
|
|
142
|
-
userBalance?: string;
|
|
143
|
-
};
|
|
144
|
-
statusCode: number;
|
|
145
|
-
} | undefined;
|
|
81
|
+
anyspendQuote: import("../../types/api_req_res").GetQuoteResponse | undefined;
|
|
146
82
|
isLoadingAnyspendQuote: boolean;
|
|
147
83
|
getAnyspendQuoteError: Error | null;
|
|
148
84
|
activeInputAmountInWei: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
+
import { FeatureFlags } from "../contexts/FeatureFlagsContext";
|
|
2
3
|
interface AnyspendProviderProps {
|
|
3
4
|
children: ReactNode;
|
|
5
|
+
featureFlags?: FeatureFlags;
|
|
4
6
|
}
|
|
5
7
|
/**
|
|
6
8
|
* AnyspendProvider is a top-level provider that wraps your application to provide
|
|
@@ -12,17 +14,18 @@ interface AnyspendProviderProps {
|
|
|
12
14
|
* - Safe to use at the application root
|
|
13
15
|
* - Configures sensible defaults for query caching
|
|
14
16
|
* - Handles Stripe payment redirects and modal state
|
|
17
|
+
* - Provides feature flags configuration
|
|
15
18
|
*
|
|
16
19
|
* @example
|
|
17
20
|
* ```tsx
|
|
18
21
|
* function App() {
|
|
19
22
|
* return (
|
|
20
|
-
* <AnyspendProvider>
|
|
23
|
+
* <AnyspendProvider featureFlags={{ showPoints: true }}>
|
|
21
24
|
* <YourApp />
|
|
22
25
|
* </AnyspendProvider>
|
|
23
26
|
* );
|
|
24
27
|
* }
|
|
25
28
|
* ```
|
|
26
29
|
*/
|
|
27
|
-
export declare const AnyspendProvider: ({ children }: AnyspendProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
export declare const AnyspendProvider: ({ children, featureFlags }: AnyspendProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
28
31
|
export {};
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { paths } from "./api";
|
|
2
2
|
export type GetOrderAndTxsResponse = paths["/orders/{orderId}"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
3
3
|
export type GetQuoteRequest = paths["/orders/quote"]["post"]["requestBody"]["content"]["application/json"];
|
|
4
|
-
|
|
4
|
+
type BaseGetQuoteResponse = paths["/orders/quote"]["post"]["responses"]["200"]["content"]["application/json"];
|
|
5
|
+
export type GetQuoteResponse = BaseGetQuoteResponse & {
|
|
6
|
+
data: BaseGetQuoteResponse["data"] & {
|
|
7
|
+
pointsAmount?: number;
|
|
8
|
+
pointsMultiplier?: number;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
5
11
|
export type GetCoinbaseOnrampOptionsResponse = paths["/onramp/coinbase/options"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
6
12
|
export type GetOrderHistoryResponse = paths["/orders"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
7
13
|
export type GetTokenListResponse = paths["/chains/{chainId}/tokens"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
8
14
|
export type CreateOrderResponse = paths["/orders"]["post"]["responses"]["200"]["content"]["application/json"];
|
|
9
15
|
export type GetStripeSupportedResponse = paths["/onramp/stripe/supported"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
10
16
|
export type GetStripeClientSecret = paths["/stripe/clientSecret"]["get"]["responses"]["200"]["content"]["application/json"];
|
|
17
|
+
export {};
|
package/package.json
CHANGED
|
@@ -223,6 +223,7 @@ function AnySpendDepositHypeInner({
|
|
|
223
223
|
onDestinationChainChange={() => {}}
|
|
224
224
|
fiatPaymentMethodIndex={PanelView.FIAT_PAYMENT_METHOD}
|
|
225
225
|
recipientSelectionPanelIndex={PanelView.RECIPIENT_SELECTION}
|
|
226
|
+
anyspendQuote={anyspendQuote}
|
|
226
227
|
/>
|
|
227
228
|
</motion.div>
|
|
228
229
|
)}
|
|
@@ -5,6 +5,7 @@ import { formatDisplayNumber } from "@b3dotfun/sdk/shared/utils/number";
|
|
|
5
5
|
import { ChevronRight } from "lucide-react";
|
|
6
6
|
import { motion } from "motion/react";
|
|
7
7
|
import { components } from "../../../types/api";
|
|
8
|
+
import { useFeatureFlags } from "../../contexts/FeatureFlagsContext";
|
|
8
9
|
import { OrderTokenAmount } from "./OrderTokenAmount";
|
|
9
10
|
|
|
10
11
|
interface CryptoReceiveSectionProps {
|
|
@@ -45,6 +46,8 @@ export function CryptoReceiveSection({
|
|
|
45
46
|
dstTokenSymbol,
|
|
46
47
|
dstTokenLogoURI,
|
|
47
48
|
}: CryptoReceiveSectionProps) {
|
|
49
|
+
const featureFlags = useFeatureFlags();
|
|
50
|
+
|
|
48
51
|
return (
|
|
49
52
|
<motion.div
|
|
50
53
|
initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
|
|
@@ -100,61 +103,68 @@ export function CryptoReceiveSection({
|
|
|
100
103
|
setToken={setSelectedDstToken || (() => {})}
|
|
101
104
|
/>
|
|
102
105
|
)}
|
|
103
|
-
<div className="text-as-primary/50 flex h-5 items-center text-sm">
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
anyspendQuote?.data?.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
<div className="text-as-primary/50 flex h-5 items-center justify-between text-sm">
|
|
107
|
+
<div className="flex items-center gap-2">
|
|
108
|
+
{formatDisplayNumber(anyspendQuote?.data?.currencyOut?.amountUsd, {
|
|
109
|
+
style: "currency",
|
|
110
|
+
fallback: "",
|
|
111
|
+
})}
|
|
112
|
+
{anyspendQuote?.data?.currencyIn?.amountUsd &&
|
|
113
|
+
anyspendQuote?.data?.currencyOut?.amountUsd &&
|
|
114
|
+
(() => {
|
|
115
|
+
const calculatePriceImpact = (inputUsd?: string | number, outputUsd?: string | number) => {
|
|
116
|
+
if (!inputUsd || !outputUsd) {
|
|
117
|
+
return { percentage: "0.00", isNegative: false };
|
|
118
|
+
}
|
|
115
119
|
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
const input = Number(inputUsd);
|
|
121
|
+
const output = Number(outputUsd);
|
|
118
122
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
// Handle edge cases
|
|
124
|
+
if (input === 0 || isNaN(input) || isNaN(output) || input <= output) {
|
|
125
|
+
return { percentage: "0.00", isNegative: false };
|
|
126
|
+
}
|
|
123
127
|
|
|
124
|
-
|
|
128
|
+
const percentageValue = ((output - input) / input) * 100;
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
// Handle the -0.00% case
|
|
131
|
+
if (percentageValue > -0.005 && percentageValue < 0) {
|
|
132
|
+
return { percentage: "0.00", isNegative: false };
|
|
133
|
+
}
|
|
130
134
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
return {
|
|
136
|
+
percentage: Math.abs(percentageValue).toFixed(2),
|
|
137
|
+
isNegative: percentageValue < 0,
|
|
138
|
+
};
|
|
134
139
|
};
|
|
135
|
-
};
|
|
136
140
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
+
const { percentage, isNegative } = calculatePriceImpact(
|
|
142
|
+
anyspendQuote.data.currencyIn.amountUsd,
|
|
143
|
+
anyspendQuote.data.currencyOut.amountUsd,
|
|
144
|
+
);
|
|
141
145
|
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
// Parse the percentage as a number for comparison
|
|
147
|
+
const percentageNum = parseFloat(percentage);
|
|
144
148
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
// Don't show if less than 1%
|
|
150
|
+
if (percentageNum < 1) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
149
153
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
// Using inline style to ensure color displays
|
|
155
|
+
return (
|
|
156
|
+
<span className="ml-2" style={{ color: percentageNum >= 10 ? "red" : "#FFD700" }}>
|
|
157
|
+
({isNegative ? "-" : ""}
|
|
158
|
+
{percentage}%)
|
|
159
|
+
</span>
|
|
160
|
+
);
|
|
161
|
+
})()}
|
|
162
|
+
</div>
|
|
163
|
+
{featureFlags.showPoints && anyspendQuote?.data?.pointsAmount && anyspendQuote.data.pointsAmount > 0 && (
|
|
164
|
+
<div key={`points-${anyspendQuote.data.pointsAmount}`} className="flex items-center gap-1">
|
|
165
|
+
<span className="text-as-brand font-medium">+{anyspendQuote.data.pointsAmount.toLocaleString()} pts</span>
|
|
166
|
+
</div>
|
|
167
|
+
)}
|
|
158
168
|
</div>
|
|
159
169
|
</motion.div>
|
|
160
170
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCoinbaseOnrampOptions, useGeoOnrampOptions } from "@b3dotfun/sdk/anyspend/react";
|
|
2
2
|
import { components } from "@b3dotfun/sdk/anyspend/types/api";
|
|
3
|
+
import { GetQuoteResponse } from "@b3dotfun/sdk/anyspend/types/api_req_res";
|
|
3
4
|
import { ALL_CHAINS } from "@b3dotfun/sdk/anyspend/utils/chain";
|
|
4
5
|
import { Input, useGetGeo, useProfile } from "@b3dotfun/sdk/global-account/react";
|
|
5
6
|
import { cn, formatUsername } from "@b3dotfun/sdk/shared/utils";
|
|
@@ -7,6 +8,7 @@ import { formatAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
|
|
|
7
8
|
import { ChevronRight, Wallet } from "lucide-react";
|
|
8
9
|
import { useRef } from "react";
|
|
9
10
|
import { toast } from "sonner";
|
|
11
|
+
import { useFeatureFlags } from "../../contexts/FeatureFlagsContext";
|
|
10
12
|
import { FiatPaymentMethod } from "./FiatPaymentMethod";
|
|
11
13
|
import { OrderTokenAmountFiat } from "./OrderTokenAmountFiat";
|
|
12
14
|
|
|
@@ -25,6 +27,7 @@ export function PanelOnramp({
|
|
|
25
27
|
recipientSelectionPanelIndex,
|
|
26
28
|
dstTokenSymbol,
|
|
27
29
|
hideDstToken = false,
|
|
30
|
+
anyspendQuote,
|
|
28
31
|
}: {
|
|
29
32
|
srcAmountOnRamp: string;
|
|
30
33
|
setSrcAmountOnRamp: (amount: string) => void;
|
|
@@ -40,7 +43,9 @@ export function PanelOnramp({
|
|
|
40
43
|
recipientSelectionPanelIndex: number;
|
|
41
44
|
dstTokenSymbol?: string;
|
|
42
45
|
hideDstToken?: boolean;
|
|
46
|
+
anyspendQuote?: GetQuoteResponse;
|
|
43
47
|
}) {
|
|
48
|
+
const featureFlags = useFeatureFlags();
|
|
44
49
|
// Get geo-based onramp options to access fee information
|
|
45
50
|
const { stripeWeb2Support } = useGeoOnrampOptions(srcAmountOnRamp);
|
|
46
51
|
|
|
@@ -245,21 +250,22 @@ export function PanelOnramp({
|
|
|
245
250
|
|
|
246
251
|
<div className="">
|
|
247
252
|
<div className="flex items-center justify-between">
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
253
|
+
<div className="flex items-center gap-2">
|
|
254
|
+
<span className="text-as-tertiarry text-sm">
|
|
255
|
+
{(() => {
|
|
256
|
+
const fee = getFeeFromApi(selectedPaymentMethod || FiatPaymentMethod.NONE);
|
|
257
|
+
return fee !== null ? `Total (included $${fee.toFixed(2)} fee)` : "Total";
|
|
258
|
+
})()}
|
|
259
|
+
</span>
|
|
260
|
+
{featureFlags.showPoints && anyspendQuote?.data?.pointsAmount && anyspendQuote.data.pointsAmount > 0 && (
|
|
261
|
+
<span key={`points-${anyspendQuote.data.pointsAmount}`} className="text-as-brand text-sm font-medium">
|
|
262
|
+
+{anyspendQuote.data.pointsAmount.toLocaleString()} pts
|
|
263
|
+
</span>
|
|
264
|
+
)}
|
|
265
|
+
</div>
|
|
266
|
+
<span className="text-as-primary font-semibold">
|
|
267
|
+
${getTotalAmount(selectedPaymentMethod || FiatPaymentMethod.NONE).toFixed(2)}
|
|
268
|
+
</span>
|
|
263
269
|
</div>
|
|
264
270
|
</div>
|
|
265
271
|
</div>
|