@b3dotfun/sdk 0.0.9-alpha.9 → 0.0.10

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.
@@ -8,6 +8,7 @@ export declare const SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = "ATokenGPvbdGV
8
8
  export declare const SOLANA_TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
9
9
  export declare const B3_TOKEN: components["schemas"]["Token"];
10
10
  export declare const USDC_BASE: components["schemas"]["Token"];
11
+ export declare const ETH_BASE: components["schemas"]["Token"];
11
12
  export declare const NFT_CONTRACTS: components["schemas"]["NftContract"][];
12
13
  export declare const DEFAULT_NFT_CONTRACT: {
13
14
  chainId: number;
@@ -15,7 +16,7 @@ export declare const DEFAULT_NFT_CONTRACT: {
15
16
  price: string;
16
17
  priceFormatted: string;
17
18
  currency: components["schemas"]["Token"];
18
- imageUrl: string;
19
+ imageUrl: string | null;
19
20
  name: string;
20
21
  description: string;
21
22
  tokenId: number | null;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VENDOR_DISPLAY_NAMES = exports.PAYMENT_METHOD_ICONS = exports.STRIPE_CONFIG = exports.DEFAULT_NFT_CONTRACT = exports.NFT_CONTRACTS = exports.USDC_BASE = exports.B3_TOKEN = exports.SOLANA_TOKEN_2022_PROGRAM_ID = exports.SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = exports.RELAY_SOLANA_MAINNET_CHAIN_ID = exports.RELAY_SOL_ADDRESS = exports.RELAY_ETH_ADDRESS = exports.ANYSPEND_TESTNET_BASE_URL = exports.ANYSPEND_MAINNET_BASE_URL = void 0;
3
+ exports.VENDOR_DISPLAY_NAMES = exports.PAYMENT_METHOD_ICONS = exports.STRIPE_CONFIG = exports.DEFAULT_NFT_CONTRACT = exports.NFT_CONTRACTS = exports.ETH_BASE = exports.USDC_BASE = exports.B3_TOKEN = exports.SOLANA_TOKEN_2022_PROGRAM_ID = exports.SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = exports.RELAY_SOLANA_MAINNET_CHAIN_ID = exports.RELAY_SOL_ADDRESS = exports.RELAY_ETH_ADDRESS = exports.ANYSPEND_TESTNET_BASE_URL = exports.ANYSPEND_MAINNET_BASE_URL = void 0;
4
4
  const chains_1 = require("viem/chains");
5
5
  exports.ANYSPEND_MAINNET_BASE_URL = process.env.NEXT_PUBLIC_ANYSPEND_BASE_URL || "https://mainnet.anyspend.com";
6
6
  exports.ANYSPEND_TESTNET_BASE_URL = process.env.NEXT_PUBLIC_ANYSPEND_BASE_URL || "https://testnet.anyspend.com";
@@ -29,6 +29,16 @@ exports.USDC_BASE = {
29
29
  logoURI: "https://polygonscan.com/token/images/usdc_32.png",
30
30
  },
31
31
  };
32
+ exports.ETH_BASE = {
33
+ symbol: "ETH",
34
+ chainId: chains_1.base.id,
35
+ address: "0x0000000000000000000000000000000000000000",
36
+ name: "Ethereum",
37
+ decimals: 18,
38
+ metadata: {
39
+ logoURI: "https://polygonscan.com/token/images/eth_32.png",
40
+ },
41
+ };
32
42
  exports.NFT_CONTRACTS = [
33
43
  {
34
44
  chainId: chains_1.base.id,
@@ -12,8 +12,78 @@ const lucide_react_1 = require("lucide-react");
12
12
  const react_2 = require("react");
13
13
  const chains_1 = require("viem/chains");
14
14
  const AnySpendCustom_1 = require("./AnySpendCustom");
15
+ // ABI for contractURI and uri functions
16
+ const CONTRACT_URI_ABI = [
17
+ {
18
+ inputs: [],
19
+ name: "contractURI",
20
+ outputs: [{ internalType: "string", name: "", type: "string" }],
21
+ stateMutability: "view",
22
+ type: "function",
23
+ },
24
+ {
25
+ inputs: [{ internalType: "uint256", name: "_tokenId", type: "uint256" }],
26
+ name: "uri",
27
+ outputs: [{ internalType: "string", name: "", type: "string" }],
28
+ stateMutability: "view",
29
+ type: "function",
30
+ },
31
+ ];
15
32
  function AnySpendNFT({ isMainnet = true, loadOrder, mode = "modal", recipientAddress, nftContract, onSuccess, }) {
16
- const header = ({ anyspendPrice, isLoadingAnyspendPrice, }) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative size-[200px]", children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 scale-95 bg-black/30 blur-md" }), (0, jsx_runtime_1.jsxs)(react_1.GlareCard, { className: "overflow-hidden", children: [(0, jsx_runtime_1.jsx)("img", { src: (0, ipfs_1.getIpfsUrl)(nftContract.imageUrl), alt: nftContract.name, className: "size-full object-cover" }), (0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 rounded-xl border border-white/10" })] }), (0, jsx_runtime_1.jsx)(DropdownMenu, { nftContract: nftContract })] }), (0, jsx_runtime_1.jsxs)("div", { className: "from-b3-react-background to-as-on-surface-1 mt-[-100px] w-full rounded-t-lg bg-gradient-to-t", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-[100px] w-full" }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-1 flex w-full flex-col items-center gap-2 p-5", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-sf-rounded text-2xl font-semibold", children: nftContract.name }), (0, jsx_runtime_1.jsx)("div", { className: "flex w-fit items-center gap-1", children: anyspendPrice ? ((0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { mode: "wait", children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("text-as-primary group flex items-center text-3xl font-semibold transition-all", {
33
+ const [imageUrlWithFallback, setFallbackImageUrl] = (0, react_2.useState)(nftContract.imageUrl);
34
+ const [isLoadingFallback, setIsLoadingFallback] = (0, react_2.useState)(false);
35
+ // Fetch contract metadata when imageUrl is empty
36
+ (0, react_2.useEffect)(() => {
37
+ async function fetchContractMetadata() {
38
+ // fetch image Uri if not provided
39
+ if (nftContract.imageUrl || isLoadingFallback) {
40
+ return;
41
+ }
42
+ try {
43
+ setIsLoadingFallback(true);
44
+ // Use the chainIdToPublicClient utility function
45
+ const publicClient = (0, anyspend_1.chainIdToPublicClient)(nftContract.chainId);
46
+ let metadataURI;
47
+ // Use uri function if tokenId is available, otherwise use contractURI
48
+ if (nftContract.tokenId !== null && nftContract.tokenId !== undefined) {
49
+ console.log("Using uri function with tokenId:", nftContract.tokenId);
50
+ metadataURI = await publicClient.readContract({
51
+ address: nftContract.contractAddress,
52
+ abi: CONTRACT_URI_ABI,
53
+ functionName: "uri",
54
+ args: [BigInt(nftContract.tokenId)],
55
+ });
56
+ }
57
+ else {
58
+ console.log("Using contractURI function");
59
+ metadataURI = await publicClient.readContract({
60
+ address: nftContract.contractAddress,
61
+ abi: CONTRACT_URI_ABI,
62
+ functionName: "contractURI",
63
+ });
64
+ }
65
+ if (metadataURI) {
66
+ // Fetch the metadata from IPFS
67
+ const metadataUrl = (0, ipfs_1.getIpfsUrl)(metadataURI);
68
+ const response = await fetch(metadataUrl);
69
+ const metadata = await response.json();
70
+ if (metadata.image) {
71
+ const fallbackUrl = (0, ipfs_1.getIpfsUrl)(metadata.image);
72
+ setFallbackImageUrl(fallbackUrl);
73
+ console.log("fallbackImageUrl", fallbackUrl);
74
+ }
75
+ }
76
+ }
77
+ catch (error) {
78
+ console.error("Error fetching contract metadata:", error);
79
+ }
80
+ finally {
81
+ setIsLoadingFallback(false);
82
+ }
83
+ }
84
+ fetchContractMetadata();
85
+ }, [nftContract.contractAddress, nftContract.chainId, nftContract.imageUrl, nftContract.tokenId]);
86
+ const header = ({ anyspendPrice, isLoadingAnyspendPrice, }) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative size-[200px]", children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 scale-95 bg-black/30 blur-md" }), (0, jsx_runtime_1.jsxs)(react_1.GlareCard, { className: "overflow-hidden", children: [imageUrlWithFallback && ((0, jsx_runtime_1.jsx)("img", { src: imageUrlWithFallback, alt: nftContract.name, className: "size-full object-cover" })), (0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 rounded-xl border border-white/10" })] }), (0, jsx_runtime_1.jsx)(DropdownMenu, { nftContract: nftContract })] }), (0, jsx_runtime_1.jsxs)("div", { className: "from-b3-react-background to-as-on-surface-1 mt-[-100px] w-full rounded-t-lg bg-gradient-to-t", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-[100px] w-full" }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-1 flex w-full flex-col items-center gap-2 p-5", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-sf-rounded text-2xl font-semibold", children: nftContract.name }), (0, jsx_runtime_1.jsx)("div", { className: "flex w-fit items-center gap-1", children: anyspendPrice ? ((0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { mode: "wait", children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("text-as-primary group flex items-center text-3xl font-semibold transition-all", {
17
87
  "opacity-0": isLoadingAnyspendPrice,
18
88
  }), children: (0, number_1.formatDisplayNumber)(anyspendPrice?.data?.currencyIn?.amountUsd, { style: "currency" }) }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "h-[36px] w-full" })) })] })] })] }));
