@flapsdk/vault-runtime 0.1.2 → 0.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flapsdk/vault-runtime",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Shared runtime surface for Flap Vault UI hosts, Workbench preview, and custom Vault components.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "runtimeContractVersion": 1,
3
3
  "packageName": "@flapsdk/vault-runtime",
4
- "packageVersion": "0.1.2",
4
+ "packageVersion": "0.1.4",
5
5
  "stableAuthoringAliases": [
6
6
  "@/src/sdk",
7
7
  "@/src/ui"
package/server.js CHANGED
@@ -252,6 +252,9 @@ async function fetchProvisionedOracle({
252
252
  // src/sdk/oracleServer.ts
253
253
  var FLAP_RUNTIME_ORACLE_REGISTRY_ENV = "FLAP_RUNTIME_ORACLE_REGISTRY";
254
254
  var DEFAULT_EXAMPLE_ORACLE_SIGNATURE = "0x000000000000000000000000000000000000dEaD";
255
+ var BNB_USD_ORACLE_ID = "bnb-usd-price";
256
+ var BNB_USD_BINANCE_ENDPOINT = "https://api.binance.com/api/v3/avgPrice?symbol=BNBUSDT";
257
+ var BNB_USD_PYTH_ENDPOINT = "https://hermes.pyth.network/v2/updates/price/latest?ids%5B%5D=0x2f95862b045670cd22bee3114c39763a4a08beeb663b145d283c31d7d1101c4f&encoding=base64&parsed=true";
255
258
  function normalizeHeaders(headers) {
256
259
  if (!headers || typeof headers !== "object" || Array.isArray(headers)) return void 0;
257
260
  const entries = Object.entries(headers).filter(([, value]) => typeof value === "string").map(([key, value]) => [key, value.trim()]).filter(([, value]) => value);
@@ -307,6 +310,60 @@ function loadDefaultRuntimeOracle(oracleId) {
307
310
  }
308
311
  return null;
309
312
  }
313
+ function readPositiveNumber(value) {
314
+ const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
315
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
316
+ }
317
+ async function fetchJson(endpoint, fetchImpl) {
318
+ const response = await (fetchImpl ?? fetch)(endpoint, {
319
+ cache: "no-store",
320
+ method: "GET"
321
+ });
322
+ if (!response.ok) {
323
+ throw new Error(`Runtime oracle request returned ${response.status}.`);
324
+ }
325
+ return response.json();
326
+ }
327
+ async function loadBnbUsdFromBinance(fetchImpl) {
328
+ const data = await fetchJson(BNB_USD_BINANCE_ENDPOINT, fetchImpl);
329
+ const price = readPositiveNumber(data?.price);
330
+ if (price === null) {
331
+ throw new Error("BNB/USD Binance oracle response did not include a positive price.");
332
+ }
333
+ return {
334
+ price,
335
+ symbol: "BNBUSDT",
336
+ timestamp: Math.floor(Date.now() / 1e3),
337
+ source: "binance"
338
+ };
339
+ }
340
+ async function loadBnbUsdFromPyth(fetchImpl) {
341
+ const data = await fetchJson(BNB_USD_PYTH_ENDPOINT, fetchImpl);
342
+ const priceData = data?.parsed?.[0]?.price;
343
+ const rawPrice = readPositiveNumber(priceData?.price);
344
+ const exponent = typeof priceData?.expo === "number" ? priceData.expo : typeof priceData?.expo === "string" ? Number(priceData.expo) : NaN;
345
+ if (rawPrice === null || !Number.isFinite(exponent)) {
346
+ throw new Error("BNB/USD Pyth oracle response did not include a usable price.");
347
+ }
348
+ const price = rawPrice * 10 ** exponent;
349
+ if (!Number.isFinite(price) || price <= 0) {
350
+ throw new Error("BNB/USD Pyth oracle response produced an invalid price.");
351
+ }
352
+ return {
353
+ price,
354
+ symbol: "BNBUSD",
355
+ timestamp: Math.floor(readPositiveNumber(priceData?.publish_time) ?? Date.now() / 1e3),
356
+ source: "pyth"
357
+ };
358
+ }
359
+ async function loadBuiltinRuntimeOracle(oracleId, fetchImpl) {
360
+ if (oracleId !== BNB_USD_ORACLE_ID) return null;
361
+ try {
362
+ return await loadBnbUsdFromBinance(fetchImpl);
363
+ } catch {
364
+ return await loadBnbUsdFromPyth(fetchImpl);
365
+ }
366
+ }
310
367
  async function loadRuntimeOracle({
311
368
  oracleId,
312
369
  params,
@@ -314,12 +371,14 @@ async function loadRuntimeOracle({
314
371
  fetchImpl
315
372
  }) {
316
373
  const provision = resolveRuntimeOracleProvision(oracleId, registry);
317
- if (!provision) return null;
318
- return fetchProvisionedOracle({
319
- provision,
320
- params,
321
- fetchImpl
322
- });
374
+ if (provision) {
375
+ return fetchProvisionedOracle({
376
+ provision,
377
+ params,
378
+ fetchImpl
379
+ });
380
+ }
381
+ return loadBuiltinRuntimeOracle(oracleId, fetchImpl);
323
382
  }
324
383
 
325
384
  export { FLAP_RUNTIME_ORACLE_REGISTRY_ENV, createLocalHostPresentationFetcher, getTaxVaultHostChainConfig, loadDefaultRuntimeOracle, loadFlapHostTokenPresentation, loadFlapHostTokenPresentationBatch, loadRuntimeOracle, parseRuntimeOracleRegistry, resolveRuntimeOracleProvision };
package/server.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/sdk/hostRuntimeConfig.ts","../../src/sdk/hostPresentation.ts","../../src/sdk/oracle.ts","../../src/sdk/oracleServer.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["import type { Address } from \"./types\";\n\nexport interface TaxVaultHostChainConfig {\n portal: Address;\n taxTokenHelperAddress?: Address;\n vaultPortal?: Address;\n wrappedNativeTokenAddress?: Address;\n giftVaultFactory?: Address;\n hostChainSlug?: string;\n ipfsGateway?: string;\n}\n\nconst taxVaultHostChains: Record<number, TaxVaultHostChainConfig> = {\n 56: {\n portal: \"0xe2ce6ab80874fa9fa2aae65d277dd6b8e65c9de0\",\n taxTokenHelperAddress: \"0x53841c73217735F37BC1775538b03b23feFD8346\",\n vaultPortal: \"0x90497450f2a706f1951b5bdda52B4E5d16f34C06\",\n wrappedNativeTokenAddress: \"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c\",\n giftVaultFactory: \"0x025549F52B03cF36f9e1a337c02d3AA7Af66ab32\",\n hostChainSlug: \"bnb\",\n ipfsGateway: \"https://gateway.pinata.cloud\",\n },\n 97: {\n portal: \"0x5bEacaF7ABCbB3aB280e80D007FD31fcE26510e9\",\n taxTokenHelperAddress: \"0xD64441e5FcD02D342B8cf6eBA10Ef6E40d0dA90f\",\n vaultPortal: \"0x027e3704fC5C16522e9393d04C60A3ac5c0d775f\",\n wrappedNativeTokenAddress: \"0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd\",\n giftVaultFactory: \"0xa02DA44D67DB6D692efa7f751b5952bd670d5326\",\n hostChainSlug: \"bnb-testnet\",\n ipfsGateway: \"https://gateway.pinata.cloud\",\n },\n};\n\nexport function getTaxVaultHostChainConfig(chainId: number) {\n return taxVaultHostChains[chainId];\n}\n","import { getAddress, isAddress } from \"viem\";\nimport { getTaxVaultHostChainConfig } from \"./hostRuntimeConfig\";\nimport type { Address, HostRuntimePresentationFetcher, HostTokenPresentation } from \"./types\";\n\nconst DEFAULT_FLAP_HOST_ORIGIN = \"https://flap.sh\";\nconst DEFAULT_RUNTIME_PRESENTATION_ENDPOINT = \"/api/runtime/token-presentation\";\nconst DEFAULT_IPFS_GATEWAY = \"https://gateway.pinata.cloud\";\nconst LEGACY_IPFS_GATEWAY_HOSTS = new Set([\"cf-ipfs.com\", \"pump.mypinata.cloud\", \"gateway.pinata.cloud\"]);\n\ninterface HostMetadataResponseItem {\n address?: string;\n name?: string;\n symbol?: string;\n metadata?: {\n image?: string;\n description?: string;\n };\n}\n\ninterface HostMetadataResponseBody {\n data?: Record<string, HostMetadataResponseItem> | null;\n}\n\nexport interface ResolveHostPresentationInput {\n chainId: number;\n tokenAddress: Address;\n flapHostOrigin?: string;\n fetchImpl?: typeof fetch;\n}\n\nexport interface ResolveHostPresentationBatchInput {\n chainId: number;\n tokenAddresses: Address[];\n flapHostOrigin?: string;\n fetchImpl?: typeof fetch;\n}\n\nexport interface LocalHostPresentationFetcherOptions {\n endpoint?: string;\n fetchImpl?: typeof fetch;\n}\n\nfunction normalizeOrigin(origin?: string) {\n if (!origin) return DEFAULT_FLAP_HOST_ORIGIN;\n return origin.replace(/\\/+$/, \"\");\n}\n\nfunction normalizeAddress(address: string): Address | null {\n return isAddress(address) ? (getAddress(address) as Address) : null;\n}\n\nfunction normalizeString(value: unknown) {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction resolveHostChainSlug(chainId: number) {\n return getTaxVaultHostChainConfig(chainId)?.hostChainSlug;\n}\n\nfunction resolveIpfsGateway(chainId: number) {\n return getTaxVaultHostChainConfig(chainId)?.ipfsGateway ?? DEFAULT_IPFS_GATEWAY;\n}\n\nfunction rewriteToPublicIpfsGateway(rawUrl: string, chainId: number) {\n try {\n const gateway = resolveIpfsGateway(chainId);\n const parsed = new URL(rawUrl);\n if (!LEGACY_IPFS_GATEWAY_HOSTS.has(parsed.hostname)) return rawUrl;\n\n const publicGateway = new URL(gateway);\n parsed.protocol = publicGateway.protocol;\n parsed.host = publicGateway.host;\n return parsed.toString();\n } catch {\n return undefined;\n }\n}\n\nfunction wrapHostImageUrl(image: string | undefined, chainId: number) {\n const raw = normalizeString(image);\n if (!raw) return undefined;\n if (raw.startsWith(\"/\")) return raw;\n if (raw.startsWith(\"https://\")) return rewriteToPublicIpfsGateway(raw, chainId);\n if (raw.startsWith(\"http://\")) return undefined;\n\n const gateway = resolveIpfsGateway(chainId).replace(/\\/+$/, \"\");\n if (raw.startsWith(\"ipfs://\")) return `${gateway}/ipfs/${raw.slice(\"ipfs://\".length)}`;\n return `${gateway}/ipfs/${raw}`;\n}\n\nfunction buildTokenDetailHref(origin: string, chainSlug: string, tokenAddress: Address) {\n return `${origin}/${chainSlug}/${tokenAddress.toLowerCase()}/taxinfo`;\n}\n\nfunction buildChainHref(origin: string, chainSlug: string) {\n return `${origin}/${chainSlug}`;\n}\n\nfunction resolveMetadataItem(payload: HostMetadataResponseBody | null | undefined, tokenAddress: Address) {\n const data = payload?.data;\n if (!data || typeof data !== \"object\") return null;\n\n const checksum = getAddress(tokenAddress);\n const lower = tokenAddress.toLowerCase();\n const direct = data[checksum] ?? data[lower];\n if (direct && typeof direct === \"object\") return direct;\n\n for (const value of Object.values(data)) {\n if (!value || typeof value !== \"object\") continue;\n const itemAddress = normalizeString((value as HostMetadataResponseItem).address);\n if (itemAddress && normalizeAddress(itemAddress)?.toLowerCase() === lower) {\n return value;\n }\n }\n\n return null;\n}\n\nfunction toHostPresentation(chainId: number, tokenAddress: Address, flapHostOrigin: string, item: HostMetadataResponseItem | null): HostTokenPresentation | null {\n if (!item) return null;\n\n const chainSlug = resolveHostChainSlug(chainId);\n if (!chainSlug) return null;\n\n const tokenSymbol = normalizeString(item.symbol);\n const tokenName = normalizeString(item.name);\n const tokenImageUrl = wrapHostImageUrl(item.metadata?.image, chainId);\n\n if (!tokenSymbol && !tokenName && !tokenImageUrl) return null;\n\n return {\n tokenSymbol,\n tokenName,\n tokenImageUrl,\n tokenDetailHref: buildTokenDetailHref(flapHostOrigin, chainSlug, tokenAddress),\n chainHref: buildChainHref(flapHostOrigin, chainSlug),\n extraConfig: {\n hostPresentationOrigin: flapHostOrigin,\n hostPresentationChain: chainSlug,\n ...(normalizeString(item.metadata?.description) ? { tokenDescription: normalizeString(item.metadata?.description) } : {}),\n },\n };\n}\n\nexport async function loadFlapHostTokenPresentation(input: ResolveHostPresentationInput): Promise<HostTokenPresentation | null> {\n const chainSlug = resolveHostChainSlug(input.chainId);\n if (!chainSlug) return null;\n\n const tokenAddress = normalizeAddress(input.tokenAddress);\n if (!tokenAddress) return null;\n\n const flapHostOrigin = normalizeOrigin(input.flapHostOrigin);\n const fetchImpl = input.fetchImpl ?? fetch;\n const response = await fetchImpl(`${flapHostOrigin}/api/tax-dashboard/metadata`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n chain: chainSlug,\n addresses: [tokenAddress.toLowerCase()],\n }),\n cache: \"no-store\",\n });\n\n if (!response.ok) return null;\n\n const payload = (await response.json()) as HostMetadataResponseBody;\n return toHostPresentation(input.chainId, tokenAddress, flapHostOrigin, resolveMetadataItem(payload, tokenAddress));\n}\n\nexport async function loadFlapHostTokenPresentationBatch(input: ResolveHostPresentationBatchInput): Promise<Record<string, HostTokenPresentation | null>> {\n const chainSlug = resolveHostChainSlug(input.chainId);\n if (!chainSlug) return {};\n\n const normalizedAddresses = input.tokenAddresses\n .map((tokenAddress) => normalizeAddress(tokenAddress))\n .filter((tokenAddress): tokenAddress is Address => Boolean(tokenAddress));\n if (!normalizedAddresses.length) return {};\n\n const flapHostOrigin = normalizeOrigin(input.flapHostOrigin);\n const fetchImpl = input.fetchImpl ?? fetch;\n const response = await fetchImpl(`${flapHostOrigin}/api/tax-dashboard/metadata`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n chain: chainSlug,\n addresses: normalizedAddresses.map((tokenAddress) => tokenAddress.toLowerCase()),\n }),\n cache: \"no-store\",\n });\n\n if (!response.ok) return {};\n\n const payload = (await response.json()) as HostMetadataResponseBody;\n return Object.fromEntries(\n normalizedAddresses.map((tokenAddress) => [\n tokenAddress,\n toHostPresentation(input.chainId, tokenAddress, flapHostOrigin, resolveMetadataItem(payload, tokenAddress)),\n ]),\n );\n}\n\nfunction parsePresentationPayload(payload: unknown): HostTokenPresentation | null {\n if (!payload || typeof payload !== \"object\") return null;\n const record = payload as Record<string, unknown>;\n const tokenSymbol = normalizeString(record.tokenSymbol);\n const tokenName = normalizeString(record.tokenName);\n const tokenImageUrl = normalizeString(record.tokenImageUrl);\n\n if (!tokenSymbol && !tokenName && !tokenImageUrl) return null;\n\n return {\n tokenSymbol,\n tokenName,\n tokenImageUrl,\n tokenDetailHref: normalizeString(record.tokenDetailHref),\n chainHref: normalizeString(record.chainHref),\n extraConfig: record.extraConfig && typeof record.extraConfig === \"object\" && !Array.isArray(record.extraConfig) ? (record.extraConfig as Record<string, unknown>) : undefined,\n };\n}\n\nexport function createLocalHostPresentationFetcher(options: LocalHostPresentationFetcherOptions = {}): HostRuntimePresentationFetcher {\n const endpoint = options.endpoint ?? DEFAULT_RUNTIME_PRESENTATION_ENDPOINT;\n const fetchImpl = options.fetchImpl ?? fetch;\n\n return async ({ chainId, tokenAddress, factoryAddress, vaultAddress }) => {\n const query = new URLSearchParams({\n chainId: String(chainId),\n tokenAddress,\n });\n if (factoryAddress) query.set(\"factoryAddress\", factoryAddress);\n if (vaultAddress) query.set(\"vaultAddress\", vaultAddress);\n\n const response = await fetchImpl(`${endpoint}?${query.toString()}`, {\n method: \"GET\",\n cache: \"no-store\",\n });\n if (!response.ok) return null;\n\n const payload = (await response.json()) as { data?: unknown } | null;\n return parsePresentationPayload(payload?.data);\n };\n}\n","import type { OracleProvision, OracleReadRequest, OracleReader } from \"./types\";\n\nconst DEFAULT_LOCAL_ORACLE_ENDPOINT_BASE = \"/api/runtime/oracle\";\n\nexport class OracleReadError extends Error {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"OracleReadError\";\n this.status = status;\n }\n}\n\nfunction appendSearchParams(url: URL, params?: Record<string, string>) {\n for (const [key, value] of Object.entries(params ?? {})) {\n url.searchParams.set(key, value);\n }\n}\n\nfunction toOracleProvision(provision: string | OracleProvision): OracleProvision {\n return typeof provision === \"string\" ? { endpoint: provision } : provision;\n}\n\nexport function buildLocalOracleUrl(oracleId: string, params?: Record<string, string>, endpointBase = DEFAULT_LOCAL_ORACLE_ENDPOINT_BASE) {\n const normalizedBase = endpointBase.replace(/\\/+$/, \"\");\n const url = new URL(`${normalizedBase}/${encodeURIComponent(oracleId)}`, \"http://localhost\");\n appendSearchParams(url, params);\n return `${url.pathname}${url.search}`;\n}\n\nexport async function fetchOracleJson<T>({\n endpoint,\n params,\n fetchImpl,\n headers,\n}: {\n endpoint: string;\n params?: Record<string, string>;\n fetchImpl?: typeof fetch;\n headers?: HeadersInit;\n}): Promise<T> {\n const fallbackOrigin = typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n const url = new URL(endpoint, fallbackOrigin);\n appendSearchParams(url, params);\n\n const response = await (fetchImpl ?? fetch)(url.toString(), {\n cache: \"no-store\",\n headers,\n method: \"GET\",\n });\n\n if (!response.ok) {\n throw new OracleReadError(`Oracle request returned ${response.status}.`, response.status);\n }\n\n return (await response.json()) as T;\n}\n\nexport async function fetchProvisionedOracle<T>({\n provision,\n params,\n fetchImpl,\n}: {\n provision: string | OracleProvision;\n params?: Record<string, string>;\n fetchImpl?: typeof fetch;\n}): Promise<T> {\n const normalizedProvision = toOracleProvision(provision);\n const filteredParams =\n normalizedProvision.allowedParams && normalizedProvision.allowedParams.length\n ? Object.fromEntries(Object.entries(params ?? {}).filter(([key]) => normalizedProvision.allowedParams?.includes(key)))\n : params;\n\n return fetchOracleJson<T>({\n endpoint: normalizedProvision.endpoint,\n params: filteredParams,\n fetchImpl,\n headers: normalizedProvision.headers,\n });\n}\n\nexport function createLocalOracleReader(options: { endpointBase?: string; fetchImpl?: typeof fetch } = {}): OracleReader {\n const endpointBase = options.endpointBase ?? DEFAULT_LOCAL_ORACLE_ENDPOINT_BASE;\n const fetchImpl = options.fetchImpl;\n\n return async function readLocalOracle<T>({ oracleId, params }: OracleReadRequest): Promise<T> {\n return fetchOracleJson<T>({\n endpoint: buildLocalOracleUrl(oracleId, params, endpointBase),\n fetchImpl,\n });\n };\n}\n","import { fetchProvisionedOracle } from \"./oracle\";\nimport type { Address, OracleProvision, RuntimeOracleRegistry } from \"./types\";\n\nexport const FLAP_RUNTIME_ORACLE_REGISTRY_ENV = \"FLAP_RUNTIME_ORACLE_REGISTRY\";\nconst DEFAULT_EXAMPLE_ORACLE_SIGNATURE = \"0x000000000000000000000000000000000000dEaD\" as Address;\n\nfunction normalizeHeaders(headers: unknown) {\n if (!headers || typeof headers !== \"object\" || Array.isArray(headers)) return undefined;\n const entries = Object.entries(headers)\n .filter(([, value]) => typeof value === \"string\")\n .map(([key, value]) => [key, value.trim()] as const)\n .filter(([, value]) => value);\n return entries.length ? Object.fromEntries(entries) : undefined;\n}\n\nfunction normalizeAllowedParams(value: unknown) {\n if (!Array.isArray(value)) return undefined;\n const params = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n return params.length ? params : undefined;\n}\n\nfunction normalizeProvision(value: unknown): OracleProvision | null {\n if (typeof value === \"string\") {\n return value.trim() ? { endpoint: value.trim() } : null;\n }\n\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const record = value as Record<string, unknown>;\n if (typeof record.endpoint !== \"string\" || !record.endpoint.trim()) return null;\n\n return {\n endpoint: record.endpoint.trim(),\n headers: normalizeHeaders(record.headers),\n allowedParams: normalizeAllowedParams(record.allowedParams),\n };\n}\n\nexport function parseRuntimeOracleRegistry(raw: string | undefined): RuntimeOracleRegistry {\n if (!raw?.trim()) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `${FLAP_RUNTIME_ORACLE_REGISTRY_ENV} must be valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`${FLAP_RUNTIME_ORACLE_REGISTRY_ENV} must be a JSON object keyed by oracle id.`);\n }\n\n return Object.fromEntries(\n Object.entries(parsed)\n .map(([oracleId, provision]) => [oracleId, normalizeProvision(provision)] as const)\n .filter((entry): entry is [string, OracleProvision] => Boolean(entry[1])),\n );\n}\n\nexport function resolveRuntimeOracleProvision(oracleId: string, registry: RuntimeOracleRegistry): OracleProvision | null {\n const provision = registry[oracleId];\n if (!provision) return null;\n return typeof provision === \"string\" ? { endpoint: provision } : provision;\n}\n\nexport function loadDefaultRuntimeOracle<T>(oracleId: string): T | null {\n if (oracleId === \"example-reward-oracle\") {\n return {\n rewardMultiplierBps: 175,\n timestamp: Math.floor(Date.now() / 1000),\n signature: DEFAULT_EXAMPLE_ORACLE_SIGNATURE,\n } as T;\n }\n\n return null;\n}\n\nexport async function loadRuntimeOracle<T>({\n oracleId,\n params,\n registry,\n fetchImpl,\n}: {\n oracleId: string;\n params?: Record<string, string>;\n registry: RuntimeOracleRegistry;\n fetchImpl?: typeof fetch;\n}): Promise<T | null> {\n const provision = resolveRuntimeOracleProvision(oracleId, registry);\n if (!provision) return null;\n return fetchProvisionedOracle<T>({\n provision,\n params,\n fetchImpl,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/sdk/hostRuntimeConfig.ts","../../src/sdk/hostPresentation.ts","../../src/sdk/oracle.ts","../../src/sdk/oracleServer.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["import type { Address } from \"./types\";\n\nexport interface TaxVaultHostChainConfig {\n portal: Address;\n taxTokenHelperAddress?: Address;\n vaultPortal?: Address;\n wrappedNativeTokenAddress?: Address;\n giftVaultFactory?: Address;\n hostChainSlug?: string;\n ipfsGateway?: string;\n}\n\nconst taxVaultHostChains: Record<number, TaxVaultHostChainConfig> = {\n 56: {\n portal: \"0xe2ce6ab80874fa9fa2aae65d277dd6b8e65c9de0\",\n taxTokenHelperAddress: \"0x53841c73217735F37BC1775538b03b23feFD8346\",\n vaultPortal: \"0x90497450f2a706f1951b5bdda52B4E5d16f34C06\",\n wrappedNativeTokenAddress: \"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c\",\n giftVaultFactory: \"0x025549F52B03cF36f9e1a337c02d3AA7Af66ab32\",\n hostChainSlug: \"bnb\",\n ipfsGateway: \"https://gateway.pinata.cloud\",\n },\n 97: {\n portal: \"0x5bEacaF7ABCbB3aB280e80D007FD31fcE26510e9\",\n taxTokenHelperAddress: \"0xD64441e5FcD02D342B8cf6eBA10Ef6E40d0dA90f\",\n vaultPortal: \"0x027e3704fC5C16522e9393d04C60A3ac5c0d775f\",\n wrappedNativeTokenAddress: \"0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd\",\n giftVaultFactory: \"0xa02DA44D67DB6D692efa7f751b5952bd670d5326\",\n hostChainSlug: \"bnb-testnet\",\n ipfsGateway: \"https://gateway.pinata.cloud\",\n },\n};\n\nexport function getTaxVaultHostChainConfig(chainId: number) {\n return taxVaultHostChains[chainId];\n}\n","import { getAddress, isAddress } from \"viem\";\nimport { getTaxVaultHostChainConfig } from \"./hostRuntimeConfig\";\nimport type { Address, HostRuntimePresentationFetcher, HostTokenPresentation } from \"./types\";\n\nconst DEFAULT_FLAP_HOST_ORIGIN = \"https://flap.sh\";\nconst DEFAULT_RUNTIME_PRESENTATION_ENDPOINT = \"/api/runtime/token-presentation\";\nconst DEFAULT_IPFS_GATEWAY = \"https://gateway.pinata.cloud\";\nconst LEGACY_IPFS_GATEWAY_HOSTS = new Set([\"cf-ipfs.com\", \"pump.mypinata.cloud\", \"gateway.pinata.cloud\"]);\n\ninterface HostMetadataResponseItem {\n address?: string;\n name?: string;\n symbol?: string;\n metadata?: {\n image?: string;\n description?: string;\n };\n}\n\ninterface HostMetadataResponseBody {\n data?: Record<string, HostMetadataResponseItem> | null;\n}\n\nexport interface ResolveHostPresentationInput {\n chainId: number;\n tokenAddress: Address;\n flapHostOrigin?: string;\n fetchImpl?: typeof fetch;\n}\n\nexport interface ResolveHostPresentationBatchInput {\n chainId: number;\n tokenAddresses: Address[];\n flapHostOrigin?: string;\n fetchImpl?: typeof fetch;\n}\n\nexport interface LocalHostPresentationFetcherOptions {\n endpoint?: string;\n fetchImpl?: typeof fetch;\n}\n\nfunction normalizeOrigin(origin?: string) {\n if (!origin) return DEFAULT_FLAP_HOST_ORIGIN;\n return origin.replace(/\\/+$/, \"\");\n}\n\nfunction normalizeAddress(address: string): Address | null {\n return isAddress(address) ? (getAddress(address) as Address) : null;\n}\n\nfunction normalizeString(value: unknown) {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction resolveHostChainSlug(chainId: number) {\n return getTaxVaultHostChainConfig(chainId)?.hostChainSlug;\n}\n\nfunction resolveIpfsGateway(chainId: number) {\n return getTaxVaultHostChainConfig(chainId)?.ipfsGateway ?? DEFAULT_IPFS_GATEWAY;\n}\n\nfunction rewriteToPublicIpfsGateway(rawUrl: string, chainId: number) {\n try {\n const gateway = resolveIpfsGateway(chainId);\n const parsed = new URL(rawUrl);\n if (!LEGACY_IPFS_GATEWAY_HOSTS.has(parsed.hostname)) return rawUrl;\n\n const publicGateway = new URL(gateway);\n parsed.protocol = publicGateway.protocol;\n parsed.host = publicGateway.host;\n return parsed.toString();\n } catch {\n return undefined;\n }\n}\n\nfunction wrapHostImageUrl(image: string | undefined, chainId: number) {\n const raw = normalizeString(image);\n if (!raw) return undefined;\n if (raw.startsWith(\"/\")) return raw;\n if (raw.startsWith(\"https://\")) return rewriteToPublicIpfsGateway(raw, chainId);\n if (raw.startsWith(\"http://\")) return undefined;\n\n const gateway = resolveIpfsGateway(chainId).replace(/\\/+$/, \"\");\n if (raw.startsWith(\"ipfs://\")) return `${gateway}/ipfs/${raw.slice(\"ipfs://\".length)}`;\n return `${gateway}/ipfs/${raw}`;\n}\n\nfunction buildTokenDetailHref(origin: string, chainSlug: string, tokenAddress: Address) {\n return `${origin}/${chainSlug}/${tokenAddress.toLowerCase()}/taxinfo`;\n}\n\nfunction buildChainHref(origin: string, chainSlug: string) {\n return `${origin}/${chainSlug}`;\n}\n\nfunction resolveMetadataItem(payload: HostMetadataResponseBody | null | undefined, tokenAddress: Address) {\n const data = payload?.data;\n if (!data || typeof data !== \"object\") return null;\n\n const checksum = getAddress(tokenAddress);\n const lower = tokenAddress.toLowerCase();\n const direct = data[checksum] ?? data[lower];\n if (direct && typeof direct === \"object\") return direct;\n\n for (const value of Object.values(data)) {\n if (!value || typeof value !== \"object\") continue;\n const itemAddress = normalizeString((value as HostMetadataResponseItem).address);\n if (itemAddress && normalizeAddress(itemAddress)?.toLowerCase() === lower) {\n return value;\n }\n }\n\n return null;\n}\n\nfunction toHostPresentation(chainId: number, tokenAddress: Address, flapHostOrigin: string, item: HostMetadataResponseItem | null): HostTokenPresentation | null {\n if (!item) return null;\n\n const chainSlug = resolveHostChainSlug(chainId);\n if (!chainSlug) return null;\n\n const tokenSymbol = normalizeString(item.symbol);\n const tokenName = normalizeString(item.name);\n const tokenImageUrl = wrapHostImageUrl(item.metadata?.image, chainId);\n\n if (!tokenSymbol && !tokenName && !tokenImageUrl) return null;\n\n return {\n tokenSymbol,\n tokenName,\n tokenImageUrl,\n tokenDetailHref: buildTokenDetailHref(flapHostOrigin, chainSlug, tokenAddress),\n chainHref: buildChainHref(flapHostOrigin, chainSlug),\n extraConfig: {\n hostPresentationOrigin: flapHostOrigin,\n hostPresentationChain: chainSlug,\n ...(normalizeString(item.metadata?.description) ? { tokenDescription: normalizeString(item.metadata?.description) } : {}),\n },\n };\n}\n\nexport async function loadFlapHostTokenPresentation(input: ResolveHostPresentationInput): Promise<HostTokenPresentation | null> {\n const chainSlug = resolveHostChainSlug(input.chainId);\n if (!chainSlug) return null;\n\n const tokenAddress = normalizeAddress(input.tokenAddress);\n if (!tokenAddress) return null;\n\n const flapHostOrigin = normalizeOrigin(input.flapHostOrigin);\n const fetchImpl = input.fetchImpl ?? fetch;\n const response = await fetchImpl(`${flapHostOrigin}/api/tax-dashboard/metadata`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n chain: chainSlug,\n addresses: [tokenAddress.toLowerCase()],\n }),\n cache: \"no-store\",\n });\n\n if (!response.ok) return null;\n\n const payload = (await response.json()) as HostMetadataResponseBody;\n return toHostPresentation(input.chainId, tokenAddress, flapHostOrigin, resolveMetadataItem(payload, tokenAddress));\n}\n\nexport async function loadFlapHostTokenPresentationBatch(input: ResolveHostPresentationBatchInput): Promise<Record<string, HostTokenPresentation | null>> {\n const chainSlug = resolveHostChainSlug(input.chainId);\n if (!chainSlug) return {};\n\n const normalizedAddresses = input.tokenAddresses\n .map((tokenAddress) => normalizeAddress(tokenAddress))\n .filter((tokenAddress): tokenAddress is Address => Boolean(tokenAddress));\n if (!normalizedAddresses.length) return {};\n\n const flapHostOrigin = normalizeOrigin(input.flapHostOrigin);\n const fetchImpl = input.fetchImpl ?? fetch;\n const response = await fetchImpl(`${flapHostOrigin}/api/tax-dashboard/metadata`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n chain: chainSlug,\n addresses: normalizedAddresses.map((tokenAddress) => tokenAddress.toLowerCase()),\n }),\n cache: \"no-store\",\n });\n\n if (!response.ok) return {};\n\n const payload = (await response.json()) as HostMetadataResponseBody;\n return Object.fromEntries(\n normalizedAddresses.map((tokenAddress) => [\n tokenAddress,\n toHostPresentation(input.chainId, tokenAddress, flapHostOrigin, resolveMetadataItem(payload, tokenAddress)),\n ]),\n );\n}\n\nfunction parsePresentationPayload(payload: unknown): HostTokenPresentation | null {\n if (!payload || typeof payload !== \"object\") return null;\n const record = payload as Record<string, unknown>;\n const tokenSymbol = normalizeString(record.tokenSymbol);\n const tokenName = normalizeString(record.tokenName);\n const tokenImageUrl = normalizeString(record.tokenImageUrl);\n\n if (!tokenSymbol && !tokenName && !tokenImageUrl) return null;\n\n return {\n tokenSymbol,\n tokenName,\n tokenImageUrl,\n tokenDetailHref: normalizeString(record.tokenDetailHref),\n chainHref: normalizeString(record.chainHref),\n extraConfig: record.extraConfig && typeof record.extraConfig === \"object\" && !Array.isArray(record.extraConfig) ? (record.extraConfig as Record<string, unknown>) : undefined,\n };\n}\n\nexport function createLocalHostPresentationFetcher(options: LocalHostPresentationFetcherOptions = {}): HostRuntimePresentationFetcher {\n const endpoint = options.endpoint ?? DEFAULT_RUNTIME_PRESENTATION_ENDPOINT;\n const fetchImpl = options.fetchImpl ?? fetch;\n\n return async ({ chainId, tokenAddress, factoryAddress, vaultAddress }) => {\n const query = new URLSearchParams({\n chainId: String(chainId),\n tokenAddress,\n });\n if (factoryAddress) query.set(\"factoryAddress\", factoryAddress);\n if (vaultAddress) query.set(\"vaultAddress\", vaultAddress);\n\n const response = await fetchImpl(`${endpoint}?${query.toString()}`, {\n method: \"GET\",\n cache: \"no-store\",\n });\n if (!response.ok) return null;\n\n const payload = (await response.json()) as { data?: unknown } | null;\n return parsePresentationPayload(payload?.data);\n };\n}\n","import type { OracleProvision, OracleReadRequest, OracleReader } from \"./types\";\n\nconst DEFAULT_LOCAL_ORACLE_ENDPOINT_BASE = \"/api/runtime/oracle\";\n\nexport class OracleReadError extends Error {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"OracleReadError\";\n this.status = status;\n }\n}\n\nfunction appendSearchParams(url: URL, params?: Record<string, string>) {\n for (const [key, value] of Object.entries(params ?? {})) {\n url.searchParams.set(key, value);\n }\n}\n\nfunction toOracleProvision(provision: string | OracleProvision): OracleProvision {\n return typeof provision === \"string\" ? { endpoint: provision } : provision;\n}\n\nexport function buildLocalOracleUrl(oracleId: string, params?: Record<string, string>, endpointBase = DEFAULT_LOCAL_ORACLE_ENDPOINT_BASE) {\n const normalizedBase = endpointBase.replace(/\\/+$/, \"\");\n const url = new URL(`${normalizedBase}/${encodeURIComponent(oracleId)}`, \"http://localhost\");\n appendSearchParams(url, params);\n return `${url.pathname}${url.search}`;\n}\n\nexport async function fetchOracleJson<T>({\n endpoint,\n params,\n fetchImpl,\n headers,\n}: {\n endpoint: string;\n params?: Record<string, string>;\n fetchImpl?: typeof fetch;\n headers?: HeadersInit;\n}): Promise<T> {\n const fallbackOrigin = typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n const url = new URL(endpoint, fallbackOrigin);\n appendSearchParams(url, params);\n\n const response = await (fetchImpl ?? fetch)(url.toString(), {\n cache: \"no-store\",\n headers,\n method: \"GET\",\n });\n\n if (!response.ok) {\n throw new OracleReadError(`Oracle request returned ${response.status}.`, response.status);\n }\n\n return (await response.json()) as T;\n}\n\nexport async function fetchProvisionedOracle<T>({\n provision,\n params,\n fetchImpl,\n}: {\n provision: string | OracleProvision;\n params?: Record<string, string>;\n fetchImpl?: typeof fetch;\n}): Promise<T> {\n const normalizedProvision = toOracleProvision(provision);\n const filteredParams =\n normalizedProvision.allowedParams && normalizedProvision.allowedParams.length\n ? Object.fromEntries(Object.entries(params ?? {}).filter(([key]) => normalizedProvision.allowedParams?.includes(key)))\n : params;\n\n return fetchOracleJson<T>({\n endpoint: normalizedProvision.endpoint,\n params: filteredParams,\n fetchImpl,\n headers: normalizedProvision.headers,\n });\n}\n\nexport function createLocalOracleReader(options: { endpointBase?: string; fetchImpl?: typeof fetch } = {}): OracleReader {\n const endpointBase = options.endpointBase ?? DEFAULT_LOCAL_ORACLE_ENDPOINT_BASE;\n const fetchImpl = options.fetchImpl;\n\n return async function readLocalOracle<T>({ oracleId, params }: OracleReadRequest): Promise<T> {\n return fetchOracleJson<T>({\n endpoint: buildLocalOracleUrl(oracleId, params, endpointBase),\n fetchImpl,\n });\n };\n}\n","import { fetchProvisionedOracle } from \"./oracle\";\nimport type { Address, OracleProvision, RuntimeOracleRegistry } from \"./types\";\n\nexport const FLAP_RUNTIME_ORACLE_REGISTRY_ENV = \"FLAP_RUNTIME_ORACLE_REGISTRY\";\nconst DEFAULT_EXAMPLE_ORACLE_SIGNATURE = \"0x000000000000000000000000000000000000dEaD\" as Address;\nconst BNB_USD_ORACLE_ID = \"bnb-usd-price\";\nconst BNB_USD_BINANCE_ENDPOINT = \"https://api.binance.com/api/v3/avgPrice?symbol=BNBUSDT\";\nconst BNB_USD_PYTH_ENDPOINT =\n \"https://hermes.pyth.network/v2/updates/price/latest?ids%5B%5D=0x2f95862b045670cd22bee3114c39763a4a08beeb663b145d283c31d7d1101c4f&encoding=base64&parsed=true\";\n\ninterface RuntimePriceOracleData {\n price: number;\n symbol: string;\n timestamp: number;\n source: \"binance\" | \"pyth\";\n}\n\nfunction normalizeHeaders(headers: unknown) {\n if (!headers || typeof headers !== \"object\" || Array.isArray(headers)) return undefined;\n const entries = Object.entries(headers)\n .filter(([, value]) => typeof value === \"string\")\n .map(([key, value]) => [key, value.trim()] as const)\n .filter(([, value]) => value);\n return entries.length ? Object.fromEntries(entries) : undefined;\n}\n\nfunction normalizeAllowedParams(value: unknown) {\n if (!Array.isArray(value)) return undefined;\n const params = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n return params.length ? params : undefined;\n}\n\nfunction normalizeProvision(value: unknown): OracleProvision | null {\n if (typeof value === \"string\") {\n return value.trim() ? { endpoint: value.trim() } : null;\n }\n\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const record = value as Record<string, unknown>;\n if (typeof record.endpoint !== \"string\" || !record.endpoint.trim()) return null;\n\n return {\n endpoint: record.endpoint.trim(),\n headers: normalizeHeaders(record.headers),\n allowedParams: normalizeAllowedParams(record.allowedParams),\n };\n}\n\nexport function parseRuntimeOracleRegistry(raw: string | undefined): RuntimeOracleRegistry {\n if (!raw?.trim()) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `${FLAP_RUNTIME_ORACLE_REGISTRY_ENV} must be valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`${FLAP_RUNTIME_ORACLE_REGISTRY_ENV} must be a JSON object keyed by oracle id.`);\n }\n\n return Object.fromEntries(\n Object.entries(parsed)\n .map(([oracleId, provision]) => [oracleId, normalizeProvision(provision)] as const)\n .filter((entry): entry is [string, OracleProvision] => Boolean(entry[1])),\n );\n}\n\nexport function resolveRuntimeOracleProvision(oracleId: string, registry: RuntimeOracleRegistry): OracleProvision | null {\n const provision = registry[oracleId];\n if (!provision) return null;\n return typeof provision === \"string\" ? { endpoint: provision } : provision;\n}\n\nexport function loadDefaultRuntimeOracle<T>(oracleId: string): T | null {\n if (oracleId === \"example-reward-oracle\") {\n return {\n rewardMultiplierBps: 175,\n timestamp: Math.floor(Date.now() / 1000),\n signature: DEFAULT_EXAMPLE_ORACLE_SIGNATURE,\n } as T;\n }\n\n return null;\n}\n\nfunction readPositiveNumber(value: unknown) {\n const parsed = typeof value === \"number\" ? value : typeof value === \"string\" ? Number(value) : NaN;\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n}\n\nasync function fetchJson(endpoint: string, fetchImpl?: typeof fetch): Promise<unknown> {\n const response = await (fetchImpl ?? fetch)(endpoint, {\n cache: \"no-store\",\n method: \"GET\",\n });\n if (!response.ok) {\n throw new Error(`Runtime oracle request returned ${response.status}.`);\n }\n return response.json();\n}\n\nasync function loadBnbUsdFromBinance(fetchImpl?: typeof fetch): Promise<RuntimePriceOracleData> {\n const data = await fetchJson(BNB_USD_BINANCE_ENDPOINT, fetchImpl);\n const price = readPositiveNumber((data as { price?: unknown } | null)?.price);\n if (price === null) {\n throw new Error(\"BNB/USD Binance oracle response did not include a positive price.\");\n }\n\n return {\n price,\n symbol: \"BNBUSDT\",\n timestamp: Math.floor(Date.now() / 1000),\n source: \"binance\",\n };\n}\n\nasync function loadBnbUsdFromPyth(fetchImpl?: typeof fetch): Promise<RuntimePriceOracleData> {\n const data = await fetchJson(BNB_USD_PYTH_ENDPOINT, fetchImpl);\n const priceData = (data as { parsed?: Array<{ price?: { price?: unknown; expo?: unknown; publish_time?: unknown } }> } | null)?.parsed?.[0]?.price;\n const rawPrice = readPositiveNumber(priceData?.price);\n const exponent = typeof priceData?.expo === \"number\" ? priceData.expo : typeof priceData?.expo === \"string\" ? Number(priceData.expo) : NaN;\n if (rawPrice === null || !Number.isFinite(exponent)) {\n throw new Error(\"BNB/USD Pyth oracle response did not include a usable price.\");\n }\n\n const price = rawPrice * 10 ** exponent;\n if (!Number.isFinite(price) || price <= 0) {\n throw new Error(\"BNB/USD Pyth oracle response produced an invalid price.\");\n }\n\n return {\n price,\n symbol: \"BNBUSD\",\n timestamp: Math.floor(readPositiveNumber(priceData?.publish_time) ?? Date.now() / 1000),\n source: \"pyth\",\n };\n}\n\nasync function loadBuiltinRuntimeOracle<T>(oracleId: string, fetchImpl?: typeof fetch): Promise<T | null> {\n if (oracleId !== BNB_USD_ORACLE_ID) return null;\n\n try {\n return (await loadBnbUsdFromBinance(fetchImpl)) as T;\n } catch {\n return (await loadBnbUsdFromPyth(fetchImpl)) as T;\n }\n}\n\nexport async function loadRuntimeOracle<T>({\n oracleId,\n params,\n registry,\n fetchImpl,\n}: {\n oracleId: string;\n params?: Record<string, string>;\n registry: RuntimeOracleRegistry;\n fetchImpl?: typeof fetch;\n}): Promise<T | null> {\n const provision = resolveRuntimeOracleProvision(oracleId, registry);\n if (provision) {\n return fetchProvisionedOracle<T>({\n provision,\n params,\n fetchImpl,\n });\n }\n return loadBuiltinRuntimeOracle<T>(oracleId, fetchImpl);\n}\n"]}