@b3dotfun/sdk 0.0.3 → 0.0.4-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/cjs/anyspend/index.js +1 -0
  2. package/dist/cjs/anyspend/react/components/index.d.ts +6 -5
  3. package/dist/cjs/anyspend/react/components/index.js +13 -11
  4. package/dist/cjs/anyspend/react/components/webview/WebviewOnrampPayment.d.ts +11 -0
  5. package/dist/cjs/anyspend/react/components/webview/WebviewOnrampPayment.js +93 -0
  6. package/dist/cjs/anyspend/react/hooks/useAnyspendOrderAndTransactions.d.ts +10 -0
  7. package/dist/cjs/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +10 -0
  8. package/dist/cjs/anyspend/services/anyspend.d.ts +5 -0
  9. package/dist/cjs/anyspend/types/order.d.ts +18 -0
  10. package/dist/cjs/anyspend/types/order.js +1 -0
  11. package/dist/cjs/anyspend/types/req-res/createOrder.d.ts +25 -0
  12. package/dist/cjs/anyspend/types/req-res/getOrderAndTransactions.d.ts +35 -0
  13. package/dist/cjs/anyspend/types/req-res/getOrderHistory.d.ts +25 -0
  14. package/dist/cjs/global-account/react/hooks/useTokenFromUrl.d.ts +1 -1
  15. package/dist/cjs/global-account/react/hooks/useTokenFromUrl.js +51 -13
  16. package/dist/cjs/shared/constants/chains/supported.d.ts +14 -4
  17. package/dist/cjs/shared/constants/chains/supported.js +11 -8
  18. package/dist/cjs/shared/generated/coingecko-chains.json +1072 -0
  19. package/dist/esm/anyspend/index.js +1 -0
  20. package/dist/esm/anyspend/react/components/index.d.ts +6 -5
  21. package/dist/esm/anyspend/react/components/index.js +6 -5
  22. package/dist/esm/anyspend/react/components/webview/WebviewOnrampPayment.d.ts +11 -0
  23. package/dist/esm/anyspend/react/components/webview/WebviewOnrampPayment.js +87 -0
  24. package/dist/esm/anyspend/react/hooks/useAnyspendOrderAndTransactions.d.ts +10 -0
  25. package/dist/esm/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +10 -0
  26. package/dist/esm/anyspend/services/anyspend.d.ts +5 -0
  27. package/dist/esm/anyspend/types/order.d.ts +18 -0
  28. package/dist/esm/anyspend/types/order.js +1 -0
  29. package/dist/esm/anyspend/types/req-res/createOrder.d.ts +25 -0
  30. package/dist/esm/anyspend/types/req-res/getOrderAndTransactions.d.ts +35 -0
  31. package/dist/esm/anyspend/types/req-res/getOrderHistory.d.ts +25 -0
  32. package/dist/esm/global-account/react/hooks/useTokenFromUrl.d.ts +1 -1
  33. package/dist/esm/global-account/react/hooks/useTokenFromUrl.js +51 -13
  34. package/dist/esm/shared/constants/chains/supported.d.ts +14 -4
  35. package/dist/esm/shared/constants/chains/supported.js +9 -7
  36. package/dist/esm/shared/generated/coingecko-chains.json +1072 -0
  37. package/dist/types/anyspend/react/components/index.d.ts +6 -5
  38. package/dist/types/anyspend/react/components/webview/WebviewOnrampPayment.d.ts +11 -0
  39. package/dist/types/anyspend/react/hooks/useAnyspendOrderAndTransactions.d.ts +10 -0
  40. package/dist/types/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +10 -0
  41. package/dist/types/anyspend/services/anyspend.d.ts +5 -0
  42. package/dist/types/anyspend/types/order.d.ts +18 -0
  43. package/dist/types/anyspend/types/req-res/createOrder.d.ts +25 -0
  44. package/dist/types/anyspend/types/req-res/getOrderAndTransactions.d.ts +35 -0
  45. package/dist/types/anyspend/types/req-res/getOrderHistory.d.ts +25 -0
  46. package/dist/types/global-account/react/hooks/useTokenFromUrl.d.ts +1 -1
  47. package/dist/types/shared/constants/chains/supported.d.ts +14 -4
  48. package/package.json +3 -3
  49. package/src/anyspend/index.ts +2 -0
  50. package/src/anyspend/react/components/index.ts +6 -5
  51. package/src/anyspend/react/components/webview/WebviewOnrampPayment.tsx +207 -0
  52. package/src/anyspend/types/order.ts +1 -0
  53. package/src/global-account/react/hooks/useTokenFromUrl.tsx +72 -14
  54. package/src/shared/constants/chains/supported.ts +23 -12
  55. package/src/shared/generated/coingecko-chains.json +1072 -0
  56. /package/dist/cjs/{generated → shared/generated}/chain-networks.json +0 -0
  57. /package/dist/esm/{generated → shared/generated}/chain-networks.json +0 -0
  58. /package/src/{generated → shared/generated}/chain-networks.json +0 -0