19
89
  return ((0, jsx_runtime_1.jsx)(AnySpendCustom_1.AnySpendCustom, { isMainnet: isMainnet, loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, orderType: "mint_nft", dstChainId: nftContract.chainId, dstToken: nftContract.currency, dstAmount: nftContract.price, contractAddress: nftContract.contractAddress, encodedData: "0x", metadata: {
@@ -1673,7 +1673,7 @@ export interface components {
1673
1673
  * @description NFT image URL
1674
1674
  * @example https://example.com/nft.png
1675
1675
  */
1676
- imageUrl: string;
1676
+ imageUrl: string | null;
1677
1677
  /**
1678
1678
  * @description NFT name
1679
1679
  * @example Cool NFT Collection
@@ -900,7 +900,7 @@ const getV1NftsByContractAddress = (options) => {
900
900
  type: 'apiKey'
901
901
  }
902
902
  ],
903
- url: 'https://insight.thirdweb.com/v1/nfts/{contract_address}',
903
+ url: '/v1/nfts/{contract_address}',
904
904
  ...options
905
905
  });
906
906
  };
@@ -5,7 +5,7 @@ const client_gen_1 = require("./generated/client.gen");
5
5
  (function () {
6
6
  // Set BASE URL
7
7
  client_gen_1.client.setConfig({
8
- baseUrl: "https://insight.thirdweb.com",
8
+ baseUrl: "https://8333.insight.thirdweb.com",
9
9
  });
10
10
  // Interceptors for issues described here https://npc-labs.slack.com/archives/C070E6HNG85/p1742446793549779?thread_ts=1741637902.666019&cid=C070E6HNG85
11
11
  client_gen_1.client.interceptors.request.use((request, options) => {
@@ -8,6 +8,7 @@ export declare const SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = "ATokenGPvbdGV
8
8
  export declare const SOLANA_TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
9
9
  export declare const B3_TOKEN: components["schemas"]["Token"];
10
10
  export declare const USDC_BASE: components["schemas"]["Token"];
11
+ export declare const ETH_BASE: components["schemas"]["Token"];
11
12
  export declare const NFT_CONTRACTS: components["schemas"]["NftContract"][];
12
13
  export declare const DEFAULT_NFT_CONTRACT: {
13
14
  chainId: number;
@@ -15,7 +16,7 @@ export declare const DEFAULT_NFT_CONTRACT: {
15
16
  price: string;
16
17
  priceFormatted: string;
17
18
  currency: components["schemas"]["Token"];
18
- imageUrl: string;
19
+ imageUrl: string | null;
19
20
  name: string;
20
21
  description: string;
21
22
  tokenId: number | null;
@@ -26,6 +26,16 @@ export const USDC_BASE = {
26
26
  logoURI: "https://polygonscan.com/token/images/usdc_32.png",
27
27
  },
28
28
  };
29
+ export const ETH_BASE = {
30
+ symbol: "ETH",
31
+ chainId: base.id,
32
+ address: "0x0000000000000000000000000000000000000000",
33
+ name: "Ethereum",
34
+ decimals: 18,
35
+ metadata: {
36
+ logoURI: "https://polygonscan.com/token/images/eth_32.png",
37
+ },
38
+ };
29
39
  export const NFT_CONTRACTS = [
30
40
  {
31
41
  chainId: base.id,
@@ -1,16 +1,86 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { ALL_CHAINS, getChainName, getExplorerAddressUrl } from "../../../anyspend/index.js";
2
+ import { ALL_CHAINS, chainIdToPublicClient, getChainName, getExplorerAddressUrl } from "../../../anyspend/index.js";
3
3
  import { GlareCard, Popover, PopoverContent, PopoverTrigger } from "../../../global-account/react/index.js";
4
4
  import { cn } from "../../../shared/utils/index.js";
5
5
  import { getIpfsUrl } from "../../../shared/utils/ipfs.js";
6
6
  import { formatDisplayNumber, formatTokenAmount } from "../../../shared/utils/number.js";
7
7
  import { AnimatePresence } from "framer-motion";
8
8
  import { MoreVertical } from "lucide-react";
9
- import { useState } from "react";
9
+ import { useEffect, useState } from "react";
10
10
  import { b3 } from "viem/chains";
11
11
  import { AnySpendCustom } from "./AnySpendCustom.js";
12
+ // ABI for contractURI and uri functions
13
+ const CONTRACT_URI_ABI = [
14
+ {
15
+ inputs: [],
16
+ name: "contractURI",
17
+ outputs: [{ internalType: "string", name: "", type: "string" }],
18
+ stateMutability: "view",
19
+ type: "function",
20
+ },
21
+ {
22
+ inputs: [{ internalType: "uint256", name: "_tokenId", type: "uint256" }],
23
+ name: "uri",
24
+ outputs: [{ internalType: "string", name: "", type: "string" }],
25
+ stateMutability: "view",
26
+ type: "function",
27
+ },
28
+ ];
12
29
  export function AnySpendNFT({ isMainnet = true, loadOrder, mode = "modal", recipientAddress, nftContract, onSuccess, }) {
13
- const header = ({ anyspendPrice, isLoadingAnyspendPrice, }) => (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative size-[200px]", children: [_jsx("div", { className: "absolute inset-0 scale-95 bg-black/30 blur-md" }), _jsxs(GlareCard, { className: "overflow-hidden", children: [_jsx("img", { src: getIpfsUrl(nftContract.imageUrl), alt: nftContract.name, className: "size-full object-cover" }), _jsx("div", { className: "absolute inset-0 rounded-xl border border-white/10" })] }), _jsx(DropdownMenu, { nftContract: nftContract })] }), _jsxs("div", { className: "from-b3-react-background to-as-on-surface-1 mt-[-100px] w-full rounded-t-lg bg-gradient-to-t", children: [_jsx("div", { className: "h-[100px] w-full" }), _jsxs("div", { className: "mb-1 flex w-full flex-col items-center gap-2 p-5", children: [_jsx("span", { className: "font-sf-rounded text-2xl font-semibold", children: nftContract.name }), _jsx("div", { className: "flex w-fit items-center gap-1", children: anyspendPrice ? (_jsx(AnimatePresence, { mode: "wait", children: _jsx("div", { className: cn("text-as-primary group flex items-center text-3xl font-semibold transition-all", {
30
+ const [imageUrlWithFallback, setFallbackImageUrl] = useState(nftContract.imageUrl);
31
+ const [isLoadingFallback, setIsLoadingFallback] = useState(false);
32
+ // Fetch contract metadata when imageUrl is empty
33
+ useEffect(() => {
34
+ async function fetchContractMetadata() {
35
+ // fetch image Uri if not provided
36
+ if (nftContract.imageUrl || isLoadingFallback) {
37
+ return;
38
+ }
39
+ try {
40
+ setIsLoadingFallback(true);
41
+ // Use the chainIdToPublicClient utility function
42
+ const publicClient = chainIdToPublicClient(nftContract.chainId);
43
+ let metadataURI;
44
+ // Use uri function if tokenId is available, otherwise use contractURI
45
+ if (nftContract.tokenId !== null && nftContract.tokenId !== undefined) {
46
+ console.log("Using uri function with tokenId:", nftContract.tokenId);
47
+ metadataURI = await publicClient.readContract({
48
+ address: nftContract.contractAddress,
49
+ abi: CONTRACT_URI_ABI,
50
+ functionName: "uri",
51
+ args: [BigInt(nftContract.tokenId)],
52
+ });
53
+ }
54
+ else {
55
+ console.log("Using contractURI function");
56
+ metadataURI = await publicClient.readContract({
57
+ address: nftContract.contractAddress,
58
+ abi: CONTRACT_URI_ABI,
59
+ functionName: "contractURI",
60
+ });
61
+ }
62
+ if (metadataURI) {
63
+ // Fetch the metadata from IPFS
64
+ const metadataUrl = getIpfsUrl(metadataURI);
65
+ const response = await fetch(metadataUrl);
66
+ const metadata = await response.json();
67
+ if (metadata.image) {
68
+ const fallbackUrl = getIpfsUrl(metadata.image);
69
+ setFallbackImageUrl(fallbackUrl);
70
+ console.log("fallbackImageUrl", fallbackUrl);
71
+ }
72
+ }
73
+ }
74
+ catch (error) {
75
+ console.error("Error fetching contract metadata:", error);
76
+ }
77
+ finally {
78
+ setIsLoadingFallback(false);
79
+ }
80
+ }
81
+ fetchContractMetadata();
82
+ }, [nftContract.contractAddress, nftContract.chainId, nftContract.imageUrl, nftContract.tokenId]);
83
+ const header = ({ anyspendPrice, isLoadingAnyspendPrice, }) => (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative size-[200px]", children: [_jsx("div", { className: "absolute inset-0 scale-95 bg-black/30 blur-md" }), _jsxs(GlareCard, { className: "overflow-hidden", children: [imageUrlWithFallback && (_jsx("img", { src: imageUrlWithFallback, alt: nftContract.name, className: "size-full object-cover" })), _jsx("div", { className: "absolute inset-0 rounded-xl border border-white/10" })] }), _jsx(DropdownMenu, { nftContract: nftContract })] }), _jsxs("div", { className: "from-b3-react-background to-as-on-surface-1 mt-[-100px] w-full rounded-t-lg bg-gradient-to-t", children: [_jsx("div", { className: "h-[100px] w-full" }), _jsxs("div", { className: "mb-1 flex w-full flex-col items-center gap-2 p-5", children: [_jsx("span", { className: "font-sf-rounded text-2xl font-semibold", children: nftContract.name }), _jsx("div", { className: "flex w-fit items-center gap-1", children: anyspendPrice ? (_jsx(AnimatePresence, { mode: "wait", children: _jsx("div", { className: cn("text-as-primary group flex items-center text-3xl font-semibold transition-all", {
14
84
  "opacity-0": isLoadingAnyspendPrice,
15
85
  }), children: formatDisplayNumber(anyspendPrice?.data?.currencyIn?.amountUsd, { style: "currency" }) }) })) : (_jsx("div", { className: "h-[36px] w-full" })) })] })] })] }));
16
86
  return (_jsx(AnySpendCustom, { isMainnet: isMainnet, loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, orderType: "mint_nft", dstChainId: nftContract.chainId, dstToken: nftContract.currency, dstAmount: nftContract.price, contractAddress: nftContract.contractAddress, encodedData: "0x", metadata: {
@@ -1673,7 +1673,7 @@ export interface components {
1673
1673
  * @description NFT image URL
1674
1674
  * @example https://example.com/nft.png
1675
1675
  */
1676
- imageUrl: string;
1676
+ imageUrl: string | null;
1677
1677
  /**
1678
1678
  * @description NFT name
1679
1679
  * @example Cool NFT Collection
@@ -864,7 +864,7 @@ export const getV1NftsByContractAddress = (options) => {
864
864
  type: 'apiKey'
865
865
  }
866
866
  ],
867
- url: 'https://insight.thirdweb.com/v1/nfts/{contract_address}',
867
+ url: '/v1/nfts/{contract_address}',
868
868
  ...options
869
869
  });
870
870
  };
@@ -3,7 +3,7 @@ import { client } from "./generated/client.gen.js";
3
3
  (function () {
4
4
  // Set BASE URL
5
5
  client.setConfig({
6
- baseUrl: "https://insight.thirdweb.com",
6
+ baseUrl: "https://8333.insight.thirdweb.com",
7
7
  });
8
8
  // Interceptors for issues described here https://npc-labs.slack.com/archives/C070E6HNG85/p1742446793549779?thread_ts=1741637902.666019&cid=C070E6HNG85
9
9
  client.interceptors.request.use((request, options) => {
@@ -8,6 +8,7 @@ export declare const SOLANA_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = "ATokenGPvbdGV
8
8
  export declare const SOLANA_TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
9
9
  export declare const B3_TOKEN: components["schemas"]["Token"];
10
10
  export declare const USDC_BASE: components["schemas"]["Token"];
11
+ export declare const ETH_BASE: components["schemas"]["Token"];
11
12
  export declare const NFT_CONTRACTS: components["schemas"]["NftContract"][];
12
13
  export declare const DEFAULT_NFT_CONTRACT: {
13
14
  chainId: number;
@@ -15,7 +16,7 @@ export declare const DEFAULT_NFT_CONTRACT: {
15
16
  price: string;
16
17
  priceFormatted: string;
17
18
  currency: components["schemas"]["Token"];
18
- imageUrl: string;
19
+ imageUrl: string | null;
19
20
  name: string;
20
21
  description: string;
21
22
  tokenId: number | null;
@@ -1673,7 +1673,7 @@ export interface components {
1673
1673
  * @description NFT image URL
1674
1674
  * @example https://example.com/nft.png
1675
1675
  */
1676
- imageUrl: string;
1676
+ imageUrl: string | null;
1677
1677
  /**
1678
1678
  * @description NFT name
1679
1679
  * @example Cool NFT Collection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.0.9-alpha.9",
3
+ "version": "0.0.10",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -191,7 +191,7 @@
191
191
  ],
192
192
  "dependencies": {
193
193
  "@amplitude/analytics-browser": "2.14.0",
194
- "@b3dotfun/b3-api": "0.0.26",
194
+ "@b3dotfun/b3-api": "0.0.27",
195
195
  "@b3dotfun/basement-api": "0.0.11",
196
196
  "@b3dotfun/bondkit": "^0.1.17",
197
197
  "@chakra-ui/react": "2.10.7",
@@ -34,6 +34,17 @@ export const USDC_BASE: components["schemas"]["Token"] = {
34
34
  },
35
35
  };
36
36
 
37
+ export const ETH_BASE: components["schemas"]["Token"] = {
38
+ symbol: "ETH",
39
+ chainId: base.id,
40
+ address: "0x0000000000000000000000000000000000000000",
41
+ name: "Ethereum",
42
+ decimals: 18,
43
+ metadata: {
44
+ logoURI: "https://polygonscan.com/token/images/eth_32.png",
45
+ },
46
+ };
47
+
37
48
  export const NFT_CONTRACTS: components["schemas"]["NftContract"][] = [
38
49
  {
39
50
  chainId: base.id,
@@ -1,15 +1,34 @@
1
- import { ALL_CHAINS, getChainName, getExplorerAddressUrl } from "@b3dotfun/sdk/anyspend";
1
+ import { ALL_CHAINS, chainIdToPublicClient, getChainName, getExplorerAddressUrl } from "@b3dotfun/sdk/anyspend";
2
+ import { components } from "@b3dotfun/sdk/anyspend/types/api";
2
3
  import { GlareCard, Popover, PopoverContent, PopoverTrigger } from "@b3dotfun/sdk/global-account/react";
3
4
  import { cn } from "@b3dotfun/sdk/shared/utils";
4
5
  import { getIpfsUrl } from "@b3dotfun/sdk/shared/utils/ipfs";
6
+
5
7
  import { formatDisplayNumber, formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
6
8
  import { AnimatePresence } from "framer-motion";
7
9
  import { MoreVertical } from "lucide-react";
8
- import { useState } from "react";
10
+ import { useEffect, useState } from "react";
9
11
  import { b3 } from "viem/chains";
10
- import { AnySpendCustom } from "./AnySpendCustom";
11
12
  import { GetQuoteResponse } from "../../types/api_req_res";
12
- import { components } from "@b3dotfun/sdk/anyspend/types/api";
13
+ import { AnySpendCustom } from "./AnySpendCustom";
14
+
15
+ // ABI for contractURI and uri functions
16
+ const CONTRACT_URI_ABI = [
17
+ {
18
+ inputs: [],
19
+ name: "contractURI",
20
+ outputs: [{ internalType: "string", name: "", type: "string" }],
21
+ stateMutability: "view",
22
+ type: "function",
23
+ },
24
+ {
25
+ inputs: [{ internalType: "uint256", name: "_tokenId", type: "uint256" }],
26
+ name: "uri",
27
+ outputs: [{ internalType: "string", name: "", type: "string" }],
28
+ stateMutability: "view",
29
+ type: "function",
30
+ },
31
+ ] as const;
13
32
 
14
33
  export function AnySpendNFT({
15
34
  isMainnet = true,
@@ -26,6 +45,65 @@ export function AnySpendNFT({
26
45
  nftContract: components["schemas"]["NftContract"];
27
46
  onSuccess?: (txHash?: string) => void;
28
47
  }) {
48
+ const [imageUrlWithFallback, setFallbackImageUrl] = useState<string | null>(nftContract.imageUrl);
49
+ const [isLoadingFallback, setIsLoadingFallback] = useState(false);
50
+
51
+ // Fetch contract metadata when imageUrl is empty
52
+ useEffect(() => {
53
+ async function fetchContractMetadata() {
54
+ // fetch image Uri if not provided
55
+ if (nftContract.imageUrl || isLoadingFallback) {
56
+ return;
57
+ }
58
+
59
+ try {
60
+ setIsLoadingFallback(true);
61
+
62
+ // Use the chainIdToPublicClient utility function
63
+ const publicClient = chainIdToPublicClient(nftContract.chainId);
64
+
65
+ let metadataURI: string;
66
+
67
+ // Use uri function if tokenId is available, otherwise use contractURI
68
+ if (nftContract.tokenId !== null && nftContract.tokenId !== undefined) {
69
+ console.log("Using uri function with tokenId:", nftContract.tokenId);
70
+ metadataURI = await publicClient.readContract({
71
+ address: nftContract.contractAddress as `0x${string}`,
72
+ abi: CONTRACT_URI_ABI,
73
+ functionName: "uri",
74
+ args: [BigInt(nftContract.tokenId)],
75
+ });
76
+ } else {
77
+ console.log("Using contractURI function");
78
+ metadataURI = await publicClient.readContract({
79
+ address: nftContract.contractAddress as `0x${string}`,
80
+ abi: CONTRACT_URI_ABI,
81
+ functionName: "contractURI",
82
+ });
83
+ }
84
+
85
+ if (metadataURI) {
86
+ // Fetch the metadata from IPFS
87
+ const metadataUrl = getIpfsUrl(metadataURI);
88
+ const response = await fetch(metadataUrl);
89
+ const metadata = await response.json();
90
+
91
+ if (metadata.image) {
92
+ const fallbackUrl = getIpfsUrl(metadata.image);
93
+ setFallbackImageUrl(fallbackUrl);
94
+ console.log("fallbackImageUrl", fallbackUrl);
95
+ }
96
+ }
97
+ } catch (error) {
98
+ console.error("Error fetching contract metadata:", error);
99
+ } finally {
100
+ setIsLoadingFallback(false);
101
+ }
102
+ }
103
+
104
+ fetchContractMetadata();
105
+ }, [nftContract.contractAddress, nftContract.chainId, nftContract.imageUrl, nftContract.tokenId]);
106
+
29
107
  const header = ({
30
108
  anyspendPrice,
31
109
  isLoadingAnyspendPrice,
@@ -37,7 +115,9 @@ export function AnySpendNFT({
37
115
  <div className="relative size-[200px]">
38
116
  <div className="absolute inset-0 scale-95 bg-black/30 blur-md"></div>
39
117
  <GlareCard className="overflow-hidden">
40
- <img src={getIpfsUrl(nftContract.imageUrl)} alt={nftContract.name} className="size-full object-cover" />
118
+ {imageUrlWithFallback && (
119
+ <img src={imageUrlWithFallback} alt={nftContract.name} className="size-full object-cover" />
120
+ )}
41
121
  <div className="absolute inset-0 rounded-xl border border-white/10"></div>
42
122
  </GlareCard>
43
123
 
@@ -1698,7 +1698,7 @@ export interface components {
1698
1698
  * @description NFT image URL
1699
1699
  * @example https://example.com/nft.png
1700
1700
  */
1701
- imageUrl: string;
1701
+ imageUrl: string | null;
1702
1702
  /**
1703
1703
  * @description NFT name
1704
1704
  * @example Cool NFT Collection
@@ -915,7 +915,7 @@ export const getV1NftsByContractAddress = <ThrowOnError extends boolean = false>
915
915
  type: 'apiKey'
916
916
  }
917
917
  ],
918
- url: 'https://insight.thirdweb.com/v1/nfts/{contract_address}',
918
+ url: '/v1/nfts/{contract_address}',
919
919
  ...options
920
920
  });
921
921
  };
@@ -4,7 +4,7 @@ import { client } from "./generated/client.gen";
4
4
  (function () {
5
5
  // Set BASE URL
6
6
  client.setConfig({
7
- baseUrl: "https://insight.thirdweb.com",
7
+ baseUrl: "https://8333.insight.thirdweb.com",
8
8
  });
9
9
 
10
10
  // Interceptors for issues described here https://npc-labs.slack.com/archives/C070E6HNG85/p1742446793549779?thread_ts=1741637902.666019&cid=C070E6HNG85