helpers.ts
1 import { DATE_URL } from "./data-url"; 2 import { 3 BlockchainInfo, 4 Difficulty, 5 Issuance, 6 IssuanceParsed, 7 LockBox, 8 NetInOutflow, 9 NodeCountData, 10 ShieldedAmountDatum, 11 ShieldedTransactionDatum, 12 ShieldedTxCount, 13 SupplyData, 14 } from "./types"; 15 16 export async function getBlockchainData( 17 url: string, 18 signal?: AbortSignal 19 ): Promise<BlockchainInfo | null> { 20 try { 21 const res = await fetch(url, { 22 signal, 23 }); 24 if (!res.ok) return null; 25 const json = await res.json(); 26 return json.data as BlockchainInfo; 27 } catch { 28 return null; 29 } 30 } 31 export async function getIssuanceData( 32 url: string, 33 signal?: AbortSignal 34 ): Promise<IssuanceParsed[] | null> { 35 try { 36 const res = await fetch(url, { 37 signal, 38 }); 39 if (!res.ok) return null; 40 const data: Issuance[] = await res.json(); 41 42 const parsed = data.map((entry) => ({ 43 Date: entry.Date, 44 zecIssuance: parseFloat(entry["ZEC Supply"]), 45 zecSupply: parseFloat(entry["ZEC Supply"]), 46 inflation: parseFloat(entry["Current Inflation (%)"]), 47 })); 48 49 return parsed; 50 } catch { 51 return null; 52 } 53 } 54 55 export async function getZcashCirculationCount( 56 url: string, 57 signal?: AbortSignal 58 ): Promise<number | null> { 59 try { 60 const res = await fetch(url, { 61 signal, 62 }); 63 if (!res.ok) return null; 64 const json = await res.json(); 65 return parseInt(json.chainSupply.chainValueZat, 10) * 1e-8; 66 } catch { 67 return null; 68 } 69 } 70 71 export async function getSupplyData( 72 url: string, 73 signal?: AbortSignal 74 ): Promise<SupplyData[]> { 75 try { 76 const res = await fetch(url, { 77 signal, 78 }); 79 if (!res.ok) return []; 80 return (await res.json()) as SupplyData[]; 81 } catch { 82 return []; 83 } 84 } 85 86 export async function getLastUpdatedDate( 87 url: string, 88 signal?: AbortSignal 89 ): Promise<string> { 90 try { 91 const res = await fetch(url, { 92 signal, 93 }); 94 if (!res.ok) return "N/A"; 95 const d = await res.json(); 96 97 console.log("djson", d); 98 return d[0]?.commit?.committer?.date ?? "N/A"; 99 } catch { 100 return "N/A"; 101 } 102 } 103 104 export function getCommitUrlForTab(tabLabel: string): string { 105 const urlMap: Record<string, string> = { 106 "total supply": DATE_URL.namadaSupplyUrl, 107 "Shielded Supply": DATE_URL.namadaSupplyUrl, 108 "transparant supply": DATE_URL.namadaSupplyUrl, 109 rewards: DATE_URL.namadaRewardUrl, 110 }; 111 112 return urlMap[tabLabel] || DATE_URL.namadaSupplyUrl; 113 } 114 115 export async function getShieldedTxCount( 116 url: string, 117 signal?: AbortSignal 118 ): Promise<ShieldedTxCount[] | null> { 119 try { 120 const res = await fetch(url, { 121 signal, 122 }); 123 if (!res.ok) return null; 124 return (await res.json()) as ShieldedTxCount[]; 125 } catch { 126 return null; 127 } 128 } 129 130 export async function getNodeCountData( 131 url: string, 132 signal?: AbortSignal 133 ): Promise<NodeCountData[]> { 134 try { 135 const res = await fetch(url, { 136 signal, 137 }); 138 if (!res.ok) return []; 139 return (await res.json()) as NodeCountData[]; 140 } catch { 141 return []; 142 } 143 } 144 145 export async function getLockboxData( 146 url: string, 147 signal?: AbortSignal 148 ): Promise<LockBox[]> { 149 try { 150 const res = await fetch(url, { signal }); 151 152 if (!res.ok) { 153 console.warn(`Fetch failed: ${res.status} ${res.statusText}`); 154 return []; 155 } 156 157 const data: any[] = await res.json(); 158 return data; 159 } catch (err: any) { 160 if (err.name === "AbortError") { 161 console.warn("Fetch aborted."); 162 } else { 163 console.error(err.message || err); 164 } 165 return []; 166 } 167 } 168 export async function getNetInOutflowData( 169 url: string, 170 signal?: AbortSignal 171 ): Promise<NetInOutflow[]> { 172 try { 173 const res = await fetch(url, { signal }); 174 175 if (!res.ok) { 176 console.warn(`Fetch failed: ${res.status} ${res.statusText}`); 177 return []; 178 } 179 180 const data: any[] = await res.json(); 181 return data; 182 } catch (err: any) { 183 if (err.name === "AbortError") { 184 console.warn("Fetch aborted."); 185 } else { 186 console.error(err.message || err); 187 } 188 return []; 189 } 190 } 191 export async function getDifficultyData( 192 url: string, 193 signal?: AbortSignal 194 ): Promise<Difficulty[]> { 195 try { 196 const res = await fetch(url, { signal }); 197 198 if (!res.ok) { 199 console.warn(`Fetch failed: ${res.status} ${res.statusText}`); 200 return []; 201 } 202 203 const data: any[] = await res.json(); 204 return data; 205 } catch (err: any) { 206 if (err.name === "AbortError") { 207 console.warn("Fetch aborted."); 208 } else { 209 console.error(err.message || err); 210 } 211 return []; 212 } 213 } 214 215 export async function getNamadaSupply( 216 url: string, 217 signal?: AbortSignal 218 ): Promise<any[]> { 219 try { 220 const res = await fetch(url, { signal }); 221 222 if (!res.ok) { 223 console.warn(`Fetch failed: ${res.status} ${res.statusText}`); 224 return []; 225 } 226 227 const data: any[] = await res.json(); 228 return data; 229 } catch (err: any) { 230 if (err.name === "AbortError") { 231 console.warn("Fetch aborted."); 232 } else { 233 console.error("Error fetching Namada supply:", err.message || err); 234 } 235 return []; 236 } 237 } 238 239 export async function fetchTransactionData( 240 url: string 241 ): Promise<Array<ShieldedTransactionDatum>> { 242 const response = await fetch(url); 243 if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); 244 return await response.json(); 245 } 246 /** 247 * Loads the historic shielded pool data from a public json file in Github repo 248 * @returns Promise of shielded pool data 249 */ 250 export async function fetchShieldedSupplyData( 251 url: string, 252 signal?: AbortSignal 253 ): Promise<Array<ShieldedAmountDatum>> { 254 const response = await fetch(url); 255 if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); 256 return await response.json(); 257 } 258 259 export function formatDate(s: string | null): string { 260 if (!s) return "N/A"; 261 const d = new Date(s); 262 return isNaN(d.getTime()) ? "N/A" : d.toLocaleDateString(); 263 } 264 265 export function transformSupplyData( 266 d: SupplyData | null 267 ): { timestamp: string; supply: number } | null { 268 return d ? { timestamp: d.close, supply: d.supply } : null; 269 } 270 271 export type PoolType = "sprout" | "sapling" | "orchard"; 272 export const getColorForPool = (poolKey: PoolType): string => { 273 switch (poolKey) { 274 case "sprout": 275 return "hsl(var(--chart-1))"; 276 case "sapling": 277 return "hsl(var(--chart-2))"; 278 case "orchard": 279 return "hsl(var(--chart-3))"; 280 default: 281 return "#999999"; // fallback gray 282 } 283 }; 284 285 export function formatNumberShort(num: number): string { 286 const absNum = Math.abs(num); 287 const sign = num < 0 ? "-" : ""; 288 289 if (absNum >= 1_000_000_000) 290 return `${sign}${(absNum / 1_000_000_000).toFixed(1)}B`; 291 if (absNum >= 1_000_000) return `${sign}${(absNum / 1_000_000).toFixed(1)}M`; 292 if (absNum >= 1_000) return `${sign}${(absNum / 1_000).toFixed(1)}k`; 293 294 return `${sign}${absNum.toLocaleString()}`; 295 }