@@ -0,0 +1,207 @@
1
+ import {
2
+ getChainName,
3
+ GetQuoteResponse,
4
+ OnrampVendor,
5
+ OrderType,
6
+ Token,
7
+ useAnyspendCreateOnrampOrder,
8
+ useGeoOnrampOptions
9
+ } from "@b3dotfun/sdk/anyspend";
10
+ import { Button } from "@b3dotfun/sdk/global-account/react";
11
+ import centerTruncate from "@b3dotfun/sdk/shared/utils/centerTruncate";
12
+ import { motion } from "framer-motion";
13
+ import { Loader2 } from "lucide-react";
14
+ import { useEffect, useRef, useState } from "react";
15
+ import { toast } from "sonner";
16
+ import { formatUnits } from "viem";
17
+
18
+ interface WebviewOnrampPaymentProps {
19
+ srcAmountOnRamp: string;
20
+ recipientAddress?: string;
21
+ destinationToken: Token;
22
+ anyspendQuote: GetQuoteResponse | undefined;
23
+ onOrderCreated: (orderId: string) => void;
24
+ userId?: string;
25
+ }
26
+
27
+ export function WebviewOnrampPayment({
28
+ srcAmountOnRamp,
29
+ recipientAddress,
30
+ destinationToken,
31
+ anyspendQuote,
32
+ onOrderCreated,
33
+ userId
34
+ }: WebviewOnrampPaymentProps) {
35
+ // Use a stable amount for geo onramp options to prevent unnecessary refetches
36
+ const [stableAmountForGeo, setStableAmountForGeo] = useState(srcAmountOnRamp);
37
+ const hasInitialized = useRef(false);
38
+
39
+ // Only update the stable amount on first render or when explicitly needed
40
+ useEffect(() => {
41
+ if (!hasInitialized.current && srcAmountOnRamp) {
42
+ setStableAmountForGeo(srcAmountOnRamp);
43
+ hasInitialized.current = true;
44
+ }
45
+ }, [srcAmountOnRamp]);
46
+
47
+ const {
48
+ geoData,
49
+ isStripeWeb2Supported,
50
+ isLoading: isLoadingGeoOnramp
51
+ } = useGeoOnrampOptions(true, stableAmountForGeo);
52
+
53
+ console.log("isStripeWeb2Supported", isStripeWeb2Supported);
54
+
55
+ const { createOrder, isCreatingOrder } = useAnyspendCreateOnrampOrder({
56
+ onSuccess: data => {
57
+ const orderId = data.data.id;
58
+ window.location.href = `${window.location.origin}/?orderId=${orderId}`;
59
+ },
60
+ onError: error => {
61
+ console.error(error);
62
+ toast.error("Failed to create order: " + error.message);
63
+ }
64
+ });
65
+
66
+ const handleContinueToPayment = async () => {
67
+ try {
68
+ if (!recipientAddress) {
69
+ toast.error("Please select a recipient");
70
+ return;
71
+ }
72
+
73
+ if (!srcAmountOnRamp || parseFloat(srcAmountOnRamp) <= 0) {
74
+ toast.error("Please enter a valid amount");
75
+ return;
76
+ }
77
+
78
+ if (!isStripeWeb2Supported) {
79
+ toast.error("Stripe credit card not available");
80
+ return;
81
+ }
82
+
83
+ if (!anyspendQuote) {
84
+ toast.error("Failed to get quote");
85
+ return;
86
+ }
87
+
88
+ const getDstToken = (): Token => {
89
+ return {
90
+ ...destinationToken,
91
+ chainId: destinationToken.chainId,
92
+ address: destinationToken.address
93
+ };
94
+ };
95
+
96
+ createOrder({
97
+ isMainnet: true,
98
+ recipientAddress,
99
+ orderType: OrderType.Swap,
100
+ dstChain: getDstToken().chainId,
101
+ dstToken: getDstToken(),
102
+ srcFiatAmount: srcAmountOnRamp,
103
+ onramp: {
104
+ vendor: OnrampVendor.StripeWeb2,
105
+ paymentMethod: "",
106
+ country: geoData?.country || "US",
107
+ ipAddress: geoData?.ip,
108
+ redirectUrl: `${window.location.origin}${userId ? `?userId=${userId}` : ""}`
109
+ },
110
+ expectedDstAmount: anyspendQuote?.data?.currencyOut?.amount?.toString() || "0"
111
+ });
112
+ } catch (err: any) {
113
+ console.error(err);
114
+ toast.error("Failed to create order: " + err.message);
115
+ }
116
+ };
117
+
118
+ return (
119
+ <div className="mx-auto flex w-full max-w-[460px] flex-col gap-6">
120
+ {/* Order Summary Section */}
121
+ <>
122
+ <h2 className="-mb-3 text-lg font-semibold">Order summary</h2>
123
+ <div className="bg-b3-react-background border-b3-react-border flex flex-col gap-3 rounded-lg border p-4">
124
+ {/* Destination Token */}
125
+ <div className="flex items-center justify-between">
126
+ <p className="text-b3-react-foreground/60">Receiving</p>
127
+ <div className="flex items-center gap-2">
128
+ {destinationToken.metadata?.logoURI && (
129
+ <img
130
+ src={destinationToken.metadata.logoURI}
131
+ alt={destinationToken.symbol}
132
+ className="h-6 w-6 rounded-full"
133
+ />
134
+ )}
135
+ <span className="text-b3-react-foreground/80">
136
+ {anyspendQuote?.data?.currencyOut?.amount
137
+ ? Number(
138
+ formatUnits(BigInt(anyspendQuote.data.currencyOut.amount), destinationToken.decimals)
139
+ ).toFixed(4)
140
+ : "0"}{" "}
141
+ {destinationToken.symbol}
142
+ </span>
143
+ </div>
144
+ </div>
145
+
146
+ {/* Network */}
147
+ <div className="flex items-center justify-between">
148
+ <p className="text-b3-react-foreground/60">Network</p>
149
+ <span className="text-b3-react-foreground/80">{getChainName(destinationToken.chainId)}</span>
150
+ </div>
151
+
152
+ {/* Recipient Section */}
153
+ {recipientAddress && (
154
+ <motion.div
155
+ initial={false}
156
+ animate={{
157
+ opacity: 1,
158
+ y: 0,
159
+ filter: "blur(0px)"
160
+ }}
161
+ transition={{ duration: 0.3, delay: 0.2, ease: "easeInOut" }}
162
+ className="flex items-center justify-between"
163
+ >
164
+ <p className="text-b3-react-foreground/60">Recipient</p>
165
+ <div className="flex items-center gap-2">
166
+ <span className="text-b3-react-foreground/80">{centerTruncate(recipientAddress)}</span>
167
+ </div>
168
+ </motion.div>
169
+ )}
170
+
171
+ {/* Amount Section */}
172
+ <div className="border-b3-react-border border-t pt-3">
173
+ <div className="flex items-center justify-between">
174
+ <p className="text-b3-react-foreground font-semibold">You Pay</p>
175
+ <p className="text-b3-react-foreground text-xl font-semibold">
176
+ ${parseFloat(srcAmountOnRamp).toFixed(2)}
177
+ </p>
178
+ </div>
179
+ </div>
180
+ </div>
181
+ </>
182
+
183
+ {/* Payment Section */}
184
+ {isCreatingOrder ? (
185
+ <div className="bg-b3-react-background border-b3-react-border flex items-center justify-center gap-3 rounded-lg border p-6">
186
+ <Loader2 className="h-4 w-4 animate-spin" />
187
+ <span className="text-as-primary/70">Creating payment session...</span>
188
+ </div>
189
+ ) : isLoadingGeoOnramp ? (
190
+ <div className="bg-b3-react-background border-b3-react-border flex items-center justify-center gap-3 rounded-lg border p-6">
191
+ <Loader2 className="h-4 w-4 animate-spin" />
192
+ <span className="text-as-primary/70">Loading payment options...</span>
193
+ </div>
194
+ ) : (
195
+ <div className="flex flex-col gap-4">
196
+ <Button
197
+ onClick={handleContinueToPayment}
198
+ disabled={isCreatingOrder || !isStripeWeb2Supported}
199
+ className="bg-as-brand hover:bg-as-brand/90 text-as-primary h-14 w-full rounded-xl text-lg font-medium"
200
+ >
201
+ {isCreatingOrder ? "Creating Payment..." : "Continue to Payment"}
202
+ </Button>
203
+ </div>
204
+ )}
205
+ </div>
206
+ );
207
+ }
@@ -57,6 +57,7 @@ export const zBaseOrder = z.object({
57
57
  expiredAt: z.number(),
58
58
  onrampMetadata: zOnrampMetadata.nullable(),
59
59
  creatorAddress: z.string().nullable(),
60
+ partnerId: z.string().nullable(),
60
61
 
61
62
  oneClickBuyUrl: z.string().nullable(),
62
63
  stripePaymentIntentId: z.string().nullable(),
@@ -1,6 +1,8 @@
1
1
  "use client";
2
2
 
3
3
  import { Token } from "@b3dotfun/sdk/anyspend";
4
+ import { getCoingeckoChainInfo } from "@b3dotfun/sdk/shared/constants/chains/supported";
5
+ import { useQuery } from "@tanstack/react-query";
4
6
  import { useSearchParams } from "next/navigation";
5
7
 
6
8
  interface UseTokenFromUrlOptions {
@@ -15,32 +17,88 @@ interface UseTokenFromUrlOptions {
15
17
  prefix: string;
16
18
  }
17
19
 
20
+ interface TokenInfo {
21
+ data: {
22
+ attributes: {
23
+ address: string;
24
+ name: string;
25
+ symbol: string;
26
+ decimals: number;
27
+ image_url: string;
28
+ };
29
+ };
30
+ }
31
+
32
+ async function fetchTokenInfo(network: string, address: string): Promise<TokenInfo> {
33
+ const response = await fetch("https://api.b3.fun/tokens", {
34
+ method: "POST",
35
+ headers: {
36
+ "Content-Type": "application/json",
37
+ "X-Service-Method": "getCoinGeckoTokenInfo"
38
+ },
39
+ body: JSON.stringify({
40
+ network,
41
+ address
42
+ })
43
+ });
44
+
45
+ if (!response.ok) {
46
+ throw new Error("Failed to fetch token info");
47
+ }
48
+
49
+ return response.json();
50
+ }
51
+
18
52
  /**
19
- * Hook to parse token data from URL parameters.
53
+ * Hook to parse token data from URL parameters and fetch additional token info.
20
54
  * Looks for parameters: [prefix]Currency
21
55
  */
22
56
  export function useTokenFromUrl({ defaultToken, prefix }: UseTokenFromUrlOptions): Token {
23
57
  const searchParams = useSearchParams();
24
58
 
25
- if (!searchParams) {
26
- return defaultToken;
27
- }
28
-
29
59
  // Get parameters from URL
30
- const currencyParam = searchParams.get(`${prefix}Currency`);
31
- const chainIdParam = searchParams.get(`${prefix}ChainId`);
32
- if (!currencyParam || !chainIdParam) {
60
+ const currencyParam = searchParams?.get(`${prefix}Currency`);
61
+ const chainIdParam = searchParams?.get(`${prefix}ChainId`);
62
+
63
+ // Determine if we should fetch token info
64
+ const shouldFetchToken = Boolean(
65
+ currencyParam && chainIdParam && currencyParam.toLowerCase() !== defaultToken.address.toLowerCase()
66
+ );
67
+
68
+ // Determine network based on chainId
69
+ const network = chainIdParam ? getCoingeckoChainInfo(Number(chainIdParam)).coingecko_id : "";
70
+
71
+ const { data: tokenInfo, isError } = useQuery({
72
+ queryKey: ["tokenInfo", network, currencyParam],
73
+ queryFn: () => fetchTokenInfo(network, currencyParam!),
74
+ enabled: shouldFetchToken,
75
+ staleTime: Infinity,
76
+ gcTime: Infinity
77
+ });
78
+
79
+ // Return default token if no params or same as default
80
+ if (!shouldFetchToken) {
33
81
  return defaultToken;
34
82
  }
35
83
 
36
- // If the currency is the same as the default token, return that
37
- if (currencyParam.toLowerCase() === defaultToken.address.toLowerCase()) {
38
- return defaultToken;
84
+ // Return basic token info if API call fails or while loading
85
+ if (isError || !tokenInfo) {
86
+ return {
87
+ ...defaultToken,
88
+ address: currencyParam!,
89
+ chainId: Number(chainIdParam)
90
+ };
39
91
  }
40
92
 
93
+ // Return enhanced token with API data
41
94
  return {
42
- ...defaultToken,
43
- address: currencyParam,
44
- chainId: Number(chainIdParam)
95
+ address: tokenInfo.data.attributes.address,
96
+ chainId: Number(chainIdParam),
97
+ name: tokenInfo.data.attributes.name,
98
+ symbol: tokenInfo.data.attributes.symbol,
99
+ decimals: tokenInfo.data.attributes.decimals,
100
+ metadata: {
101
+ logoURI: tokenInfo.data.attributes.image_url
102
+ }
45
103
  };
46
104
  }
@@ -3,8 +3,10 @@ import { toThirdwebChain, toViemChain } from "@b3dotfun/sdk/shared/utils/chain-t
3
3
  import type { Chain as ThirdwebChain } from "thirdweb";
4
4
  // Import the JSON directly
5
5
  // @ts-ignore
6
- import chainNetworksJSON from "../../../generated/chain-networks.json" with { type: "json" };
7
- import invariant from "invariant";
6
+ import chainNetworksJSON from "../../generated/chain-networks.json" with { type: "json" };
7
+ // @ts-ignore
8
+ import coingeckoChainsJSON from "../../generated/coingecko-chains.json" with { type: "json" };
9
+
8
10
  const chainNetworks = chainNetworksJSON as ChainNetworks[];
9
11
 
10
12
  // Convert custom chains to Viem format
@@ -27,15 +29,24 @@ export const supportedChainsTW: ThirdwebChain[] = [
27
29
  // Original format from chain-networks.json
28
30
  export const supportedChainNetworks = chainNetworks;
29
31
 
30
- export const b3Mainnet = supportedChains.find(chain => chain.id === 8333)!;
31
- invariant(b3Mainnet, "B3 mainnet chain not found in supported chains");
32
- export const b3Testnet = supportedChains.find(chain => chain.id === 1993)!;
33
- invariant(b3Testnet, "B3 testnet chain not found in supported chains");
34
- export const baseMainnet = supportedChains.find(chain => chain.id === 8453);
35
- invariant(baseMainnet, "Base mainnet chain not found in supported chains");
32
+ // CoinGecko chain mapping
33
+ export const coingeckoChains = coingeckoChainsJSON as Record<
34
+ number,
35
+ {
36
+ coingecko_id: string;
37
+ name: string;
38
+ native_coin_id: string;
39
+ }
40
+ >;
36
41
 
37
- export const b3MainnetThirdWeb = supportedChainsTW.find(chain => chain.id === 8333)!;
38
- invariant(b3MainnetThirdWeb, "B3 mainnet chain not found in supported chains TW");
42
+ // Helper function to get CoinGecko chain info
43
+ export function getCoingeckoChainInfo(chainId: number) {
44
+ return coingeckoChains[chainId];
45
+ }
46
+
47
+ export const b3Mainnet = supportedChains.find(chain => chain.id === 8333);
48
+ export const b3Testnet = supportedChains.find(chain => chain.id === 1993);
49
+ export const baseMainnet = supportedChains.find(chain => chain.id === 8453);
39
50
 
40
- export const b3TestnetThirdWeb = supportedChainsTW.find(chain => chain.id === 1993)!;
41
- invariant(b3TestnetThirdWeb, "B3 testnet chain not found in supported chains TW");
51
+ export const b3MainnetThirdWeb = supportedChainsTW.find(chain => chain.id === 8333);
52
+ export const b3TestnetThirdWeb = supportedChainsTW.find(chain => chain.id === 1993);