Skip to content

Commit

Permalink
fix: pricing data from dispensers on stamps
Browse files Browse the repository at this point in the history
  • Loading branch information
reinamora137 committed Jan 16, 2025
1 parent b734ac3 commit 783b2fa
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 90 deletions.
8 changes: 4 additions & 4 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@
"dayjs": "https://esm.sh/dayjs@1.11.10",
"dayjs/": "https://esm.sh/dayjs@1.11.10/",
"djwt/": "https://deno.land/x/djwt@v3.0.2/",
"dom": "https://deno.land/x/deno_dom@v0.1.49/deno-dom-wasm.ts",
"flatpickr": "https://esm.sh/flatpickr@4.6.13",
"flatpickr/": "https://esm.sh/flatpickr@4.6.13/",
"$fresh/": "https://deno.land/x/fresh@1.7.3/",
"fresh_charts/": "https://deno.land/x/fresh_charts@0.3.1/",
"fresh/tests/": "https://deno.land/x/fresh@1.7.6/tests/",
Expand All @@ -120,10 +123,7 @@
"$lib/": "./lib/",
"$routes/": "./routes/",
"$server/": "./server/",
"$types/": "./lib/types/",
"flatpickr": "https://esm.sh/flatpickr@4.6.13",
"flatpickr/": "https://esm.sh/flatpickr@4.6.13/",
"dom": "https://deno.land/x/deno_dom/deno-dom-wasm.ts"
"$types/": "./lib/types/"
},
"compilerOptions": {
"jsx": "react-jsx",
Expand Down
28 changes: 14 additions & 14 deletions islands/stamp/StampCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -269,24 +269,24 @@ export function StampCard({
} BTC`,
style: TEXT_STYLES.price,
};
} else if (stamp.floorPrice !== "priceless") {
return {
text: `${stripTrailingZeros(Number(stamp.floorPrice).toFixed(8))} BTC`,
style: TEXT_STYLES.price,
};
} else if (stamp.recentSalePrice !== "priceless") {
}

// Handle floor price or recent sale price
const price = stamp.floorPrice !== "priceless"
? stamp.floorPrice
: stamp.recentSalePrice;
if (price !== "priceless" && !isNaN(Number(price))) {
return {
text: `${
stripTrailingZeros(Number(stamp.recentSalePrice).toFixed(8))
} BTC`,
text: `${stripTrailingZeros(Number(price).toFixed(8))} BTC`,
style: TEXT_STYLES.price,
};
} else {
return {
text: stamp.stamp_mimetype?.split("/")[1].toUpperCase() || "UNKNOWN",
style: TEXT_STYLES.mimeType,
};
}

// Default to mime type if no valid price
return {
text: stamp.stamp_mimetype?.split("/")[1].toUpperCase() || "UNKNOWN",
style: TEXT_STYLES.mimeType,
};
};

const shouldDisplayHash = Number(stamp.stamp ?? 0) >= 0 ||
Expand Down
31 changes: 28 additions & 3 deletions lib/utils/balanceUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,31 @@ import {
import { BLOCKCYPHER_API_BASE_URL } from "$lib/utils/constants.ts";
import { getBTCBalanceFromMempool } from "$lib/utils/mempool.ts";

// Cache for BTC price with TTL
let btcPriceCache: {
price: number;
timestamp: number;
} | null = null;

const CACHE_TTL = 10 * 60 * 1000; // 5 minutes in milliseconds

export async function fetchBTCPriceInUSD(apiBaseUrl?: string): Promise<number> {
const requestId = `btc-price-${Date.now()}-${
Math.random().toString(36).substr(2, 9)
}`;

// Check cache first
if (btcPriceCache && Date.now() - btcPriceCache.timestamp < CACHE_TTL) {
console.log(
`[${requestId}] Using cached BTC price: ${btcPriceCache.price}`,
);
return btcPriceCache.price;
}

console.log(
`[${requestId}] Fetching BTC price, apiBaseUrl: ${apiBaseUrl || "none"}`,
`[${requestId}] Cache miss, fetching BTC price, apiBaseUrl: ${
apiBaseUrl || "none"
}`,
);

try {
Expand All @@ -33,7 +52,7 @@ export async function fetchBTCPriceInUSD(apiBaseUrl?: string): Promise<number> {
console.warn(
`[${requestId}] BTC price endpoint returned ${response.status}: ${response.statusText}`,
);
return 0;
return btcPriceCache?.price || 0; // Return cached price if available, otherwise 0
}

const text = await response.text();
Expand All @@ -45,10 +64,16 @@ export async function fetchBTCPriceInUSD(apiBaseUrl?: string): Promise<number> {
const price = formatUSDValue(data.data?.price || 0);
console.log(`[${requestId}] Formatted price: ${price}`);

// Update cache
btcPriceCache = {
price,
timestamp: Date.now(),
};

return price;
} catch (error) {
console.error(`[${requestId}] Error fetching BTC price:`, error);
return 0;
return btcPriceCache?.price || 0; // Return cached price if available, otherwise 0
}
}

Expand Down
98 changes: 43 additions & 55 deletions routes/stamp/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,39 +18,25 @@ import { DispenserManager } from "$server/services/xcpService.ts";
import { RouteType } from "$server/services/cacheService.ts";
import { DOMParser } from "dom";

interface Holder {
address: string | null;
quantity: number;
amt: number;
percentage: number;
}

interface StampDetailPageProps {
data: {
stamp: StampRow;
htmlTitle: string | undefined;
total: number;
sends: any;
dispensers: any;
dispenses: any;
holders: any;
vaults: any;
last_block: number;
stamps_recent: any;
lowestPriceDispenser: any; // Add this property
};
}

interface StampData {
stamp: StampRow;
stamp: StampRow & { name?: string };
total: number;
sends: any;
dispensers: any;
dispenses: any;
holders: any;
holders: any[];
vaults: any;
last_block: number;
stamps_recent: any;
lowestPriceDispenser: any;
htmlTitle?: string;
error?: string;
url: string;
}

interface StampDetailPageProps {
data: StampData;
url?: string;
}

export const handler: Handlers<StampData> = {
Expand Down Expand Up @@ -109,20 +95,6 @@ export const handler: Handlers<StampData> = {
btcPrice,
);

const calculateHoldersWithPercentage = (rawHolders: Holder[]) => {
const totalQuantity = rawHolders.reduce(
(sum, holder) => sum + holder.quantity,
0,
);
return rawHolders.map((holder) => ({
...holder,
amt: holder.quantity,
percentage: Number(
((holder.quantity / totalQuantity) * 100).toFixed(2),
),
}));
};

let htmlTitle = null;
if (
stampWithPrices.stamp_mimetype === "text/html" &&
Expand All @@ -142,8 +114,8 @@ export const handler: Handlers<StampData> = {
stamp: stampWithPrices,
htmlTitle: htmlTitle,
last_block: stampData.last_block,
stamps_recent: mainCategories[0]?.stamps ?? [], // Use the stamps from mainCategories
holders: calculateHoldersWithPercentage(holders.data),
stamps_recent: mainCategories[0]?.stamps ?? [],
holders: holders.data,
lowestPriceDispenser: lowestPriceDispenser,
url: req.url,
});
Expand All @@ -154,6 +126,17 @@ export const handler: Handlers<StampData> = {
}
return ctx.render({
error: error instanceof Error ? error.message : "Internal server error",
stamp: {} as StampRow,
total: 0,
sends: [],
dispensers: [],
dispenses: [],
holders: [],
vaults: [],
last_block: 0,
stamps_recent: [],
lowestPriceDispenser: null,
url: req.url,
});
}
},
Expand Down Expand Up @@ -203,20 +186,25 @@ export default function StampPage(props: StampDetailPageProps) {
stamp,
htmlTitle,
holders,
_sends,
stamps_recent,
_dispensers = [],
_dispenses = [],
lowestPriceDispenser = null,
} = props.data;
const title = htmlTitle
? htmlTitle.toUpperCase()
: stamp.cpid.startsWith("A")
? `Bitcoin Stamp #${stamp.stamp} - stampchain.io`
: stamp.cpid;
: stamp?.cpid?.startsWith("A")
? `Bitcoin Stamp #${stamp?.stamp || ""} - stampchain.io`
: stamp?.cpid || "Stamp Not Found";

// Update the getMetaImageInfo and add dimension handling
const getMetaImageInfo = (stamp: StampRow | undefined, baseUrl: string) => {
if (!stamp) {
return {
url: `${baseUrl}/default-stamp-image.png`, // You should add a default image
width: 1200,
height: 1200,
};
}

// Update the getMetaImageUrl and add dimension handling
const getMetaImageInfo = (stamp: StampRow, baseUrl: string) => {
// For HTML/SVG content, use preview endpoint with known dimensions
if (
stamp.stamp_mimetype === "text/html" ||
Expand All @@ -235,11 +223,11 @@ export default function StampPage(props: StampDetailPageProps) {
};
};

const baseUrl = new URL(props.url).origin;
const baseUrl = new URL(props.url || "").origin;
const metaInfo = getMetaImageInfo(stamp, baseUrl);
const metaDescription = `Bitcoin Stamp #${stamp.stamp} - ${
stamp.name || "Unprunable UTXO Art"
}`;
const metaDescription = stamp
? `Bitcoin Stamp #${stamp.stamp} - ${stamp.name || "Unprunable UTXO Art"}`
: "Bitcoin Stamp - Unprunable UTXO Art";

const bodyClassName = "flex flex-col gap-6";

Expand Down Expand Up @@ -320,8 +308,8 @@ export default function StampPage(props: StampDetailPageProps) {
)}

<StampRelatedInfo
stampId={stamp.stamp?.toString() || ""}
cpid={stamp.cpid}
_stampId={stamp?.stamp?.toString() || ""}
cpid={stamp?.cpid || ""}
/>

<div class="pt-12 mobileLg:pt-24 desktop:pt-36">
Expand Down
1 change: 1 addition & 0 deletions routes/stamp/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const handler: Handlers = {
filterBy,
ident,
collectionId,
url: url.origin,
});
}

Expand Down
20 changes: 18 additions & 2 deletions schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2096,7 +2096,15 @@ components:
floorPrice:
type: number
nullable: true
description: "Current floor price in BTC, or 'priceless' if no open dispensers"
description: "Current floor price in BTC. Uses lowest open dispenser price, or most recent closed dispenser price if no open dispensers exist"
floorPriceUSD:
type: number
nullable: true
description: "Floor price converted to USD using current BTC/USD exchange rate"
marketCapUSD:
type: number
nullable: true
description: "Market capitalization in USD (supply * floorPrice * BTC/USD rate)"
StampRowSummary:
type: object
properties:
Expand Down Expand Up @@ -2141,7 +2149,15 @@ components:
floorPrice:
type: number
nullable: true
description: "Current floor price in BTC, or 'priceless' if no open dispensers"
description: "Current floor price in BTC. Uses lowest open dispenser price, or most recent closed dispenser price if no open dispensers exist"
floorPriceUSD:
type: number
nullable: true
description: "Floor price converted to USD using current BTC/USD exchange rate"
marketCapUSD:
type: number
nullable: true
description: "Market capitalization in USD (supply * floorPrice * BTC/USD rate)"
BlockStampRow:
type: object
properties:
Expand Down
Loading

0 comments on commit 783b2fa

Please sign in to comment.