@chipi-stack/shared 14.16.0 → 14.17.0
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/dist/constants/index.js +12 -2
- package/dist/constants/index.js.map +1 -1
- package/dist/constants/index.mjs +12 -2
- package/dist/constants/index.mjs.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +12 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/constants/index.js
CHANGED
|
@@ -246,8 +246,10 @@ var WALLET_CLASS_HASHES = {
|
|
|
246
246
|
CHIPI: "0x053f4f8791ed5bed0fddaa553d180c664e32cfaf8316bb232ae77bb08f459f2a",
|
|
247
247
|
// v29 — must match backend until coordinated v33 upgrade
|
|
248
248
|
READY: "0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f",
|
|
249
|
-
|
|
250
|
-
// V8.4
|
|
249
|
+
// V8.5 ShhhAccount — declared 2026-10-14. The single-owner envelope must
|
|
250
|
+
// carry the threshold (V8.4 ignored it). Needs chipi-back with
|
|
251
|
+
// OPT_IN_SHHH_CLASS_HASHES: createWallet names this class explicitly.
|
|
252
|
+
SHHH: "0x067828c8b82ac723b4adb141f9aa8975e296d8c11179d22bb8d7203b32abd96a"
|
|
251
253
|
};
|
|
252
254
|
var LEGACY_CHIPI_CLASS_HASHES = [
|
|
253
255
|
"0x0484bbd2404b3c7264bea271f7267d6d4004821ac7787a9eed7f472e79ef40d1",
|
|
@@ -262,6 +264,8 @@ var LEGACY_CHIPI_CLASS_HASHES = [
|
|
|
262
264
|
// v28
|
|
263
265
|
];
|
|
264
266
|
var LEGACY_SHHH_CLASS_HASHES = [
|
|
267
|
+
"0x075dfb396145926bffa6beb659897f46cc082a50b211d80871cff7f1038fa58a",
|
|
268
|
+
// V8.4 — deprecated 2026-10-14, single-owner path ignores the threshold (safe at threshold 1)
|
|
265
269
|
"0x03bc539295abd3e59bd9ea799d12fe3331748d484bc77bff45b302b1636a87d9"
|
|
266
270
|
// V8.3 — deprecated 2026-05-15, no stranded-bootstrap recovery
|
|
267
271
|
];
|
|
@@ -271,6 +275,11 @@ var SHHH_VERIFIER_CLASS_HASHES = {
|
|
|
271
275
|
SECP256K1: "0x03e81667a46bd5287e09a9600fa98d28fdc477735f2689f5f4e8e95f37b67b74",
|
|
272
276
|
EIP191_SECP256K1: "0x03a75997862059c36cb8e204fb3027eb6d1fdf933488d42c2db4528118d084e6",
|
|
273
277
|
EIP712_SECP256K1: "0x072a3f77e8c28bfea2ade91ec3fb83b6290169d1ed8c1b2396704231841c6474",
|
|
278
|
+
// Starknet browser wallets (Bramble, Braavos, Ready/Argent, OZ) via
|
|
279
|
+
// wallet_signTypedData. Built from shhh-wallet-cairo PR #23 with Scarb 2.14.0
|
|
280
|
+
// (same toolchain that reproduces every hash above). Declared on mainnet
|
|
281
|
+
// 2026-10-14 (block 16377651); isShhhVerifierDeclared() checks other networks.
|
|
282
|
+
STARK_SNIP12: "0x017884125977631bee198b34cd3e3fcf975a543e453c8b996a818910a964b5e",
|
|
274
283
|
P256: "0x01b600709af54c8838e5f18ddad3a26feeb47cb124c239f55a0f1b7a780e2d8a",
|
|
275
284
|
WEBAUTHN_P256: "0x074f6efd2af9025cd8cab41a4565bc73b6ef097214c31352838fcdbac0a44657",
|
|
276
285
|
JWT_ES256: "0x002efce875fa3e73e04d825d8ebade53e188cc995dfe0c55a6a2f7fa6c59f497",
|
|
@@ -282,6 +291,7 @@ var SHHH_KIND_GAS_OVERHEAD = {
|
|
|
282
291
|
SECP256K1: 5e6,
|
|
283
292
|
EIP191_SECP256K1: 1e7,
|
|
284
293
|
EIP712_SECP256K1: 12e6,
|
|
294
|
+
STARK_SNIP12: 25e5,
|
|
285
295
|
P256: 3e7,
|
|
286
296
|
ED25519: 33e6,
|
|
287
297
|
WEBAUTHN_P256: 35e6,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/constants/rpc.ts","../../src/constants/index.ts"],"names":["RpcProvider"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Ordered Starknet RPC provider chain with transport-level failover.\n *\n * ## Published-SDK contract (read before changing anything here)\n *\n * `@chipi-stack/*` is consumed by external integrators who do NOT have Chipi's\n * Starkscan API key. The keyless path must keep working with zero configuration,\n * so Starkscan is layered on top rather than baked in:\n *\n * - `STARKSCAN_API_KEY` set (Chipi's own server-side deployments) → Starkscan is\n * the primary endpoint, key travelling in a header.\n * - `STARKSCAN_API_KEY` unset (every integrator) → the chain HEAD is byte-identical\n * to the endpoint the SDK resolved before this module existed\n * (`STARKNET_RPC_URL` when set, else the default Infura mainnet URL). The only\n * difference is that the SDK now retries on additional nodes instead of failing.\n *\n * Starkscan is MAINNET-ONLY (`SN_SEPOLIA` answers `unsupported_chain`), so a\n * non-mainnet configuration never gets it (and never gets mainnet fallbacks\n * either; see `buildRpcChain`).\n *\n * The custom `baseFetch` transport classifier is installed ONLY on providers this module\n * builds for the chain. A provider an integrator constructs themselves from\n * `WALLET_RPC_ENDPOINTS` / `STARKNET_NETWORKS` keeps stock starknet.js behaviour, so the\n * blast radius of coupling to starknet.js internals is limited to the chain helper.\n */\nimport { RpcProvider } from \"starknet\";\n\n/**\n * Starkscan's JSON-RPC route. Mainnet only. The key rides in the canonical\n * `X-Starkscan-Api-Key` header, never in the URL.\n */\nexport const STARKSCAN_MAINNET_RPC = \"https://api.starkscan.co/v1/SN_MAIN/rpc\";\n\n/** Public keyless mainnet node used as the last resort in the chain. */\n/** Dead since 2026-09: HTTP 410 \"This endpoint has been discontinued\". Kept only\n * so an integrator pinning it via env still resolves; never pushed into the chain. */\nexport const LAVA_MAINNET_RPC = \"https://rpc.starknet.lava.build\";\n/** Keyless public fallback (Cartridge). Replaces Lava as the chain's last resort. */\nexport const CARTRIDGE_MAINNET_RPC = \"https://api.cartridge.gg/x/starknet/mainnet\";\n\n/** Keyless default mainnet RPC. This is the value published SDKs resolve to today. Do not change. */\nexport const DEFAULT_MAINNET_RPC =\n \"https://starknet-mainnet.infura.io/v3/4a4a1fdd7d704509aa99154fb29886e2\";\n\n/** Keyless default sepolia RPC. Starkscan is never layered onto this. */\nexport const DEFAULT_SEPOLIA_RPC =\n \"https://starknet-sepolia.infura.io/v3/4a4a1fdd7d704509aa99154fb29886e2\";\n\nexport type RpcEndpoint = { label: string; url: string; headers?: Record<string, string> };\n\n/**\n * Read an env var defensively: this module is bundled into browser-facing packages\n * where `process` may not exist. Empty / whitespace-only values are treated as unset.\n */\nexport function readEnv(name: string): string | undefined {\n if (typeof process === \"undefined\" || !process.env) return undefined;\n const value = process.env[name];\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Anything that is clearly not Starknet mainnet. A non-mainnet head must never be\n * followed by mainnet fallbacks (answering a sepolia question with mainnet state is\n * worse than failing), so such a chain stays single-entry.\n */\nfunction looksNonMainnet(url: string): boolean {\n return /sepolia|goerli|testnet|devnet|localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0/i.test(url);\n}\n\n/**\n * Build the ordered endpoint chain.\n *\n * @param opts.fallbackUrl the URL this call site resolved on its own (e.g.\n * `WALLET_RPC_ENDPOINTS[walletType]` or an integrator-supplied `nodeUrl`). It is the\n * first KEYLESS entry, which is what keeps the no-Starkscan behaviour byte-identical\n * to today.\n *\n * Order: starkscan (only with a key) → caller URL → `STARKNET_RPC_URL` → Infura default\n * → cartridge. De-duplicated by URL so an operator who pins `STARKNET_RPC_URL` there does\n * not get the same node twice (which would make \"fallback\" a no-op).\n */\nexport function buildRpcChain(opts?: { fallbackUrl?: string }): RpcEndpoint[] {\n const callerUrl = opts?.fallbackUrl?.trim() || undefined;\n const envUrl = readEnv(\"STARKNET_RPC_URL\");\n\n // The endpoint this call site would have used before this module existed.\n const head = callerUrl ?? envUrl ?? DEFAULT_MAINNET_RPC;\n\n // Non-mainnet deployments keep exactly one endpoint: no Starkscan (it rejects\n // SN_SEPOLIA with `unsupported_chain`) and no cross-chain fallback.\n if (looksNonMainnet(head)) {\n return [{ label: \"configured\", url: head }];\n }\n\n const chain: RpcEndpoint[] = [];\n const seen = new Set<string>();\n\n const push = (label: string, url: string | undefined, headers?: Record<string, string>) => {\n if (!url) return;\n const nodeUrl = url.trim();\n if (!nodeUrl) return;\n const key = nodeUrl.replace(/\\/+$/, \"\").toLowerCase();\n if (seen.has(key)) return;\n seen.add(key);\n chain.push(headers ? { label, url: nodeUrl, headers } : { label, url: nodeUrl });\n };\n\n // Server-only key. Never logged, never interpolated into a URL, never shipped in a\n // browser bundle's env. Absent (every external integrator) → chain is unchanged.\n const starkscanApiKey = readEnv(\"STARKSCAN_API_KEY\");\n if (starkscanApiKey) {\n push(\"starkscan\", STARKSCAN_MAINNET_RPC, { \"X-Starkscan-Api-Key\": starkscanApiKey });\n }\n\n push(\"caller\", callerUrl);\n push(\"env\", envUrl);\n push(\"default\", DEFAULT_MAINNET_RPC);\n push(\"cartridge\", CARTRIDGE_MAINNET_RPC);\n\n return chain;\n}\n\n/**\n * Marker on transport-class failures we raise ourselves. starknet.js re-wraps thrown\n * fetch errors as a plain `Error(message)`, so the error *instance* does not survive the\n * round trip. Only the message text does.\n */\nconst TRANSPORT_MARKER = \"[chipi-rpc-transport]\";\n\n/**\n * HTTP statuses that mean \"this endpoint did not answer\" rather than \"the chain says no\":\n * 429/5xx (rate limited / node broken) plus 401/403/404, which is what a missing, wrong,\n * rotated or unprovisioned API key looks like. Falling through is exactly right there.\n */\nfunction isTransportStatus(status: number): boolean {\n return (\n status === 401 ||\n status === 403 ||\n status === 404 ||\n status === 410 || // Gone: a discontinued endpoint (Lava, 2026-09) is transport, not chain truth\n status === 429 ||\n status >= 500\n );\n}\n\n/** Per-request budget for one RPC round-trip before we call it a transport failure. */\nconst RPC_TIMEOUT_MS = 15_000;\n\n/**\n * Wraps global fetch so an HTTP-level failure is classified while the status code is\n * still visible.\n *\n * This is necessary because **starknet.js never inspects the HTTP status**:\n * `RpcChannel.fetchEndpoint` goes straight to `.json()`. Without this wrapper a rate-limit\n * page or an auth rejection surfaces either as an opaque JSON parse error or, when the body\n * happens to be valid JSON, as a silent `undefined` result.\n *\n * Scope note (published SDK): this wrapper is installed ONLY on providers built by\n * `rpcProviderFor` for the fallback chain. Providers an integrator constructs themselves\n * from `WALLET_RPC_ENDPOINTS` / `STARKNET_NETWORKS` keep stock starknet.js fetch behaviour.\n */\nexport function makeRpcBaseFetch(label: string): typeof fetch {\n return async (input, init) => {\n let response: Response;\n try {\n response = await fetch(input, {\n ...init,\n // RN and older runtimes may not have AbortSignal.timeout. Only use it when present.\n signal:\n init?.signal ??\n (typeof AbortSignal !== \"undefined\" && typeof AbortSignal.timeout === \"function\"\n ? AbortSignal.timeout(RPC_TIMEOUT_MS)\n : undefined),\n });\n } catch (err) {\n // Network unreachable, DNS failure, connection reset, timeout/abort.\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(`${TRANSPORT_MARKER} endpoint \"${label}\" fetch failed: ${detail}`);\n }\n\n if (response.ok) return response;\n\n // Non-2xx. A node that actually answered still returns a JSON-RPC envelope; anything\n // else (rate-limit page, REST-shaped auth rejection, gateway error) is a transport failure.\n const body = await response.text();\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n parsed = undefined;\n }\n // A real envelope, not merely \"some JSON with an error field\". Lava's\n // discontinuation notice ({\"error\":\"This endpoint has been discontinued.\"},\n // HTTP 410) passed an `\"error\" in parsed` test, was re-served as a 200, and\n // starknet.js turned it into an RpcError with undefined fields that the\n // fallback honoured as chain truth, stranding the chain behind a dead\n // endpoint (2026-09-07 chipi-back prod balance outage). A node that\n // actually answered wraps its error in an OBJECT with a numeric `code`;\n // a string `error` is a REST body: the endpoint did not answer.\n const isJsonRpcEnvelope =\n !!parsed &&\n typeof parsed === \"object\" &&\n (\"result\" in parsed ||\n (typeof (parsed as { error?: unknown }).error === \"object\" &&\n (parsed as { error?: unknown }).error !== null &&\n typeof (parsed as { error: { code?: unknown } }).error.code === \"number\"));\n\n if (isJsonRpcEnvelope && !isTransportStatus(response.status)) {\n // A well-formed JSON-RPC error that merely arrived over a non-200 status. Hand it back\n // so starknet.js raises a proper RpcError instead of a parse error, and so the chain\n // does NOT burn other endpoints on a question they would all answer identically.\n return new Response(body, { status: 200, headers: { \"content-type\": \"application/json\" } });\n }\n\n // Label only: never the URL (query params) and never the headers (API key).\n throw new Error(`${TRANSPORT_MARKER} endpoint \"${label}\" returned HTTP ${response.status}`);\n };\n}\n\nconst TRANSPORT_MESSAGE_HINTS = [\n TRANSPORT_MARKER,\n // network / socket\n \"fetch failed\",\n \"failed to fetch\",\n \"network error\",\n \"networkerror\",\n \"socket hang up\",\n \"econnreset\",\n \"econnrefused\",\n \"econnaborted\",\n \"enotfound\",\n \"etimedout\",\n \"ehostunreach\",\n \"enetunreach\",\n \"epipe\",\n // timeouts / cancellation\n \"timeout\",\n \"timed out\",\n \"aborted\",\n // JSON parse failure: an error page or truncated body instead of a JSON-RPC envelope\n \"unexpected token\",\n \"unexpected end of json\",\n \"is not valid json\",\n \"invalid json\",\n \"json parse\",\n];\n\n/**\n * True only for transport-class failures (network/fetch error, timeout, HTTP 401/403/404/\n * 429/5xx, JSON parse failure).\n *\n * A well-formed JSON-RPC error (\"Contract not found\", \"Invalid params\") means the node\n * answered correctly: it is NOT a transport failure, so the caller rethrows immediately\n * instead of burning the rest of the chain on a question every node answers the same way.\n */\n/**\n * Starkscan's gateway code for \"this credential cannot do this here\" (missing RPC scope, rate\n * cap). Live 2026-08-15 as HTTP 403 + `{error:{code:-32012}}`, and also observed on HTTP 200.\n */\nconst STARKSCAN_GATEWAY_REFUSAL = -32012;\n\n/** Reads a JSON-RPC error code off whatever shape starknet.js hands us, or undefined. */\nfunction jsonRpcErrorCode(err: unknown): number | undefined {\n const e = err as { code?: unknown; baseError?: { code?: unknown } } | null | undefined;\n const raw = e?.baseError?.code ?? e?.code;\n return typeof raw === \"number\" ? raw : undefined;\n}\n\nfunction isTransportFailure(err: unknown): boolean {\n if (!err) return false;\n\n const e = err as {\n name?: string;\n message?: string;\n baseError?: unknown;\n status?: number;\n statusCode?: number;\n cause?: unknown;\n };\n\n // Starkscan's gateway signals a per-endpoint refusal (missing key scope, rate cap) with\n // this code, sometimes on an HTTP 200. Neither is chain truth, so it must fail over even\n // though it arrives as a well-formed JSON-RPC error. Auth is a property of OUR credential\n // at THIS endpoint, never of the chain.\n if (jsonRpcErrorCode(err) === STARKSCAN_GATEWAY_REFUSAL) return true;\n\n // starknet.js RpcError: the node replied with a JSON-RPC error envelope. Duck-typed\n // rather than `instanceof` so unit tests that mock the starknet module still take this path.\n if (e.name === \"RpcError\" || e.baseError !== undefined) return false;\n\n const status = typeof e.status === \"number\" ? e.status : e.statusCode;\n if (typeof status === \"number\" && isTransportStatus(status)) return true;\n\n if (e.name === \"AbortError\" || e.name === \"TimeoutError\" || e.name === \"SyntaxError\") return true;\n\n const message = typeof e.message === \"string\" ? e.message.toLowerCase() : \"\";\n if (message && TRANSPORT_MESSAGE_HINTS.some((hint) => message.includes(hint))) return true;\n\n // Node's fetch wraps the underlying socket error in `cause`.\n if (e.cause && e.cause !== err) return isTransportFailure(e.cause);\n\n return false;\n}\n\nconst providerCache = new Map<string, RpcProvider>();\n\n/** Memoized provider for one endpoint. */\nexport function rpcProviderFor(endpoint: RpcEndpoint): RpcProvider {\n const cacheKey = `${endpoint.label}|${endpoint.url}|${endpoint.headers ? \"auth\" : \"anon\"}`;\n const cached = providerCache.get(cacheKey);\n if (cached) return cached;\n\n const provider = new RpcProvider({\n nodeUrl: endpoint.url,\n baseFetch: makeRpcBaseFetch(endpoint.label),\n ...(endpoint.headers ? { headers: endpoint.headers } : {}),\n });\n providerCache.set(cacheKey, provider);\n return provider;\n}\n\n/**\n * Run a read against the endpoint chain, advancing to the next endpoint only when the\n * current one fails at transport level.\n *\n * Use for reads and for confirmation polling (both idempotent). Do NOT use it to wrap a\n * transaction submission: a retry on a different node could double-submit.\n */\nexport async function withRpcFallback<T>(\n fn: (provider: RpcProvider) => Promise<T>,\n opts?: { fallbackUrl?: string }\n): Promise<T> {\n const chain = buildRpcChain(opts);\n if (chain.length === 0) {\n // Defensive: buildRpcChain always appends a keyless endpoint, so this is unreachable.\n throw new Error(\"No Starknet RPC endpoint configured\");\n }\n\n let lastError: unknown;\n\n for (let i = 0; i < chain.length; i++) {\n const endpoint = chain[i];\n const isLast = i === chain.length - 1;\n\n try {\n const result = await fn(rpcProviderFor(endpoint));\n\n // An empty result is a transport failure in disguise, NOT a valid answer.\n // Starkscan rejects a bad/missing/expired API key with HTTP 401 carrying a\n // REST-shaped body (`{\"code\":\"unauthorized\",\"message\":\"Unauthorized\",...}`)\n // instead of a JSON-RPC error object. starknet.js cannot parse that: on both\n // 9.2.1 and 9.4.2, `getBlockNumber()` / `callContract()` resolve to `undefined`\n // and DO NOT THROW. Without this guard a wrong key would silently return\n // `undefined` from every SDK read with no error at all. Discriminate on\n // `undefined`/`null` ONLY: `0`, `\"0x0\"`, `false` and `[]` are legitimate\n // results (a balance read legitimately returns `[\"0x0\",\"0x0\"]`).\n if (result === undefined || result === null) {\n if (isLast) {\n throw new Error(\n `Starknet RPC endpoint \"${endpoint.label}\" returned an empty response ` +\n `(no JSON-RPC result). If this endpoint requires an API key, the key is ` +\n `likely missing, wrong or expired.`\n );\n }\n lastError = new Error(\n `${TRANSPORT_MARKER} endpoint \"${endpoint.label}\" returned an empty response`\n );\n continue;\n }\n\n return result;\n } catch (error) {\n if (isLast || !isTransportFailure(error)) throw error;\n lastError = error;\n // Label only: never the endpoint URL, headers or the API key.\n console.warn(\n `[chipi:rpc] transport failure on \"${endpoint.label}\" (${i + 1}/${chain.length}), falling through`\n );\n }\n }\n\n throw lastError instanceof Error\n ? lastError\n : new Error(`All Starknet RPC endpoints failed: ${String(lastError)}`);\n}\n","/**\n * Constants used across Chipi SDK packages\n */\n\nimport type { ShhhSignerKind, WalletType } from \"@chipi-stack/types\";\nimport { CARTRIDGE_MAINNET_RPC, DEFAULT_MAINNET_RPC, DEFAULT_SEPOLIA_RPC, readEnv } from \"./rpc\";\n\n// Ordered RPC chain + transport-level failover (Starkscan is primary only when\n// STARKSCAN_API_KEY is set; keyless integrators keep today's endpoint).\nexport * from \"./rpc\";\n\n/**\n * API Versioning\n * - VERSION: Major version for path-based versioning (/v1, /v2, etc.)\n * - VERSION_DATE: Detailed version for tracking breaking changes (YYYY-MM-DD format)\n *\n * Update VERSION_DATE when making API changes.\n * Update VERSION when making major breaking changes (typically 1-2 times per year).\n */\nexport const API_VERSIONING = {\n VERSION: \"1\", // Major version - used in URL path\n VERSION_DATE: \"2025-12-30\", // Detailed version - sent as query param for tracking\n} as const;\n\n// Default RPC URLs — override via STARKNET_RPC_URL / STARKNET_RPC_URL_SEPOLIA env vars.\n// The URL literals now live in ./rpc.ts alongside the failover chain that uses them;\n// the resolved values here are unchanged.\n\n// These evaluate at MODULE SCOPE, and this module is bundled into browser-facing\n// packages, so a bare `process.env` read throws at import time anywhere `process`\n// is not defined. It has worked so far only because bundlers inject a shim, which\n// makes client-side imports of this package accidental rather than supported.\n// `readEnv` is the same guard ./rpc.ts already uses; server behaviour is identical.\nexport const STARKNET_NETWORKS = {\n MAINNET: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n // Last resort of the mainnet chain built by buildRpcChain(), no longer a dead constant.\n MAINNET_FALLBACK: CARTRIDGE_MAINNET_RPC,\n SEPOLIA: readEnv(\"STARKNET_RPC_URL_SEPOLIA\") ?? DEFAULT_SEPOLIA_RPC,\n} as const;\n\nexport const CONTRACT_ADDRESSES = {\n USDC_MAINNET: \"0x033068F6539f8e6e6b131e6B2B814e6c34A5224bC66947c47DaB9dFeE93b35fb\", // Changed to Native USDC (was bridged USDC.e)\n VESU_USDC_MAINNET: \"0x017f19582c61479f2fe0b6606300e975c0a8f439102f43eeecc1d0e9b3d84350\",\n} as const;\n\nexport const TOKEN_DECIMALS = {\n USDC: 6,\n USDT: 6,\n ETH: 18,\n STRK: 18,\n DAI: 18,\n} as const;\n\nexport const API_ENDPOINTS = {\n CHIPI_WALLETS: \"/chipi-wallets\",\n TRANSACTIONS: \"/transactions\",\n SKUS: \"/skus\",\n SKU_PURCHASES: \"/sku-purchases\",\n EXCHANGES: \"/exchanges\",\n USERS: \"/users\",\n // SHHH multisig coordination (Plus Wave 9 / P1): SDK-exposed treasury\n // propose / sign / execute / list, owner-signature-authed.\n TREASURIES: \"/treasuries\",\n} as const;\n\nexport const ERRORS = {\n INVALID_API_KEY: \"INVALID_API_KEY\",\n WALLET_NOT_FOUND: \"WALLET_NOT_FOUND\",\n INSUFFICIENT_BALANCE: \"INSUFFICIENT_BALANCE\",\n TRANSACTION_FAILED: \"TRANSACTION_FAILED\",\n INVALID_SIGNATURE: \"INVALID_SIGNATURE\",\n SKU_NOT_FOUND: \"SKU_NOT_FOUND\",\n SKU_UNAVAILABLE: \"SKU_UNAVAILABLE\",\n} as const;\n\nexport const SKU_CONTRACTS = {\n RECHARGER_WITH_STRK_MAINNET: \"0x02d65bb726d2c29e3c97669cf297c5145eac19284fb6f935c05c0bfc68dae2b7\", //changed contract address used to be 0x0f3\n CHIPI_BILL_SERVICE: \"0x4e8150110d580069de26adec9b179023289d55859ea07487aaade5458d7aa8b\",\n} as const;\n\n// Service types\nexport const SERVICE_TYPES = {\n BUY_SERVICE: \"BUY_SERVICE\",\n} as const;\n\n// Carrier IDs\nexport const CARRIER_IDS = {\n CHIPI_PAY: \"chipi_pay\",\n} as const;\n\nexport const CHAIN_TYPES = {\n STARKNET: \"STARKNET\",\n} as const;\n\nexport const CHAIN_TOKEN_TYPES = {\n USDC: \"USDC\", // Changed to Native USDC (was bridged USDC.e)\n USDT: \"USDT\",\n ETH: \"ETH\",\n STRK: \"STRK\",\n DAI: \"DAI\",\n WBTC: \"WBTC\",\n OTHER: \"OTHER\",\n} as const;\n\nexport const WALLET_CLASS_HASHES: Record<string, string> = {\n CHIPI: \"0x053f4f8791ed5bed0fddaa553d180c664e32cfaf8316bb232ae77bb08f459f2a\", // v29 — must match backend until coordinated v33 upgrade\n READY: \"0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f\",\n SHHH: \"0x075dfb396145926bffa6beb659897f46cc082a50b211d80871cff7f1038fa58a\", // V8.4 ShhhAccount — declared 2026-05-15, audit-closed\n};\n\n/**\n * Previous CHIPI wallet class hashes that are still deployed on-chain.\n * Used by getWalletTypeFromClassHash() to identify legacy wallets.\n * Ordered newest → oldest.\n */\nexport const LEGACY_CHIPI_CLASS_HASHES: string[] = [\n \"0x0484bbd2404b3c7264bea271f7267d6d4004821ac7787a9eed7f472e79ef40d1\", // v33 — wallets created during brief v33 window\n \"0x035a2251aca25daba18a5d8950deffa8372a7d84774554e75283cb85552eebc9\", // v32 — audit 3\n \"0x0254f6dd0427319ec614c29e4e3929500d1ba95d0da87ff81d67051ce572667\", // v31\n \"0x072b77b033a874fa1b8f7ff52e18be8fb5ce01a00c59cd184ae15f5b29bc0e57\", // v30\n \"0x02de1565226d5215a38b68c4d9a4913989b54edff64c68c45e453c417b44cd83\", // v28\n];\n\n/**\n * Deprecated SHHH class hashes that may exist on-chain but must NOT be routed\n * for new deploys. V8 series ships without an `upgrade` selector, so existing\n * instances at deprecated classes cannot self-upgrade — they redeploy at the\n * current SHHH class hash.\n */\nexport const LEGACY_SHHH_CLASS_HASHES: string[] = [\n \"0x03bc539295abd3e59bd9ea799d12fe3331748d484bc77bff45b302b1636a87d9\", // V8.3 — deprecated 2026-05-15, no stranded-bootstrap recovery\n];\n\n/**\n * SHHH ShhhAccount verifier class hashes (V8.4, mainnet).\n *\n * The ShhhAccount dispatches `verify` to one of these verifier classes via\n * `library_call_syscall` based on the owner's `kind_tag`. Verifier classes are\n * pinned to deterministic outputs of `scarb build` at commit `3975532` (tag\n * v8.4) — Chipi routes to these hashes as a consumer; we do not redeclare.\n */\nexport const SHHH_VERIFIER_CLASS_HASHES: Record<ShhhSignerKind, string> = {\n STARK: \"0x00d09209b2da9d49fc805ba26380ba4ce25aa641116c10eb178e1051a71dbf68\",\n ED25519: \"0x030a7dfc03e59cef6e41699e734abd2df53ce393a052221c02c6e07665949f74\",\n SECP256K1: \"0x03e81667a46bd5287e09a9600fa98d28fdc477735f2689f5f4e8e95f37b67b74\",\n EIP191_SECP256K1: \"0x03a75997862059c36cb8e204fb3027eb6d1fdf933488d42c2db4528118d084e6\",\n EIP712_SECP256K1: \"0x072a3f77e8c28bfea2ade91ec3fb83b6290169d1ed8c1b2396704231841c6474\",\n P256: \"0x01b600709af54c8838e5f18ddad3a26feeb47cb124c239f55a0f1b7a780e2d8a\",\n WEBAUTHN_P256: \"0x074f6efd2af9025cd8cab41a4565bc73b6ef097214c31352838fcdbac0a44657\",\n JWT_ES256: \"0x002efce875fa3e73e04d825d8ebade53e188cc995dfe0c55a6a2f7fa6c59f497\",\n JWT_ES256_APPLE_SUB: \"0x06b67762218a25fdd28e25b063480893a5cef9cdeecbc663e32d444d5734c471\",\n BLS12_381: \"0x02623721e74a9ad3e0ba639065f5631a09bf900913de6ab21ea6984973cd2cd1\",\n};\n\n/**\n * Upper-bound l2_gas overhead per SHHH signer kind, in addition to base\n * paymaster execution cost. Numbers from snforge runs at tag v8.4\n * (252-byte calls, single owner, no session key). Paymaster adds ~5M safety\n * margin on top.\n *\n * Threshold envelopes: sum the per-owner cost + ~3M aggregation overhead.\n * Session-key envelopes (SNIP-163 4-felt): ~2M + session-policy enforcement.\n */\nexport const SHHH_KIND_GAS_OVERHEAD: Record<ShhhSignerKind, number> = {\n STARK: 2_000_000,\n SECP256K1: 5_000_000,\n EIP191_SECP256K1: 10_000_000,\n EIP712_SECP256K1: 12_000_000,\n P256: 30_000_000,\n ED25519: 33_000_000,\n WEBAUTHN_P256: 35_000_000,\n JWT_ES256: 60_000_000,\n JWT_ES256_APPLE_SUB: 62_000_000,\n BLS12_381: 80_000_000,\n};\n\n/**\n * Inner-envelope routing tags per the V8.4 Pluggable-Signer SNIP draft.\n * The ShhhAccount strips the version tag and library_calls the verifier;\n * Chipi paymaster does NOT need to parse the inner payload but DOES need\n * to pass the entire signature span verbatim to `execute_from_outside_v2`.\n */\nexport const SHHH_ENVELOPE_TAGS = {\n V2_SNIP12: \"V2_SNIP12\",\n V2_THRESHOLD: \"V2_THRESHOLD\",\n // Session-key envelopes are the SNIP-163 4-felt format (no version tag prefix).\n} as const;\n\n/**\n * Determine wallet type from an on-chain class hash.\n * - If it matches the READY hash → READY\n * - If it matches the current CHIPI hash or a legacy CHIPI hash → CHIPI\n * - If it matches the current SHHH hash or a legacy SHHH hash → SHHH\n * - Otherwise → null (unknown class hash, caller should handle accordingly)\n */\nexport function getWalletTypeFromClassHash(classHash: string): WalletType | null {\n const normalize = (h: string) => h.toLowerCase().replace(/^0x0+/, \"0x\");\n const normalized = normalize(classHash);\n\n if (normalize(WALLET_CLASS_HASHES.READY) === normalized) {\n return \"READY\";\n }\n if (normalize(WALLET_CLASS_HASHES.CHIPI) === normalized) {\n return \"CHIPI\";\n }\n if (LEGACY_CHIPI_CLASS_HASHES.some((h) => normalize(h) === normalized)) {\n return \"CHIPI\";\n }\n if (normalize(WALLET_CLASS_HASHES.SHHH) === normalized) {\n return \"SHHH\";\n }\n if (LEGACY_SHHH_CLASS_HASHES.some((h) => normalize(h) === normalized)) {\n return \"SHHH\";\n }\n // Unknown class hash — return null so callers can handle explicitly\n return null;\n}\n\n/**\n * Returns true if a class hash is a registered SHHH ShhhAccount class\n * (current or legacy) OR one of the 10 V8.4 verifier classes. Used by the\n * backend to reject unknown class hashes when an integrator opts into SHHH\n * via `walletType: \"SHHH\"` (D4 safety net — open SDK option, no per-org gate).\n */\nexport function isKnownShhhClassHash(classHash: string): boolean {\n const normalize = (h: string) => h.toLowerCase().replace(/^0x0+/, \"0x\");\n const normalized = normalize(classHash);\n\n if (normalize(WALLET_CLASS_HASHES.SHHH) === normalized) return true;\n if (LEGACY_SHHH_CLASS_HASHES.some((h) => normalize(h) === normalized)) return true;\n return Object.values(SHHH_VERIFIER_CLASS_HASHES).some((h) => normalize(h) === normalized);\n}\n\n// RPC endpoints per wallet type — any standard Starknet RPC works for all wallet types.\n// Override via STARKNET_RPC_URL env var; falls back to the default Infura endpoint.\n//\n// Deliberately still a Record<string, string> of plain URLs: it is a published API\n// consumed as URL strings in ~8 places, so widening it would be a breaking change.\n// A Starkscan endpoint cannot be represented here anyway (its key must travel in a\n// header, never in the URL). Pass these values as `buildRpcChain({ fallbackUrl })` /\n// `withRpcFallback(fn, { fallbackUrl })` to get the header-authed chain on top.\nexport const WALLET_RPC_ENDPOINTS: Record<string, string> = {\n CHIPI: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n READY: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n SHHH: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n};\n\n// Paymaster configuration\nexport const PAYMASTER_CONFIG = {\n URL: \"https://paymaster.chipipay.com\",\n} as const;\n\n// Session key configuration (CHIPI wallets only - SNIP-9 compatible)\nexport const SESSION_DEFAULTS = {\n /** Default session duration: 6 hours in seconds */\n DURATION_SECONDS: 21600,\n /** Default max calls per session */\n MAX_CALLS: 1000,\n} as const;\n\n// Session-specific error codes\nexport const SESSION_ERRORS = {\n /** Session keys only work with CHIPI wallets */\n INVALID_WALLET_TYPE_FOR_SESSION: \"INVALID_WALLET_TYPE_FOR_SESSION\",\n /** Session has expired (validUntil < now) */\n SESSION_EXPIRED: \"SESSION_EXPIRED\",\n /** Session key not registered on contract */\n SESSION_NOT_REGISTERED: \"SESSION_NOT_REGISTERED\",\n /** Session key has been revoked */\n SESSION_REVOKED: \"SESSION_REVOKED\",\n /** Session has exceeded max calls */\n SESSION_MAX_CALLS_EXCEEDED: \"SESSION_MAX_CALLS_EXCEEDED\",\n /** Entrypoint not allowed for this session */\n SESSION_ENTRYPOINT_NOT_ALLOWED: \"SESSION_ENTRYPOINT_NOT_ALLOWED\",\n /** Failed to decrypt session private key */\n SESSION_DECRYPTION_FAILED: \"SESSION_DECRYPTION_FAILED\",\n /** Failed to create session key */\n SESSION_CREATION_FAILED: \"SESSION_CREATION_FAILED\",\n /** Backend returned an invalid response shape */\n SESSION_INVALID_RESPONSE: \"SESSION_INVALID_RESPONSE\",\n /** Invalid spending policy configuration */\n INVALID_SPENDING_POLICY: \"INVALID_SPENDING_POLICY\",\n} as const;\n\n// Session contract entrypoint names\nexport const SESSION_ENTRYPOINTS = {\n /** Add or update a session key (owner only) */\n ADD_OR_UPDATE: \"add_or_update_session_key\",\n /** Revoke a session key (owner only) */\n REVOKE: \"revoke_session_key\",\n /** Query session data (public read) */\n GET_DATA: \"get_session_data\",\n /** Set a spending policy for a session key + token pair (owner only) */\n SET_SPENDING_POLICY: \"set_spending_policy\",\n /** Query a spending policy (public read) */\n GET_SPENDING_POLICY: \"get_spending_policy\",\n /** Remove a spending policy (owner only) */\n REMOVE_SPENDING_POLICY: \"remove_spending_policy\",\n} as const;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/constants/rpc.ts","../../src/constants/index.ts"],"names":["RpcProvider"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Ordered Starknet RPC provider chain with transport-level failover.\n *\n * ## Published-SDK contract (read before changing anything here)\n *\n * `@chipi-stack/*` is consumed by external integrators who do NOT have Chipi's\n * Starkscan API key. The keyless path must keep working with zero configuration,\n * so Starkscan is layered on top rather than baked in:\n *\n * - `STARKSCAN_API_KEY` set (Chipi's own server-side deployments) → Starkscan is\n * the primary endpoint, key travelling in a header.\n * - `STARKSCAN_API_KEY` unset (every integrator) → the chain HEAD is byte-identical\n * to the endpoint the SDK resolved before this module existed\n * (`STARKNET_RPC_URL` when set, else the default Infura mainnet URL). The only\n * difference is that the SDK now retries on additional nodes instead of failing.\n *\n * Starkscan is MAINNET-ONLY (`SN_SEPOLIA` answers `unsupported_chain`), so a\n * non-mainnet configuration never gets it (and never gets mainnet fallbacks\n * either; see `buildRpcChain`).\n *\n * The custom `baseFetch` transport classifier is installed ONLY on providers this module\n * builds for the chain. A provider an integrator constructs themselves from\n * `WALLET_RPC_ENDPOINTS` / `STARKNET_NETWORKS` keeps stock starknet.js behaviour, so the\n * blast radius of coupling to starknet.js internals is limited to the chain helper.\n */\nimport { RpcProvider } from \"starknet\";\n\n/**\n * Starkscan's JSON-RPC route. Mainnet only. The key rides in the canonical\n * `X-Starkscan-Api-Key` header, never in the URL.\n */\nexport const STARKSCAN_MAINNET_RPC = \"https://api.starkscan.co/v1/SN_MAIN/rpc\";\n\n/** Public keyless mainnet node used as the last resort in the chain. */\n/** Dead since 2026-09: HTTP 410 \"This endpoint has been discontinued\". Kept only\n * so an integrator pinning it via env still resolves; never pushed into the chain. */\nexport const LAVA_MAINNET_RPC = \"https://rpc.starknet.lava.build\";\n/** Keyless public fallback (Cartridge). Replaces Lava as the chain's last resort. */\nexport const CARTRIDGE_MAINNET_RPC = \"https://api.cartridge.gg/x/starknet/mainnet\";\n\n/** Keyless default mainnet RPC. This is the value published SDKs resolve to today. Do not change. */\nexport const DEFAULT_MAINNET_RPC =\n \"https://starknet-mainnet.infura.io/v3/4a4a1fdd7d704509aa99154fb29886e2\";\n\n/** Keyless default sepolia RPC. Starkscan is never layered onto this. */\nexport const DEFAULT_SEPOLIA_RPC =\n \"https://starknet-sepolia.infura.io/v3/4a4a1fdd7d704509aa99154fb29886e2\";\n\nexport type RpcEndpoint = { label: string; url: string; headers?: Record<string, string> };\n\n/**\n * Read an env var defensively: this module is bundled into browser-facing packages\n * where `process` may not exist. Empty / whitespace-only values are treated as unset.\n */\nexport function readEnv(name: string): string | undefined {\n if (typeof process === \"undefined\" || !process.env) return undefined;\n const value = process.env[name];\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Anything that is clearly not Starknet mainnet. A non-mainnet head must never be\n * followed by mainnet fallbacks (answering a sepolia question with mainnet state is\n * worse than failing), so such a chain stays single-entry.\n */\nfunction looksNonMainnet(url: string): boolean {\n return /sepolia|goerli|testnet|devnet|localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0/i.test(url);\n}\n\n/**\n * Build the ordered endpoint chain.\n *\n * @param opts.fallbackUrl the URL this call site resolved on its own (e.g.\n * `WALLET_RPC_ENDPOINTS[walletType]` or an integrator-supplied `nodeUrl`). It is the\n * first KEYLESS entry, which is what keeps the no-Starkscan behaviour byte-identical\n * to today.\n *\n * Order: starkscan (only with a key) → caller URL → `STARKNET_RPC_URL` → Infura default\n * → cartridge. De-duplicated by URL so an operator who pins `STARKNET_RPC_URL` there does\n * not get the same node twice (which would make \"fallback\" a no-op).\n */\nexport function buildRpcChain(opts?: { fallbackUrl?: string }): RpcEndpoint[] {\n const callerUrl = opts?.fallbackUrl?.trim() || undefined;\n const envUrl = readEnv(\"STARKNET_RPC_URL\");\n\n // The endpoint this call site would have used before this module existed.\n const head = callerUrl ?? envUrl ?? DEFAULT_MAINNET_RPC;\n\n // Non-mainnet deployments keep exactly one endpoint: no Starkscan (it rejects\n // SN_SEPOLIA with `unsupported_chain`) and no cross-chain fallback.\n if (looksNonMainnet(head)) {\n return [{ label: \"configured\", url: head }];\n }\n\n const chain: RpcEndpoint[] = [];\n const seen = new Set<string>();\n\n const push = (label: string, url: string | undefined, headers?: Record<string, string>) => {\n if (!url) return;\n const nodeUrl = url.trim();\n if (!nodeUrl) return;\n const key = nodeUrl.replace(/\\/+$/, \"\").toLowerCase();\n if (seen.has(key)) return;\n seen.add(key);\n chain.push(headers ? { label, url: nodeUrl, headers } : { label, url: nodeUrl });\n };\n\n // Server-only key. Never logged, never interpolated into a URL, never shipped in a\n // browser bundle's env. Absent (every external integrator) → chain is unchanged.\n const starkscanApiKey = readEnv(\"STARKSCAN_API_KEY\");\n if (starkscanApiKey) {\n push(\"starkscan\", STARKSCAN_MAINNET_RPC, { \"X-Starkscan-Api-Key\": starkscanApiKey });\n }\n\n push(\"caller\", callerUrl);\n push(\"env\", envUrl);\n push(\"default\", DEFAULT_MAINNET_RPC);\n push(\"cartridge\", CARTRIDGE_MAINNET_RPC);\n\n return chain;\n}\n\n/**\n * Marker on transport-class failures we raise ourselves. starknet.js re-wraps thrown\n * fetch errors as a plain `Error(message)`, so the error *instance* does not survive the\n * round trip. Only the message text does.\n */\nconst TRANSPORT_MARKER = \"[chipi-rpc-transport]\";\n\n/**\n * HTTP statuses that mean \"this endpoint did not answer\" rather than \"the chain says no\":\n * 429/5xx (rate limited / node broken) plus 401/403/404, which is what a missing, wrong,\n * rotated or unprovisioned API key looks like. Falling through is exactly right there.\n */\nfunction isTransportStatus(status: number): boolean {\n return (\n status === 401 ||\n status === 403 ||\n status === 404 ||\n status === 410 || // Gone: a discontinued endpoint (Lava, 2026-09) is transport, not chain truth\n status === 429 ||\n status >= 500\n );\n}\n\n/** Per-request budget for one RPC round-trip before we call it a transport failure. */\nconst RPC_TIMEOUT_MS = 15_000;\n\n/**\n * Wraps global fetch so an HTTP-level failure is classified while the status code is\n * still visible.\n *\n * This is necessary because **starknet.js never inspects the HTTP status**:\n * `RpcChannel.fetchEndpoint` goes straight to `.json()`. Without this wrapper a rate-limit\n * page or an auth rejection surfaces either as an opaque JSON parse error or, when the body\n * happens to be valid JSON, as a silent `undefined` result.\n *\n * Scope note (published SDK): this wrapper is installed ONLY on providers built by\n * `rpcProviderFor` for the fallback chain. Providers an integrator constructs themselves\n * from `WALLET_RPC_ENDPOINTS` / `STARKNET_NETWORKS` keep stock starknet.js fetch behaviour.\n */\nexport function makeRpcBaseFetch(label: string): typeof fetch {\n return async (input, init) => {\n let response: Response;\n try {\n response = await fetch(input, {\n ...init,\n // RN and older runtimes may not have AbortSignal.timeout. Only use it when present.\n signal:\n init?.signal ??\n (typeof AbortSignal !== \"undefined\" && typeof AbortSignal.timeout === \"function\"\n ? AbortSignal.timeout(RPC_TIMEOUT_MS)\n : undefined),\n });\n } catch (err) {\n // Network unreachable, DNS failure, connection reset, timeout/abort.\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(`${TRANSPORT_MARKER} endpoint \"${label}\" fetch failed: ${detail}`);\n }\n\n if (response.ok) return response;\n\n // Non-2xx. A node that actually answered still returns a JSON-RPC envelope; anything\n // else (rate-limit page, REST-shaped auth rejection, gateway error) is a transport failure.\n const body = await response.text();\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n parsed = undefined;\n }\n // A real envelope, not merely \"some JSON with an error field\". Lava's\n // discontinuation notice ({\"error\":\"This endpoint has been discontinued.\"},\n // HTTP 410) passed an `\"error\" in parsed` test, was re-served as a 200, and\n // starknet.js turned it into an RpcError with undefined fields that the\n // fallback honoured as chain truth, stranding the chain behind a dead\n // endpoint (2026-09-07 chipi-back prod balance outage). A node that\n // actually answered wraps its error in an OBJECT with a numeric `code`;\n // a string `error` is a REST body: the endpoint did not answer.\n const isJsonRpcEnvelope =\n !!parsed &&\n typeof parsed === \"object\" &&\n (\"result\" in parsed ||\n (typeof (parsed as { error?: unknown }).error === \"object\" &&\n (parsed as { error?: unknown }).error !== null &&\n typeof (parsed as { error: { code?: unknown } }).error.code === \"number\"));\n\n if (isJsonRpcEnvelope && !isTransportStatus(response.status)) {\n // A well-formed JSON-RPC error that merely arrived over a non-200 status. Hand it back\n // so starknet.js raises a proper RpcError instead of a parse error, and so the chain\n // does NOT burn other endpoints on a question they would all answer identically.\n return new Response(body, { status: 200, headers: { \"content-type\": \"application/json\" } });\n }\n\n // Label only: never the URL (query params) and never the headers (API key).\n throw new Error(`${TRANSPORT_MARKER} endpoint \"${label}\" returned HTTP ${response.status}`);\n };\n}\n\nconst TRANSPORT_MESSAGE_HINTS = [\n TRANSPORT_MARKER,\n // network / socket\n \"fetch failed\",\n \"failed to fetch\",\n \"network error\",\n \"networkerror\",\n \"socket hang up\",\n \"econnreset\",\n \"econnrefused\",\n \"econnaborted\",\n \"enotfound\",\n \"etimedout\",\n \"ehostunreach\",\n \"enetunreach\",\n \"epipe\",\n // timeouts / cancellation\n \"timeout\",\n \"timed out\",\n \"aborted\",\n // JSON parse failure: an error page or truncated body instead of a JSON-RPC envelope\n \"unexpected token\",\n \"unexpected end of json\",\n \"is not valid json\",\n \"invalid json\",\n \"json parse\",\n];\n\n/**\n * True only for transport-class failures (network/fetch error, timeout, HTTP 401/403/404/\n * 429/5xx, JSON parse failure).\n *\n * A well-formed JSON-RPC error (\"Contract not found\", \"Invalid params\") means the node\n * answered correctly: it is NOT a transport failure, so the caller rethrows immediately\n * instead of burning the rest of the chain on a question every node answers the same way.\n */\n/**\n * Starkscan's gateway code for \"this credential cannot do this here\" (missing RPC scope, rate\n * cap). Live 2026-08-15 as HTTP 403 + `{error:{code:-32012}}`, and also observed on HTTP 200.\n */\nconst STARKSCAN_GATEWAY_REFUSAL = -32012;\n\n/** Reads a JSON-RPC error code off whatever shape starknet.js hands us, or undefined. */\nfunction jsonRpcErrorCode(err: unknown): number | undefined {\n const e = err as { code?: unknown; baseError?: { code?: unknown } } | null | undefined;\n const raw = e?.baseError?.code ?? e?.code;\n return typeof raw === \"number\" ? raw : undefined;\n}\n\nfunction isTransportFailure(err: unknown): boolean {\n if (!err) return false;\n\n const e = err as {\n name?: string;\n message?: string;\n baseError?: unknown;\n status?: number;\n statusCode?: number;\n cause?: unknown;\n };\n\n // Starkscan's gateway signals a per-endpoint refusal (missing key scope, rate cap) with\n // this code, sometimes on an HTTP 200. Neither is chain truth, so it must fail over even\n // though it arrives as a well-formed JSON-RPC error. Auth is a property of OUR credential\n // at THIS endpoint, never of the chain.\n if (jsonRpcErrorCode(err) === STARKSCAN_GATEWAY_REFUSAL) return true;\n\n // starknet.js RpcError: the node replied with a JSON-RPC error envelope. Duck-typed\n // rather than `instanceof` so unit tests that mock the starknet module still take this path.\n if (e.name === \"RpcError\" || e.baseError !== undefined) return false;\n\n const status = typeof e.status === \"number\" ? e.status : e.statusCode;\n if (typeof status === \"number\" && isTransportStatus(status)) return true;\n\n if (e.name === \"AbortError\" || e.name === \"TimeoutError\" || e.name === \"SyntaxError\") return true;\n\n const message = typeof e.message === \"string\" ? e.message.toLowerCase() : \"\";\n if (message && TRANSPORT_MESSAGE_HINTS.some((hint) => message.includes(hint))) return true;\n\n // Node's fetch wraps the underlying socket error in `cause`.\n if (e.cause && e.cause !== err) return isTransportFailure(e.cause);\n\n return false;\n}\n\nconst providerCache = new Map<string, RpcProvider>();\n\n/** Memoized provider for one endpoint. */\nexport function rpcProviderFor(endpoint: RpcEndpoint): RpcProvider {\n const cacheKey = `${endpoint.label}|${endpoint.url}|${endpoint.headers ? \"auth\" : \"anon\"}`;\n const cached = providerCache.get(cacheKey);\n if (cached) return cached;\n\n const provider = new RpcProvider({\n nodeUrl: endpoint.url,\n baseFetch: makeRpcBaseFetch(endpoint.label),\n ...(endpoint.headers ? { headers: endpoint.headers } : {}),\n });\n providerCache.set(cacheKey, provider);\n return provider;\n}\n\n/**\n * Run a read against the endpoint chain, advancing to the next endpoint only when the\n * current one fails at transport level.\n *\n * Use for reads and for confirmation polling (both idempotent). Do NOT use it to wrap a\n * transaction submission: a retry on a different node could double-submit.\n */\nexport async function withRpcFallback<T>(\n fn: (provider: RpcProvider) => Promise<T>,\n opts?: { fallbackUrl?: string }\n): Promise<T> {\n const chain = buildRpcChain(opts);\n if (chain.length === 0) {\n // Defensive: buildRpcChain always appends a keyless endpoint, so this is unreachable.\n throw new Error(\"No Starknet RPC endpoint configured\");\n }\n\n let lastError: unknown;\n\n for (let i = 0; i < chain.length; i++) {\n const endpoint = chain[i];\n const isLast = i === chain.length - 1;\n\n try {\n const result = await fn(rpcProviderFor(endpoint));\n\n // An empty result is a transport failure in disguise, NOT a valid answer.\n // Starkscan rejects a bad/missing/expired API key with HTTP 401 carrying a\n // REST-shaped body (`{\"code\":\"unauthorized\",\"message\":\"Unauthorized\",...}`)\n // instead of a JSON-RPC error object. starknet.js cannot parse that: on both\n // 9.2.1 and 9.4.2, `getBlockNumber()` / `callContract()` resolve to `undefined`\n // and DO NOT THROW. Without this guard a wrong key would silently return\n // `undefined` from every SDK read with no error at all. Discriminate on\n // `undefined`/`null` ONLY: `0`, `\"0x0\"`, `false` and `[]` are legitimate\n // results (a balance read legitimately returns `[\"0x0\",\"0x0\"]`).\n if (result === undefined || result === null) {\n if (isLast) {\n throw new Error(\n `Starknet RPC endpoint \"${endpoint.label}\" returned an empty response ` +\n `(no JSON-RPC result). If this endpoint requires an API key, the key is ` +\n `likely missing, wrong or expired.`\n );\n }\n lastError = new Error(\n `${TRANSPORT_MARKER} endpoint \"${endpoint.label}\" returned an empty response`\n );\n continue;\n }\n\n return result;\n } catch (error) {\n if (isLast || !isTransportFailure(error)) throw error;\n lastError = error;\n // Label only: never the endpoint URL, headers or the API key.\n console.warn(\n `[chipi:rpc] transport failure on \"${endpoint.label}\" (${i + 1}/${chain.length}), falling through`\n );\n }\n }\n\n throw lastError instanceof Error\n ? lastError\n : new Error(`All Starknet RPC endpoints failed: ${String(lastError)}`);\n}\n","/**\n * Constants used across Chipi SDK packages\n */\n\nimport type { ShhhSignerKind, WalletType } from \"@chipi-stack/types\";\nimport { CARTRIDGE_MAINNET_RPC, DEFAULT_MAINNET_RPC, DEFAULT_SEPOLIA_RPC, readEnv } from \"./rpc\";\n\n// Ordered RPC chain + transport-level failover (Starkscan is primary only when\n// STARKSCAN_API_KEY is set; keyless integrators keep today's endpoint).\nexport * from \"./rpc\";\n\n/**\n * API Versioning\n * - VERSION: Major version for path-based versioning (/v1, /v2, etc.)\n * - VERSION_DATE: Detailed version for tracking breaking changes (YYYY-MM-DD format)\n *\n * Update VERSION_DATE when making API changes.\n * Update VERSION when making major breaking changes (typically 1-2 times per year).\n */\nexport const API_VERSIONING = {\n VERSION: \"1\", // Major version - used in URL path\n VERSION_DATE: \"2025-12-30\", // Detailed version - sent as query param for tracking\n} as const;\n\n// Default RPC URLs — override via STARKNET_RPC_URL / STARKNET_RPC_URL_SEPOLIA env vars.\n// The URL literals now live in ./rpc.ts alongside the failover chain that uses them;\n// the resolved values here are unchanged.\n\n// These evaluate at MODULE SCOPE, and this module is bundled into browser-facing\n// packages, so a bare `process.env` read throws at import time anywhere `process`\n// is not defined. It has worked so far only because bundlers inject a shim, which\n// makes client-side imports of this package accidental rather than supported.\n// `readEnv` is the same guard ./rpc.ts already uses; server behaviour is identical.\nexport const STARKNET_NETWORKS = {\n MAINNET: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n // Last resort of the mainnet chain built by buildRpcChain(), no longer a dead constant.\n MAINNET_FALLBACK: CARTRIDGE_MAINNET_RPC,\n SEPOLIA: readEnv(\"STARKNET_RPC_URL_SEPOLIA\") ?? DEFAULT_SEPOLIA_RPC,\n} as const;\n\nexport const CONTRACT_ADDRESSES = {\n USDC_MAINNET: \"0x033068F6539f8e6e6b131e6B2B814e6c34A5224bC66947c47DaB9dFeE93b35fb\", // Changed to Native USDC (was bridged USDC.e)\n VESU_USDC_MAINNET: \"0x017f19582c61479f2fe0b6606300e975c0a8f439102f43eeecc1d0e9b3d84350\",\n} as const;\n\nexport const TOKEN_DECIMALS = {\n USDC: 6,\n USDT: 6,\n ETH: 18,\n STRK: 18,\n DAI: 18,\n} as const;\n\nexport const API_ENDPOINTS = {\n CHIPI_WALLETS: \"/chipi-wallets\",\n TRANSACTIONS: \"/transactions\",\n SKUS: \"/skus\",\n SKU_PURCHASES: \"/sku-purchases\",\n EXCHANGES: \"/exchanges\",\n USERS: \"/users\",\n // SHHH multisig coordination (Plus Wave 9 / P1): SDK-exposed treasury\n // propose / sign / execute / list, owner-signature-authed.\n TREASURIES: \"/treasuries\",\n} as const;\n\nexport const ERRORS = {\n INVALID_API_KEY: \"INVALID_API_KEY\",\n WALLET_NOT_FOUND: \"WALLET_NOT_FOUND\",\n INSUFFICIENT_BALANCE: \"INSUFFICIENT_BALANCE\",\n TRANSACTION_FAILED: \"TRANSACTION_FAILED\",\n INVALID_SIGNATURE: \"INVALID_SIGNATURE\",\n SKU_NOT_FOUND: \"SKU_NOT_FOUND\",\n SKU_UNAVAILABLE: \"SKU_UNAVAILABLE\",\n} as const;\n\nexport const SKU_CONTRACTS = {\n RECHARGER_WITH_STRK_MAINNET: \"0x02d65bb726d2c29e3c97669cf297c5145eac19284fb6f935c05c0bfc68dae2b7\", //changed contract address used to be 0x0f3\n CHIPI_BILL_SERVICE: \"0x4e8150110d580069de26adec9b179023289d55859ea07487aaade5458d7aa8b\",\n} as const;\n\n// Service types\nexport const SERVICE_TYPES = {\n BUY_SERVICE: \"BUY_SERVICE\",\n} as const;\n\n// Carrier IDs\nexport const CARRIER_IDS = {\n CHIPI_PAY: \"chipi_pay\",\n} as const;\n\nexport const CHAIN_TYPES = {\n STARKNET: \"STARKNET\",\n} as const;\n\nexport const CHAIN_TOKEN_TYPES = {\n USDC: \"USDC\", // Changed to Native USDC (was bridged USDC.e)\n USDT: \"USDT\",\n ETH: \"ETH\",\n STRK: \"STRK\",\n DAI: \"DAI\",\n WBTC: \"WBTC\",\n OTHER: \"OTHER\",\n} as const;\n\nexport const WALLET_CLASS_HASHES: Record<string, string> = {\n CHIPI: \"0x053f4f8791ed5bed0fddaa553d180c664e32cfaf8316bb232ae77bb08f459f2a\", // v29 — must match backend until coordinated v33 upgrade\n READY: \"0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f\",\n // V8.5 ShhhAccount — declared 2026-10-14. The single-owner envelope must\n // carry the threshold (V8.4 ignored it). Needs chipi-back with\n // OPT_IN_SHHH_CLASS_HASHES: createWallet names this class explicitly.\n SHHH: \"0x067828c8b82ac723b4adb141f9aa8975e296d8c11179d22bb8d7203b32abd96a\",\n};\n\n/**\n * Previous CHIPI wallet class hashes that are still deployed on-chain.\n * Used by getWalletTypeFromClassHash() to identify legacy wallets.\n * Ordered newest → oldest.\n */\nexport const LEGACY_CHIPI_CLASS_HASHES: string[] = [\n \"0x0484bbd2404b3c7264bea271f7267d6d4004821ac7787a9eed7f472e79ef40d1\", // v33 — wallets created during brief v33 window\n \"0x035a2251aca25daba18a5d8950deffa8372a7d84774554e75283cb85552eebc9\", // v32 — audit 3\n \"0x0254f6dd0427319ec614c29e4e3929500d1ba95d0da87ff81d67051ce572667\", // v31\n \"0x072b77b033a874fa1b8f7ff52e18be8fb5ce01a00c59cd184ae15f5b29bc0e57\", // v30\n \"0x02de1565226d5215a38b68c4d9a4913989b54edff64c68c45e453c417b44cd83\", // v28\n];\n\n/**\n * Deprecated SHHH class hashes that may exist on-chain but must NOT be routed\n * for new deploys. V8 series ships without an `upgrade` selector, so existing\n * instances at deprecated classes cannot self-upgrade — they redeploy at the\n * current SHHH class hash.\n */\nexport const LEGACY_SHHH_CLASS_HASHES: string[] = [\n \"0x075dfb396145926bffa6beb659897f46cc082a50b211d80871cff7f1038fa58a\", // V8.4 — deprecated 2026-10-14, single-owner path ignores the threshold (safe at threshold 1)\n \"0x03bc539295abd3e59bd9ea799d12fe3331748d484bc77bff45b302b1636a87d9\", // V8.3 — deprecated 2026-05-15, no stranded-bootstrap recovery\n];\n\n/**\n * SHHH ShhhAccount verifier class hashes (V8.4, mainnet).\n *\n * The ShhhAccount dispatches `verify` to one of these verifier classes via\n * `library_call_syscall` based on the owner's `kind_tag`. Verifier classes are\n * pinned to deterministic outputs of `scarb build` at commit `3975532` (tag\n * v8.4) — Chipi routes to these hashes as a consumer; we do not redeclare.\n */\nexport const SHHH_VERIFIER_CLASS_HASHES: Record<ShhhSignerKind, string> = {\n STARK: \"0x00d09209b2da9d49fc805ba26380ba4ce25aa641116c10eb178e1051a71dbf68\",\n ED25519: \"0x030a7dfc03e59cef6e41699e734abd2df53ce393a052221c02c6e07665949f74\",\n SECP256K1: \"0x03e81667a46bd5287e09a9600fa98d28fdc477735f2689f5f4e8e95f37b67b74\",\n EIP191_SECP256K1: \"0x03a75997862059c36cb8e204fb3027eb6d1fdf933488d42c2db4528118d084e6\",\n EIP712_SECP256K1: \"0x072a3f77e8c28bfea2ade91ec3fb83b6290169d1ed8c1b2396704231841c6474\",\n // Starknet browser wallets (Bramble, Braavos, Ready/Argent, OZ) via\n // wallet_signTypedData. Built from shhh-wallet-cairo PR #23 with Scarb 2.14.0\n // (same toolchain that reproduces every hash above). Declared on mainnet\n // 2026-10-14 (block 16377651); isShhhVerifierDeclared() checks other networks.\n STARK_SNIP12: \"0x017884125977631bee198b34cd3e3fcf975a543e453c8b996a818910a964b5e\",\n P256: \"0x01b600709af54c8838e5f18ddad3a26feeb47cb124c239f55a0f1b7a780e2d8a\",\n WEBAUTHN_P256: \"0x074f6efd2af9025cd8cab41a4565bc73b6ef097214c31352838fcdbac0a44657\",\n JWT_ES256: \"0x002efce875fa3e73e04d825d8ebade53e188cc995dfe0c55a6a2f7fa6c59f497\",\n JWT_ES256_APPLE_SUB: \"0x06b67762218a25fdd28e25b063480893a5cef9cdeecbc663e32d444d5734c471\",\n BLS12_381: \"0x02623721e74a9ad3e0ba639065f5631a09bf900913de6ab21ea6984973cd2cd1\",\n};\n\n/**\n * Upper-bound l2_gas overhead per SHHH signer kind, in addition to base\n * paymaster execution cost. Numbers from snforge runs at tag v8.4\n * (252-byte calls, single owner, no session key). Paymaster adds ~5M safety\n * margin on top.\n *\n * Threshold envelopes: sum the per-owner cost + ~3M aggregation overhead.\n * Session-key envelopes (SNIP-163 4-felt): ~2M + session-policy enforcement.\n */\nexport const SHHH_KIND_GAS_OVERHEAD: Record<ShhhSignerKind, number> = {\n STARK: 2_000_000,\n SECP256K1: 5_000_000,\n EIP191_SECP256K1: 10_000_000,\n EIP712_SECP256K1: 12_000_000,\n STARK_SNIP12: 2_500_000,\n P256: 30_000_000,\n ED25519: 33_000_000,\n WEBAUTHN_P256: 35_000_000,\n JWT_ES256: 60_000_000,\n JWT_ES256_APPLE_SUB: 62_000_000,\n BLS12_381: 80_000_000,\n};\n\n/**\n * Inner-envelope routing tags per the V8.4 Pluggable-Signer SNIP draft.\n * The ShhhAccount strips the version tag and library_calls the verifier;\n * Chipi paymaster does NOT need to parse the inner payload but DOES need\n * to pass the entire signature span verbatim to `execute_from_outside_v2`.\n */\nexport const SHHH_ENVELOPE_TAGS = {\n V2_SNIP12: \"V2_SNIP12\",\n V2_THRESHOLD: \"V2_THRESHOLD\",\n // Session-key envelopes are the SNIP-163 4-felt format (no version tag prefix).\n} as const;\n\n/**\n * Determine wallet type from an on-chain class hash.\n * - If it matches the READY hash → READY\n * - If it matches the current CHIPI hash or a legacy CHIPI hash → CHIPI\n * - If it matches the current SHHH hash or a legacy SHHH hash → SHHH\n * - Otherwise → null (unknown class hash, caller should handle accordingly)\n */\nexport function getWalletTypeFromClassHash(classHash: string): WalletType | null {\n const normalize = (h: string) => h.toLowerCase().replace(/^0x0+/, \"0x\");\n const normalized = normalize(classHash);\n\n if (normalize(WALLET_CLASS_HASHES.READY) === normalized) {\n return \"READY\";\n }\n if (normalize(WALLET_CLASS_HASHES.CHIPI) === normalized) {\n return \"CHIPI\";\n }\n if (LEGACY_CHIPI_CLASS_HASHES.some((h) => normalize(h) === normalized)) {\n return \"CHIPI\";\n }\n if (normalize(WALLET_CLASS_HASHES.SHHH) === normalized) {\n return \"SHHH\";\n }\n if (LEGACY_SHHH_CLASS_HASHES.some((h) => normalize(h) === normalized)) {\n return \"SHHH\";\n }\n // Unknown class hash — return null so callers can handle explicitly\n return null;\n}\n\n/**\n * Returns true if a class hash is a registered SHHH ShhhAccount class\n * (current or legacy) OR one of the 10 V8.4 verifier classes. Used by the\n * backend to reject unknown class hashes when an integrator opts into SHHH\n * via `walletType: \"SHHH\"` (D4 safety net — open SDK option, no per-org gate).\n */\nexport function isKnownShhhClassHash(classHash: string): boolean {\n const normalize = (h: string) => h.toLowerCase().replace(/^0x0+/, \"0x\");\n const normalized = normalize(classHash);\n\n if (normalize(WALLET_CLASS_HASHES.SHHH) === normalized) return true;\n if (LEGACY_SHHH_CLASS_HASHES.some((h) => normalize(h) === normalized)) return true;\n return Object.values(SHHH_VERIFIER_CLASS_HASHES).some((h) => normalize(h) === normalized);\n}\n\n// RPC endpoints per wallet type — any standard Starknet RPC works for all wallet types.\n// Override via STARKNET_RPC_URL env var; falls back to the default Infura endpoint.\n//\n// Deliberately still a Record<string, string> of plain URLs: it is a published API\n// consumed as URL strings in ~8 places, so widening it would be a breaking change.\n// A Starkscan endpoint cannot be represented here anyway (its key must travel in a\n// header, never in the URL). Pass these values as `buildRpcChain({ fallbackUrl })` /\n// `withRpcFallback(fn, { fallbackUrl })` to get the header-authed chain on top.\nexport const WALLET_RPC_ENDPOINTS: Record<string, string> = {\n CHIPI: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n READY: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n SHHH: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n};\n\n// Paymaster configuration\nexport const PAYMASTER_CONFIG = {\n URL: \"https://paymaster.chipipay.com\",\n} as const;\n\n// Session key configuration (CHIPI wallets only - SNIP-9 compatible)\nexport const SESSION_DEFAULTS = {\n /** Default session duration: 6 hours in seconds */\n DURATION_SECONDS: 21600,\n /** Default max calls per session */\n MAX_CALLS: 1000,\n} as const;\n\n// Session-specific error codes\nexport const SESSION_ERRORS = {\n /** Session keys only work with CHIPI wallets */\n INVALID_WALLET_TYPE_FOR_SESSION: \"INVALID_WALLET_TYPE_FOR_SESSION\",\n /** Session has expired (validUntil < now) */\n SESSION_EXPIRED: \"SESSION_EXPIRED\",\n /** Session key not registered on contract */\n SESSION_NOT_REGISTERED: \"SESSION_NOT_REGISTERED\",\n /** Session key has been revoked */\n SESSION_REVOKED: \"SESSION_REVOKED\",\n /** Session has exceeded max calls */\n SESSION_MAX_CALLS_EXCEEDED: \"SESSION_MAX_CALLS_EXCEEDED\",\n /** Entrypoint not allowed for this session */\n SESSION_ENTRYPOINT_NOT_ALLOWED: \"SESSION_ENTRYPOINT_NOT_ALLOWED\",\n /** Failed to decrypt session private key */\n SESSION_DECRYPTION_FAILED: \"SESSION_DECRYPTION_FAILED\",\n /** Failed to create session key */\n SESSION_CREATION_FAILED: \"SESSION_CREATION_FAILED\",\n /** Backend returned an invalid response shape */\n SESSION_INVALID_RESPONSE: \"SESSION_INVALID_RESPONSE\",\n /** Invalid spending policy configuration */\n INVALID_SPENDING_POLICY: \"INVALID_SPENDING_POLICY\",\n} as const;\n\n// Session contract entrypoint names\nexport const SESSION_ENTRYPOINTS = {\n /** Add or update a session key (owner only) */\n ADD_OR_UPDATE: \"add_or_update_session_key\",\n /** Revoke a session key (owner only) */\n REVOKE: \"revoke_session_key\",\n /** Query session data (public read) */\n GET_DATA: \"get_session_data\",\n /** Set a spending policy for a session key + token pair (owner only) */\n SET_SPENDING_POLICY: \"set_spending_policy\",\n /** Query a spending policy (public read) */\n GET_SPENDING_POLICY: \"get_spending_policy\",\n /** Remove a spending policy (owner only) */\n REMOVE_SPENDING_POLICY: \"remove_spending_policy\",\n} as const;\n"]}
|
package/dist/constants/index.mjs
CHANGED
|
@@ -244,8 +244,10 @@ var WALLET_CLASS_HASHES = {
|
|
|
244
244
|
CHIPI: "0x053f4f8791ed5bed0fddaa553d180c664e32cfaf8316bb232ae77bb08f459f2a",
|
|
245
245
|
// v29 — must match backend until coordinated v33 upgrade
|
|
246
246
|
READY: "0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f",
|
|
247
|
-
|
|
248
|
-
// V8.4
|
|
247
|
+
// V8.5 ShhhAccount — declared 2026-10-14. The single-owner envelope must
|
|
248
|
+
// carry the threshold (V8.4 ignored it). Needs chipi-back with
|
|
249
|
+
// OPT_IN_SHHH_CLASS_HASHES: createWallet names this class explicitly.
|
|
250
|
+
SHHH: "0x067828c8b82ac723b4adb141f9aa8975e296d8c11179d22bb8d7203b32abd96a"
|
|
249
251
|
};
|
|
250
252
|
var LEGACY_CHIPI_CLASS_HASHES = [
|
|
251
253
|
"0x0484bbd2404b3c7264bea271f7267d6d4004821ac7787a9eed7f472e79ef40d1",
|
|
@@ -260,6 +262,8 @@ var LEGACY_CHIPI_CLASS_HASHES = [
|
|
|
260
262
|
// v28
|
|
261
263
|
];
|
|
262
264
|
var LEGACY_SHHH_CLASS_HASHES = [
|
|
265
|
+
"0x075dfb396145926bffa6beb659897f46cc082a50b211d80871cff7f1038fa58a",
|
|
266
|
+
// V8.4 — deprecated 2026-10-14, single-owner path ignores the threshold (safe at threshold 1)
|
|
263
267
|
"0x03bc539295abd3e59bd9ea799d12fe3331748d484bc77bff45b302b1636a87d9"
|
|
264
268
|
// V8.3 — deprecated 2026-05-15, no stranded-bootstrap recovery
|
|
265
269
|
];
|
|
@@ -269,6 +273,11 @@ var SHHH_VERIFIER_CLASS_HASHES = {
|
|
|
269
273
|
SECP256K1: "0x03e81667a46bd5287e09a9600fa98d28fdc477735f2689f5f4e8e95f37b67b74",
|
|
270
274
|
EIP191_SECP256K1: "0x03a75997862059c36cb8e204fb3027eb6d1fdf933488d42c2db4528118d084e6",
|
|
271
275
|
EIP712_SECP256K1: "0x072a3f77e8c28bfea2ade91ec3fb83b6290169d1ed8c1b2396704231841c6474",
|
|
276
|
+
// Starknet browser wallets (Bramble, Braavos, Ready/Argent, OZ) via
|
|
277
|
+
// wallet_signTypedData. Built from shhh-wallet-cairo PR #23 with Scarb 2.14.0
|
|
278
|
+
// (same toolchain that reproduces every hash above). Declared on mainnet
|
|
279
|
+
// 2026-10-14 (block 16377651); isShhhVerifierDeclared() checks other networks.
|
|
280
|
+
STARK_SNIP12: "0x017884125977631bee198b34cd3e3fcf975a543e453c8b996a818910a964b5e",
|
|
272
281
|
P256: "0x01b600709af54c8838e5f18ddad3a26feeb47cb124c239f55a0f1b7a780e2d8a",
|
|
273
282
|
WEBAUTHN_P256: "0x074f6efd2af9025cd8cab41a4565bc73b6ef097214c31352838fcdbac0a44657",
|
|
274
283
|
JWT_ES256: "0x002efce875fa3e73e04d825d8ebade53e188cc995dfe0c55a6a2f7fa6c59f497",
|
|
@@ -280,6 +289,7 @@ var SHHH_KIND_GAS_OVERHEAD = {
|
|
|
280
289
|
SECP256K1: 5e6,
|
|
281
290
|
EIP191_SECP256K1: 1e7,
|
|
282
291
|
EIP712_SECP256K1: 12e6,
|
|
292
|
+
STARK_SNIP12: 25e5,
|
|
283
293
|
P256: 3e7,
|
|
284
294
|
ED25519: 33e6,
|
|
285
295
|
WEBAUTHN_P256: 35e6,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/constants/rpc.ts","../../src/constants/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Ordered Starknet RPC provider chain with transport-level failover.\n *\n * ## Published-SDK contract (read before changing anything here)\n *\n * `@chipi-stack/*` is consumed by external integrators who do NOT have Chipi's\n * Starkscan API key. The keyless path must keep working with zero configuration,\n * so Starkscan is layered on top rather than baked in:\n *\n * - `STARKSCAN_API_KEY` set (Chipi's own server-side deployments) → Starkscan is\n * the primary endpoint, key travelling in a header.\n * - `STARKSCAN_API_KEY` unset (every integrator) → the chain HEAD is byte-identical\n * to the endpoint the SDK resolved before this module existed\n * (`STARKNET_RPC_URL` when set, else the default Infura mainnet URL). The only\n * difference is that the SDK now retries on additional nodes instead of failing.\n *\n * Starkscan is MAINNET-ONLY (`SN_SEPOLIA` answers `unsupported_chain`), so a\n * non-mainnet configuration never gets it (and never gets mainnet fallbacks\n * either; see `buildRpcChain`).\n *\n * The custom `baseFetch` transport classifier is installed ONLY on providers this module\n * builds for the chain. A provider an integrator constructs themselves from\n * `WALLET_RPC_ENDPOINTS` / `STARKNET_NETWORKS` keeps stock starknet.js behaviour, so the\n * blast radius of coupling to starknet.js internals is limited to the chain helper.\n */\nimport { RpcProvider } from \"starknet\";\n\n/**\n * Starkscan's JSON-RPC route. Mainnet only. The key rides in the canonical\n * `X-Starkscan-Api-Key` header, never in the URL.\n */\nexport const STARKSCAN_MAINNET_RPC = \"https://api.starkscan.co/v1/SN_MAIN/rpc\";\n\n/** Public keyless mainnet node used as the last resort in the chain. */\n/** Dead since 2026-09: HTTP 410 \"This endpoint has been discontinued\". Kept only\n * so an integrator pinning it via env still resolves; never pushed into the chain. */\nexport const LAVA_MAINNET_RPC = \"https://rpc.starknet.lava.build\";\n/** Keyless public fallback (Cartridge). Replaces Lava as the chain's last resort. */\nexport const CARTRIDGE_MAINNET_RPC = \"https://api.cartridge.gg/x/starknet/mainnet\";\n\n/** Keyless default mainnet RPC. This is the value published SDKs resolve to today. Do not change. */\nexport const DEFAULT_MAINNET_RPC =\n \"https://starknet-mainnet.infura.io/v3/4a4a1fdd7d704509aa99154fb29886e2\";\n\n/** Keyless default sepolia RPC. Starkscan is never layered onto this. */\nexport const DEFAULT_SEPOLIA_RPC =\n \"https://starknet-sepolia.infura.io/v3/4a4a1fdd7d704509aa99154fb29886e2\";\n\nexport type RpcEndpoint = { label: string; url: string; headers?: Record<string, string> };\n\n/**\n * Read an env var defensively: this module is bundled into browser-facing packages\n * where `process` may not exist. Empty / whitespace-only values are treated as unset.\n */\nexport function readEnv(name: string): string | undefined {\n if (typeof process === \"undefined\" || !process.env) return undefined;\n const value = process.env[name];\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Anything that is clearly not Starknet mainnet. A non-mainnet head must never be\n * followed by mainnet fallbacks (answering a sepolia question with mainnet state is\n * worse than failing), so such a chain stays single-entry.\n */\nfunction looksNonMainnet(url: string): boolean {\n return /sepolia|goerli|testnet|devnet|localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0/i.test(url);\n}\n\n/**\n * Build the ordered endpoint chain.\n *\n * @param opts.fallbackUrl the URL this call site resolved on its own (e.g.\n * `WALLET_RPC_ENDPOINTS[walletType]` or an integrator-supplied `nodeUrl`). It is the\n * first KEYLESS entry, which is what keeps the no-Starkscan behaviour byte-identical\n * to today.\n *\n * Order: starkscan (only with a key) → caller URL → `STARKNET_RPC_URL` → Infura default\n * → cartridge. De-duplicated by URL so an operator who pins `STARKNET_RPC_URL` there does\n * not get the same node twice (which would make \"fallback\" a no-op).\n */\nexport function buildRpcChain(opts?: { fallbackUrl?: string }): RpcEndpoint[] {\n const callerUrl = opts?.fallbackUrl?.trim() || undefined;\n const envUrl = readEnv(\"STARKNET_RPC_URL\");\n\n // The endpoint this call site would have used before this module existed.\n const head = callerUrl ?? envUrl ?? DEFAULT_MAINNET_RPC;\n\n // Non-mainnet deployments keep exactly one endpoint: no Starkscan (it rejects\n // SN_SEPOLIA with `unsupported_chain`) and no cross-chain fallback.\n if (looksNonMainnet(head)) {\n return [{ label: \"configured\", url: head }];\n }\n\n const chain: RpcEndpoint[] = [];\n const seen = new Set<string>();\n\n const push = (label: string, url: string | undefined, headers?: Record<string, string>) => {\n if (!url) return;\n const nodeUrl = url.trim();\n if (!nodeUrl) return;\n const key = nodeUrl.replace(/\\/+$/, \"\").toLowerCase();\n if (seen.has(key)) return;\n seen.add(key);\n chain.push(headers ? { label, url: nodeUrl, headers } : { label, url: nodeUrl });\n };\n\n // Server-only key. Never logged, never interpolated into a URL, never shipped in a\n // browser bundle's env. Absent (every external integrator) → chain is unchanged.\n const starkscanApiKey = readEnv(\"STARKSCAN_API_KEY\");\n if (starkscanApiKey) {\n push(\"starkscan\", STARKSCAN_MAINNET_RPC, { \"X-Starkscan-Api-Key\": starkscanApiKey });\n }\n\n push(\"caller\", callerUrl);\n push(\"env\", envUrl);\n push(\"default\", DEFAULT_MAINNET_RPC);\n push(\"cartridge\", CARTRIDGE_MAINNET_RPC);\n\n return chain;\n}\n\n/**\n * Marker on transport-class failures we raise ourselves. starknet.js re-wraps thrown\n * fetch errors as a plain `Error(message)`, so the error *instance* does not survive the\n * round trip. Only the message text does.\n */\nconst TRANSPORT_MARKER = \"[chipi-rpc-transport]\";\n\n/**\n * HTTP statuses that mean \"this endpoint did not answer\" rather than \"the chain says no\":\n * 429/5xx (rate limited / node broken) plus 401/403/404, which is what a missing, wrong,\n * rotated or unprovisioned API key looks like. Falling through is exactly right there.\n */\nfunction isTransportStatus(status: number): boolean {\n return (\n status === 401 ||\n status === 403 ||\n status === 404 ||\n status === 410 || // Gone: a discontinued endpoint (Lava, 2026-09) is transport, not chain truth\n status === 429 ||\n status >= 500\n );\n}\n\n/** Per-request budget for one RPC round-trip before we call it a transport failure. */\nconst RPC_TIMEOUT_MS = 15_000;\n\n/**\n * Wraps global fetch so an HTTP-level failure is classified while the status code is\n * still visible.\n *\n * This is necessary because **starknet.js never inspects the HTTP status**:\n * `RpcChannel.fetchEndpoint` goes straight to `.json()`. Without this wrapper a rate-limit\n * page or an auth rejection surfaces either as an opaque JSON parse error or, when the body\n * happens to be valid JSON, as a silent `undefined` result.\n *\n * Scope note (published SDK): this wrapper is installed ONLY on providers built by\n * `rpcProviderFor` for the fallback chain. Providers an integrator constructs themselves\n * from `WALLET_RPC_ENDPOINTS` / `STARKNET_NETWORKS` keep stock starknet.js fetch behaviour.\n */\nexport function makeRpcBaseFetch(label: string): typeof fetch {\n return async (input, init) => {\n let response: Response;\n try {\n response = await fetch(input, {\n ...init,\n // RN and older runtimes may not have AbortSignal.timeout. Only use it when present.\n signal:\n init?.signal ??\n (typeof AbortSignal !== \"undefined\" && typeof AbortSignal.timeout === \"function\"\n ? AbortSignal.timeout(RPC_TIMEOUT_MS)\n : undefined),\n });\n } catch (err) {\n // Network unreachable, DNS failure, connection reset, timeout/abort.\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(`${TRANSPORT_MARKER} endpoint \"${label}\" fetch failed: ${detail}`);\n }\n\n if (response.ok) return response;\n\n // Non-2xx. A node that actually answered still returns a JSON-RPC envelope; anything\n // else (rate-limit page, REST-shaped auth rejection, gateway error) is a transport failure.\n const body = await response.text();\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n parsed = undefined;\n }\n // A real envelope, not merely \"some JSON with an error field\". Lava's\n // discontinuation notice ({\"error\":\"This endpoint has been discontinued.\"},\n // HTTP 410) passed an `\"error\" in parsed` test, was re-served as a 200, and\n // starknet.js turned it into an RpcError with undefined fields that the\n // fallback honoured as chain truth, stranding the chain behind a dead\n // endpoint (2026-09-07 chipi-back prod balance outage). A node that\n // actually answered wraps its error in an OBJECT with a numeric `code`;\n // a string `error` is a REST body: the endpoint did not answer.\n const isJsonRpcEnvelope =\n !!parsed &&\n typeof parsed === \"object\" &&\n (\"result\" in parsed ||\n (typeof (parsed as { error?: unknown }).error === \"object\" &&\n (parsed as { error?: unknown }).error !== null &&\n typeof (parsed as { error: { code?: unknown } }).error.code === \"number\"));\n\n if (isJsonRpcEnvelope && !isTransportStatus(response.status)) {\n // A well-formed JSON-RPC error that merely arrived over a non-200 status. Hand it back\n // so starknet.js raises a proper RpcError instead of a parse error, and so the chain\n // does NOT burn other endpoints on a question they would all answer identically.\n return new Response(body, { status: 200, headers: { \"content-type\": \"application/json\" } });\n }\n\n // Label only: never the URL (query params) and never the headers (API key).\n throw new Error(`${TRANSPORT_MARKER} endpoint \"${label}\" returned HTTP ${response.status}`);\n };\n}\n\nconst TRANSPORT_MESSAGE_HINTS = [\n TRANSPORT_MARKER,\n // network / socket\n \"fetch failed\",\n \"failed to fetch\",\n \"network error\",\n \"networkerror\",\n \"socket hang up\",\n \"econnreset\",\n \"econnrefused\",\n \"econnaborted\",\n \"enotfound\",\n \"etimedout\",\n \"ehostunreach\",\n \"enetunreach\",\n \"epipe\",\n // timeouts / cancellation\n \"timeout\",\n \"timed out\",\n \"aborted\",\n // JSON parse failure: an error page or truncated body instead of a JSON-RPC envelope\n \"unexpected token\",\n \"unexpected end of json\",\n \"is not valid json\",\n \"invalid json\",\n \"json parse\",\n];\n\n/**\n * True only for transport-class failures (network/fetch error, timeout, HTTP 401/403/404/\n * 429/5xx, JSON parse failure).\n *\n * A well-formed JSON-RPC error (\"Contract not found\", \"Invalid params\") means the node\n * answered correctly: it is NOT a transport failure, so the caller rethrows immediately\n * instead of burning the rest of the chain on a question every node answers the same way.\n */\n/**\n * Starkscan's gateway code for \"this credential cannot do this here\" (missing RPC scope, rate\n * cap). Live 2026-08-15 as HTTP 403 + `{error:{code:-32012}}`, and also observed on HTTP 200.\n */\nconst STARKSCAN_GATEWAY_REFUSAL = -32012;\n\n/** Reads a JSON-RPC error code off whatever shape starknet.js hands us, or undefined. */\nfunction jsonRpcErrorCode(err: unknown): number | undefined {\n const e = err as { code?: unknown; baseError?: { code?: unknown } } | null | undefined;\n const raw = e?.baseError?.code ?? e?.code;\n return typeof raw === \"number\" ? raw : undefined;\n}\n\nfunction isTransportFailure(err: unknown): boolean {\n if (!err) return false;\n\n const e = err as {\n name?: string;\n message?: string;\n baseError?: unknown;\n status?: number;\n statusCode?: number;\n cause?: unknown;\n };\n\n // Starkscan's gateway signals a per-endpoint refusal (missing key scope, rate cap) with\n // this code, sometimes on an HTTP 200. Neither is chain truth, so it must fail over even\n // though it arrives as a well-formed JSON-RPC error. Auth is a property of OUR credential\n // at THIS endpoint, never of the chain.\n if (jsonRpcErrorCode(err) === STARKSCAN_GATEWAY_REFUSAL) return true;\n\n // starknet.js RpcError: the node replied with a JSON-RPC error envelope. Duck-typed\n // rather than `instanceof` so unit tests that mock the starknet module still take this path.\n if (e.name === \"RpcError\" || e.baseError !== undefined) return false;\n\n const status = typeof e.status === \"number\" ? e.status : e.statusCode;\n if (typeof status === \"number\" && isTransportStatus(status)) return true;\n\n if (e.name === \"AbortError\" || e.name === \"TimeoutError\" || e.name === \"SyntaxError\") return true;\n\n const message = typeof e.message === \"string\" ? e.message.toLowerCase() : \"\";\n if (message && TRANSPORT_MESSAGE_HINTS.some((hint) => message.includes(hint))) return true;\n\n // Node's fetch wraps the underlying socket error in `cause`.\n if (e.cause && e.cause !== err) return isTransportFailure(e.cause);\n\n return false;\n}\n\nconst providerCache = new Map<string, RpcProvider>();\n\n/** Memoized provider for one endpoint. */\nexport function rpcProviderFor(endpoint: RpcEndpoint): RpcProvider {\n const cacheKey = `${endpoint.label}|${endpoint.url}|${endpoint.headers ? \"auth\" : \"anon\"}`;\n const cached = providerCache.get(cacheKey);\n if (cached) return cached;\n\n const provider = new RpcProvider({\n nodeUrl: endpoint.url,\n baseFetch: makeRpcBaseFetch(endpoint.label),\n ...(endpoint.headers ? { headers: endpoint.headers } : {}),\n });\n providerCache.set(cacheKey, provider);\n return provider;\n}\n\n/**\n * Run a read against the endpoint chain, advancing to the next endpoint only when the\n * current one fails at transport level.\n *\n * Use for reads and for confirmation polling (both idempotent). Do NOT use it to wrap a\n * transaction submission: a retry on a different node could double-submit.\n */\nexport async function withRpcFallback<T>(\n fn: (provider: RpcProvider) => Promise<T>,\n opts?: { fallbackUrl?: string }\n): Promise<T> {\n const chain = buildRpcChain(opts);\n if (chain.length === 0) {\n // Defensive: buildRpcChain always appends a keyless endpoint, so this is unreachable.\n throw new Error(\"No Starknet RPC endpoint configured\");\n }\n\n let lastError: unknown;\n\n for (let i = 0; i < chain.length; i++) {\n const endpoint = chain[i];\n const isLast = i === chain.length - 1;\n\n try {\n const result = await fn(rpcProviderFor(endpoint));\n\n // An empty result is a transport failure in disguise, NOT a valid answer.\n // Starkscan rejects a bad/missing/expired API key with HTTP 401 carrying a\n // REST-shaped body (`{\"code\":\"unauthorized\",\"message\":\"Unauthorized\",...}`)\n // instead of a JSON-RPC error object. starknet.js cannot parse that: on both\n // 9.2.1 and 9.4.2, `getBlockNumber()` / `callContract()` resolve to `undefined`\n // and DO NOT THROW. Without this guard a wrong key would silently return\n // `undefined` from every SDK read with no error at all. Discriminate on\n // `undefined`/`null` ONLY: `0`, `\"0x0\"`, `false` and `[]` are legitimate\n // results (a balance read legitimately returns `[\"0x0\",\"0x0\"]`).\n if (result === undefined || result === null) {\n if (isLast) {\n throw new Error(\n `Starknet RPC endpoint \"${endpoint.label}\" returned an empty response ` +\n `(no JSON-RPC result). If this endpoint requires an API key, the key is ` +\n `likely missing, wrong or expired.`\n );\n }\n lastError = new Error(\n `${TRANSPORT_MARKER} endpoint \"${endpoint.label}\" returned an empty response`\n );\n continue;\n }\n\n return result;\n } catch (error) {\n if (isLast || !isTransportFailure(error)) throw error;\n lastError = error;\n // Label only: never the endpoint URL, headers or the API key.\n console.warn(\n `[chipi:rpc] transport failure on \"${endpoint.label}\" (${i + 1}/${chain.length}), falling through`\n );\n }\n }\n\n throw lastError instanceof Error\n ? lastError\n : new Error(`All Starknet RPC endpoints failed: ${String(lastError)}`);\n}\n","/**\n * Constants used across Chipi SDK packages\n */\n\nimport type { ShhhSignerKind, WalletType } from \"@chipi-stack/types\";\nimport { CARTRIDGE_MAINNET_RPC, DEFAULT_MAINNET_RPC, DEFAULT_SEPOLIA_RPC, readEnv } from \"./rpc\";\n\n// Ordered RPC chain + transport-level failover (Starkscan is primary only when\n// STARKSCAN_API_KEY is set; keyless integrators keep today's endpoint).\nexport * from \"./rpc\";\n\n/**\n * API Versioning\n * - VERSION: Major version for path-based versioning (/v1, /v2, etc.)\n * - VERSION_DATE: Detailed version for tracking breaking changes (YYYY-MM-DD format)\n *\n * Update VERSION_DATE when making API changes.\n * Update VERSION when making major breaking changes (typically 1-2 times per year).\n */\nexport const API_VERSIONING = {\n VERSION: \"1\", // Major version - used in URL path\n VERSION_DATE: \"2025-12-30\", // Detailed version - sent as query param for tracking\n} as const;\n\n// Default RPC URLs — override via STARKNET_RPC_URL / STARKNET_RPC_URL_SEPOLIA env vars.\n// The URL literals now live in ./rpc.ts alongside the failover chain that uses them;\n// the resolved values here are unchanged.\n\n// These evaluate at MODULE SCOPE, and this module is bundled into browser-facing\n// packages, so a bare `process.env` read throws at import time anywhere `process`\n// is not defined. It has worked so far only because bundlers inject a shim, which\n// makes client-side imports of this package accidental rather than supported.\n// `readEnv` is the same guard ./rpc.ts already uses; server behaviour is identical.\nexport const STARKNET_NETWORKS = {\n MAINNET: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n // Last resort of the mainnet chain built by buildRpcChain(), no longer a dead constant.\n MAINNET_FALLBACK: CARTRIDGE_MAINNET_RPC,\n SEPOLIA: readEnv(\"STARKNET_RPC_URL_SEPOLIA\") ?? DEFAULT_SEPOLIA_RPC,\n} as const;\n\nexport const CONTRACT_ADDRESSES = {\n USDC_MAINNET: \"0x033068F6539f8e6e6b131e6B2B814e6c34A5224bC66947c47DaB9dFeE93b35fb\", // Changed to Native USDC (was bridged USDC.e)\n VESU_USDC_MAINNET: \"0x017f19582c61479f2fe0b6606300e975c0a8f439102f43eeecc1d0e9b3d84350\",\n} as const;\n\nexport const TOKEN_DECIMALS = {\n USDC: 6,\n USDT: 6,\n ETH: 18,\n STRK: 18,\n DAI: 18,\n} as const;\n\nexport const API_ENDPOINTS = {\n CHIPI_WALLETS: \"/chipi-wallets\",\n TRANSACTIONS: \"/transactions\",\n SKUS: \"/skus\",\n SKU_PURCHASES: \"/sku-purchases\",\n EXCHANGES: \"/exchanges\",\n USERS: \"/users\",\n // SHHH multisig coordination (Plus Wave 9 / P1): SDK-exposed treasury\n // propose / sign / execute / list, owner-signature-authed.\n TREASURIES: \"/treasuries\",\n} as const;\n\nexport const ERRORS = {\n INVALID_API_KEY: \"INVALID_API_KEY\",\n WALLET_NOT_FOUND: \"WALLET_NOT_FOUND\",\n INSUFFICIENT_BALANCE: \"INSUFFICIENT_BALANCE\",\n TRANSACTION_FAILED: \"TRANSACTION_FAILED\",\n INVALID_SIGNATURE: \"INVALID_SIGNATURE\",\n SKU_NOT_FOUND: \"SKU_NOT_FOUND\",\n SKU_UNAVAILABLE: \"SKU_UNAVAILABLE\",\n} as const;\n\nexport const SKU_CONTRACTS = {\n RECHARGER_WITH_STRK_MAINNET: \"0x02d65bb726d2c29e3c97669cf297c5145eac19284fb6f935c05c0bfc68dae2b7\", //changed contract address used to be 0x0f3\n CHIPI_BILL_SERVICE: \"0x4e8150110d580069de26adec9b179023289d55859ea07487aaade5458d7aa8b\",\n} as const;\n\n// Service types\nexport const SERVICE_TYPES = {\n BUY_SERVICE: \"BUY_SERVICE\",\n} as const;\n\n// Carrier IDs\nexport const CARRIER_IDS = {\n CHIPI_PAY: \"chipi_pay\",\n} as const;\n\nexport const CHAIN_TYPES = {\n STARKNET: \"STARKNET\",\n} as const;\n\nexport const CHAIN_TOKEN_TYPES = {\n USDC: \"USDC\", // Changed to Native USDC (was bridged USDC.e)\n USDT: \"USDT\",\n ETH: \"ETH\",\n STRK: \"STRK\",\n DAI: \"DAI\",\n WBTC: \"WBTC\",\n OTHER: \"OTHER\",\n} as const;\n\nexport const WALLET_CLASS_HASHES: Record<string, string> = {\n CHIPI: \"0x053f4f8791ed5bed0fddaa553d180c664e32cfaf8316bb232ae77bb08f459f2a\", // v29 — must match backend until coordinated v33 upgrade\n READY: \"0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f\",\n SHHH: \"0x075dfb396145926bffa6beb659897f46cc082a50b211d80871cff7f1038fa58a\", // V8.4 ShhhAccount — declared 2026-05-15, audit-closed\n};\n\n/**\n * Previous CHIPI wallet class hashes that are still deployed on-chain.\n * Used by getWalletTypeFromClassHash() to identify legacy wallets.\n * Ordered newest → oldest.\n */\nexport const LEGACY_CHIPI_CLASS_HASHES: string[] = [\n \"0x0484bbd2404b3c7264bea271f7267d6d4004821ac7787a9eed7f472e79ef40d1\", // v33 — wallets created during brief v33 window\n \"0x035a2251aca25daba18a5d8950deffa8372a7d84774554e75283cb85552eebc9\", // v32 — audit 3\n \"0x0254f6dd0427319ec614c29e4e3929500d1ba95d0da87ff81d67051ce572667\", // v31\n \"0x072b77b033a874fa1b8f7ff52e18be8fb5ce01a00c59cd184ae15f5b29bc0e57\", // v30\n \"0x02de1565226d5215a38b68c4d9a4913989b54edff64c68c45e453c417b44cd83\", // v28\n];\n\n/**\n * Deprecated SHHH class hashes that may exist on-chain but must NOT be routed\n * for new deploys. V8 series ships without an `upgrade` selector, so existing\n * instances at deprecated classes cannot self-upgrade — they redeploy at the\n * current SHHH class hash.\n */\nexport const LEGACY_SHHH_CLASS_HASHES: string[] = [\n \"0x03bc539295abd3e59bd9ea799d12fe3331748d484bc77bff45b302b1636a87d9\", // V8.3 — deprecated 2026-05-15, no stranded-bootstrap recovery\n];\n\n/**\n * SHHH ShhhAccount verifier class hashes (V8.4, mainnet).\n *\n * The ShhhAccount dispatches `verify` to one of these verifier classes via\n * `library_call_syscall` based on the owner's `kind_tag`. Verifier classes are\n * pinned to deterministic outputs of `scarb build` at commit `3975532` (tag\n * v8.4) — Chipi routes to these hashes as a consumer; we do not redeclare.\n */\nexport const SHHH_VERIFIER_CLASS_HASHES: Record<ShhhSignerKind, string> = {\n STARK: \"0x00d09209b2da9d49fc805ba26380ba4ce25aa641116c10eb178e1051a71dbf68\",\n ED25519: \"0x030a7dfc03e59cef6e41699e734abd2df53ce393a052221c02c6e07665949f74\",\n SECP256K1: \"0x03e81667a46bd5287e09a9600fa98d28fdc477735f2689f5f4e8e95f37b67b74\",\n EIP191_SECP256K1: \"0x03a75997862059c36cb8e204fb3027eb6d1fdf933488d42c2db4528118d084e6\",\n EIP712_SECP256K1: \"0x072a3f77e8c28bfea2ade91ec3fb83b6290169d1ed8c1b2396704231841c6474\",\n P256: \"0x01b600709af54c8838e5f18ddad3a26feeb47cb124c239f55a0f1b7a780e2d8a\",\n WEBAUTHN_P256: \"0x074f6efd2af9025cd8cab41a4565bc73b6ef097214c31352838fcdbac0a44657\",\n JWT_ES256: \"0x002efce875fa3e73e04d825d8ebade53e188cc995dfe0c55a6a2f7fa6c59f497\",\n JWT_ES256_APPLE_SUB: \"0x06b67762218a25fdd28e25b063480893a5cef9cdeecbc663e32d444d5734c471\",\n BLS12_381: \"0x02623721e74a9ad3e0ba639065f5631a09bf900913de6ab21ea6984973cd2cd1\",\n};\n\n/**\n * Upper-bound l2_gas overhead per SHHH signer kind, in addition to base\n * paymaster execution cost. Numbers from snforge runs at tag v8.4\n * (252-byte calls, single owner, no session key). Paymaster adds ~5M safety\n * margin on top.\n *\n * Threshold envelopes: sum the per-owner cost + ~3M aggregation overhead.\n * Session-key envelopes (SNIP-163 4-felt): ~2M + session-policy enforcement.\n */\nexport const SHHH_KIND_GAS_OVERHEAD: Record<ShhhSignerKind, number> = {\n STARK: 2_000_000,\n SECP256K1: 5_000_000,\n EIP191_SECP256K1: 10_000_000,\n EIP712_SECP256K1: 12_000_000,\n P256: 30_000_000,\n ED25519: 33_000_000,\n WEBAUTHN_P256: 35_000_000,\n JWT_ES256: 60_000_000,\n JWT_ES256_APPLE_SUB: 62_000_000,\n BLS12_381: 80_000_000,\n};\n\n/**\n * Inner-envelope routing tags per the V8.4 Pluggable-Signer SNIP draft.\n * The ShhhAccount strips the version tag and library_calls the verifier;\n * Chipi paymaster does NOT need to parse the inner payload but DOES need\n * to pass the entire signature span verbatim to `execute_from_outside_v2`.\n */\nexport const SHHH_ENVELOPE_TAGS = {\n V2_SNIP12: \"V2_SNIP12\",\n V2_THRESHOLD: \"V2_THRESHOLD\",\n // Session-key envelopes are the SNIP-163 4-felt format (no version tag prefix).\n} as const;\n\n/**\n * Determine wallet type from an on-chain class hash.\n * - If it matches the READY hash → READY\n * - If it matches the current CHIPI hash or a legacy CHIPI hash → CHIPI\n * - If it matches the current SHHH hash or a legacy SHHH hash → SHHH\n * - Otherwise → null (unknown class hash, caller should handle accordingly)\n */\nexport function getWalletTypeFromClassHash(classHash: string): WalletType | null {\n const normalize = (h: string) => h.toLowerCase().replace(/^0x0+/, \"0x\");\n const normalized = normalize(classHash);\n\n if (normalize(WALLET_CLASS_HASHES.READY) === normalized) {\n return \"READY\";\n }\n if (normalize(WALLET_CLASS_HASHES.CHIPI) === normalized) {\n return \"CHIPI\";\n }\n if (LEGACY_CHIPI_CLASS_HASHES.some((h) => normalize(h) === normalized)) {\n return \"CHIPI\";\n }\n if (normalize(WALLET_CLASS_HASHES.SHHH) === normalized) {\n return \"SHHH\";\n }\n if (LEGACY_SHHH_CLASS_HASHES.some((h) => normalize(h) === normalized)) {\n return \"SHHH\";\n }\n // Unknown class hash — return null so callers can handle explicitly\n return null;\n}\n\n/**\n * Returns true if a class hash is a registered SHHH ShhhAccount class\n * (current or legacy) OR one of the 10 V8.4 verifier classes. Used by the\n * backend to reject unknown class hashes when an integrator opts into SHHH\n * via `walletType: \"SHHH\"` (D4 safety net — open SDK option, no per-org gate).\n */\nexport function isKnownShhhClassHash(classHash: string): boolean {\n const normalize = (h: string) => h.toLowerCase().replace(/^0x0+/, \"0x\");\n const normalized = normalize(classHash);\n\n if (normalize(WALLET_CLASS_HASHES.SHHH) === normalized) return true;\n if (LEGACY_SHHH_CLASS_HASHES.some((h) => normalize(h) === normalized)) return true;\n return Object.values(SHHH_VERIFIER_CLASS_HASHES).some((h) => normalize(h) === normalized);\n}\n\n// RPC endpoints per wallet type — any standard Starknet RPC works for all wallet types.\n// Override via STARKNET_RPC_URL env var; falls back to the default Infura endpoint.\n//\n// Deliberately still a Record<string, string> of plain URLs: it is a published API\n// consumed as URL strings in ~8 places, so widening it would be a breaking change.\n// A Starkscan endpoint cannot be represented here anyway (its key must travel in a\n// header, never in the URL). Pass these values as `buildRpcChain({ fallbackUrl })` /\n// `withRpcFallback(fn, { fallbackUrl })` to get the header-authed chain on top.\nexport const WALLET_RPC_ENDPOINTS: Record<string, string> = {\n CHIPI: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n READY: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n SHHH: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n};\n\n// Paymaster configuration\nexport const PAYMASTER_CONFIG = {\n URL: \"https://paymaster.chipipay.com\",\n} as const;\n\n// Session key configuration (CHIPI wallets only - SNIP-9 compatible)\nexport const SESSION_DEFAULTS = {\n /** Default session duration: 6 hours in seconds */\n DURATION_SECONDS: 21600,\n /** Default max calls per session */\n MAX_CALLS: 1000,\n} as const;\n\n// Session-specific error codes\nexport const SESSION_ERRORS = {\n /** Session keys only work with CHIPI wallets */\n INVALID_WALLET_TYPE_FOR_SESSION: \"INVALID_WALLET_TYPE_FOR_SESSION\",\n /** Session has expired (validUntil < now) */\n SESSION_EXPIRED: \"SESSION_EXPIRED\",\n /** Session key not registered on contract */\n SESSION_NOT_REGISTERED: \"SESSION_NOT_REGISTERED\",\n /** Session key has been revoked */\n SESSION_REVOKED: \"SESSION_REVOKED\",\n /** Session has exceeded max calls */\n SESSION_MAX_CALLS_EXCEEDED: \"SESSION_MAX_CALLS_EXCEEDED\",\n /** Entrypoint not allowed for this session */\n SESSION_ENTRYPOINT_NOT_ALLOWED: \"SESSION_ENTRYPOINT_NOT_ALLOWED\",\n /** Failed to decrypt session private key */\n SESSION_DECRYPTION_FAILED: \"SESSION_DECRYPTION_FAILED\",\n /** Failed to create session key */\n SESSION_CREATION_FAILED: \"SESSION_CREATION_FAILED\",\n /** Backend returned an invalid response shape */\n SESSION_INVALID_RESPONSE: \"SESSION_INVALID_RESPONSE\",\n /** Invalid spending policy configuration */\n INVALID_SPENDING_POLICY: \"INVALID_SPENDING_POLICY\",\n} as const;\n\n// Session contract entrypoint names\nexport const SESSION_ENTRYPOINTS = {\n /** Add or update a session key (owner only) */\n ADD_OR_UPDATE: \"add_or_update_session_key\",\n /** Revoke a session key (owner only) */\n REVOKE: \"revoke_session_key\",\n /** Query session data (public read) */\n GET_DATA: \"get_session_data\",\n /** Set a spending policy for a session key + token pair (owner only) */\n SET_SPENDING_POLICY: \"set_spending_policy\",\n /** Query a spending policy (public read) */\n GET_SPENDING_POLICY: \"get_spending_policy\",\n /** Remove a spending policy (owner only) */\n REMOVE_SPENDING_POLICY: \"remove_spending_policy\",\n} as const;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/constants/rpc.ts","../../src/constants/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Ordered Starknet RPC provider chain with transport-level failover.\n *\n * ## Published-SDK contract (read before changing anything here)\n *\n * `@chipi-stack/*` is consumed by external integrators who do NOT have Chipi's\n * Starkscan API key. The keyless path must keep working with zero configuration,\n * so Starkscan is layered on top rather than baked in:\n *\n * - `STARKSCAN_API_KEY` set (Chipi's own server-side deployments) → Starkscan is\n * the primary endpoint, key travelling in a header.\n * - `STARKSCAN_API_KEY` unset (every integrator) → the chain HEAD is byte-identical\n * to the endpoint the SDK resolved before this module existed\n * (`STARKNET_RPC_URL` when set, else the default Infura mainnet URL). The only\n * difference is that the SDK now retries on additional nodes instead of failing.\n *\n * Starkscan is MAINNET-ONLY (`SN_SEPOLIA` answers `unsupported_chain`), so a\n * non-mainnet configuration never gets it (and never gets mainnet fallbacks\n * either; see `buildRpcChain`).\n *\n * The custom `baseFetch` transport classifier is installed ONLY on providers this module\n * builds for the chain. A provider an integrator constructs themselves from\n * `WALLET_RPC_ENDPOINTS` / `STARKNET_NETWORKS` keeps stock starknet.js behaviour, so the\n * blast radius of coupling to starknet.js internals is limited to the chain helper.\n */\nimport { RpcProvider } from \"starknet\";\n\n/**\n * Starkscan's JSON-RPC route. Mainnet only. The key rides in the canonical\n * `X-Starkscan-Api-Key` header, never in the URL.\n */\nexport const STARKSCAN_MAINNET_RPC = \"https://api.starkscan.co/v1/SN_MAIN/rpc\";\n\n/** Public keyless mainnet node used as the last resort in the chain. */\n/** Dead since 2026-09: HTTP 410 \"This endpoint has been discontinued\". Kept only\n * so an integrator pinning it via env still resolves; never pushed into the chain. */\nexport const LAVA_MAINNET_RPC = \"https://rpc.starknet.lava.build\";\n/** Keyless public fallback (Cartridge). Replaces Lava as the chain's last resort. */\nexport const CARTRIDGE_MAINNET_RPC = \"https://api.cartridge.gg/x/starknet/mainnet\";\n\n/** Keyless default mainnet RPC. This is the value published SDKs resolve to today. Do not change. */\nexport const DEFAULT_MAINNET_RPC =\n \"https://starknet-mainnet.infura.io/v3/4a4a1fdd7d704509aa99154fb29886e2\";\n\n/** Keyless default sepolia RPC. Starkscan is never layered onto this. */\nexport const DEFAULT_SEPOLIA_RPC =\n \"https://starknet-sepolia.infura.io/v3/4a4a1fdd7d704509aa99154fb29886e2\";\n\nexport type RpcEndpoint = { label: string; url: string; headers?: Record<string, string> };\n\n/**\n * Read an env var defensively: this module is bundled into browser-facing packages\n * where `process` may not exist. Empty / whitespace-only values are treated as unset.\n */\nexport function readEnv(name: string): string | undefined {\n if (typeof process === \"undefined\" || !process.env) return undefined;\n const value = process.env[name];\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Anything that is clearly not Starknet mainnet. A non-mainnet head must never be\n * followed by mainnet fallbacks (answering a sepolia question with mainnet state is\n * worse than failing), so such a chain stays single-entry.\n */\nfunction looksNonMainnet(url: string): boolean {\n return /sepolia|goerli|testnet|devnet|localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0/i.test(url);\n}\n\n/**\n * Build the ordered endpoint chain.\n *\n * @param opts.fallbackUrl the URL this call site resolved on its own (e.g.\n * `WALLET_RPC_ENDPOINTS[walletType]` or an integrator-supplied `nodeUrl`). It is the\n * first KEYLESS entry, which is what keeps the no-Starkscan behaviour byte-identical\n * to today.\n *\n * Order: starkscan (only with a key) → caller URL → `STARKNET_RPC_URL` → Infura default\n * → cartridge. De-duplicated by URL so an operator who pins `STARKNET_RPC_URL` there does\n * not get the same node twice (which would make \"fallback\" a no-op).\n */\nexport function buildRpcChain(opts?: { fallbackUrl?: string }): RpcEndpoint[] {\n const callerUrl = opts?.fallbackUrl?.trim() || undefined;\n const envUrl = readEnv(\"STARKNET_RPC_URL\");\n\n // The endpoint this call site would have used before this module existed.\n const head = callerUrl ?? envUrl ?? DEFAULT_MAINNET_RPC;\n\n // Non-mainnet deployments keep exactly one endpoint: no Starkscan (it rejects\n // SN_SEPOLIA with `unsupported_chain`) and no cross-chain fallback.\n if (looksNonMainnet(head)) {\n return [{ label: \"configured\", url: head }];\n }\n\n const chain: RpcEndpoint[] = [];\n const seen = new Set<string>();\n\n const push = (label: string, url: string | undefined, headers?: Record<string, string>) => {\n if (!url) return;\n const nodeUrl = url.trim();\n if (!nodeUrl) return;\n const key = nodeUrl.replace(/\\/+$/, \"\").toLowerCase();\n if (seen.has(key)) return;\n seen.add(key);\n chain.push(headers ? { label, url: nodeUrl, headers } : { label, url: nodeUrl });\n };\n\n // Server-only key. Never logged, never interpolated into a URL, never shipped in a\n // browser bundle's env. Absent (every external integrator) → chain is unchanged.\n const starkscanApiKey = readEnv(\"STARKSCAN_API_KEY\");\n if (starkscanApiKey) {\n push(\"starkscan\", STARKSCAN_MAINNET_RPC, { \"X-Starkscan-Api-Key\": starkscanApiKey });\n }\n\n push(\"caller\", callerUrl);\n push(\"env\", envUrl);\n push(\"default\", DEFAULT_MAINNET_RPC);\n push(\"cartridge\", CARTRIDGE_MAINNET_RPC);\n\n return chain;\n}\n\n/**\n * Marker on transport-class failures we raise ourselves. starknet.js re-wraps thrown\n * fetch errors as a plain `Error(message)`, so the error *instance* does not survive the\n * round trip. Only the message text does.\n */\nconst TRANSPORT_MARKER = \"[chipi-rpc-transport]\";\n\n/**\n * HTTP statuses that mean \"this endpoint did not answer\" rather than \"the chain says no\":\n * 429/5xx (rate limited / node broken) plus 401/403/404, which is what a missing, wrong,\n * rotated or unprovisioned API key looks like. Falling through is exactly right there.\n */\nfunction isTransportStatus(status: number): boolean {\n return (\n status === 401 ||\n status === 403 ||\n status === 404 ||\n status === 410 || // Gone: a discontinued endpoint (Lava, 2026-09) is transport, not chain truth\n status === 429 ||\n status >= 500\n );\n}\n\n/** Per-request budget for one RPC round-trip before we call it a transport failure. */\nconst RPC_TIMEOUT_MS = 15_000;\n\n/**\n * Wraps global fetch so an HTTP-level failure is classified while the status code is\n * still visible.\n *\n * This is necessary because **starknet.js never inspects the HTTP status**:\n * `RpcChannel.fetchEndpoint` goes straight to `.json()`. Without this wrapper a rate-limit\n * page or an auth rejection surfaces either as an opaque JSON parse error or, when the body\n * happens to be valid JSON, as a silent `undefined` result.\n *\n * Scope note (published SDK): this wrapper is installed ONLY on providers built by\n * `rpcProviderFor` for the fallback chain. Providers an integrator constructs themselves\n * from `WALLET_RPC_ENDPOINTS` / `STARKNET_NETWORKS` keep stock starknet.js fetch behaviour.\n */\nexport function makeRpcBaseFetch(label: string): typeof fetch {\n return async (input, init) => {\n let response: Response;\n try {\n response = await fetch(input, {\n ...init,\n // RN and older runtimes may not have AbortSignal.timeout. Only use it when present.\n signal:\n init?.signal ??\n (typeof AbortSignal !== \"undefined\" && typeof AbortSignal.timeout === \"function\"\n ? AbortSignal.timeout(RPC_TIMEOUT_MS)\n : undefined),\n });\n } catch (err) {\n // Network unreachable, DNS failure, connection reset, timeout/abort.\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(`${TRANSPORT_MARKER} endpoint \"${label}\" fetch failed: ${detail}`);\n }\n\n if (response.ok) return response;\n\n // Non-2xx. A node that actually answered still returns a JSON-RPC envelope; anything\n // else (rate-limit page, REST-shaped auth rejection, gateway error) is a transport failure.\n const body = await response.text();\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n parsed = undefined;\n }\n // A real envelope, not merely \"some JSON with an error field\". Lava's\n // discontinuation notice ({\"error\":\"This endpoint has been discontinued.\"},\n // HTTP 410) passed an `\"error\" in parsed` test, was re-served as a 200, and\n // starknet.js turned it into an RpcError with undefined fields that the\n // fallback honoured as chain truth, stranding the chain behind a dead\n // endpoint (2026-09-07 chipi-back prod balance outage). A node that\n // actually answered wraps its error in an OBJECT with a numeric `code`;\n // a string `error` is a REST body: the endpoint did not answer.\n const isJsonRpcEnvelope =\n !!parsed &&\n typeof parsed === \"object\" &&\n (\"result\" in parsed ||\n (typeof (parsed as { error?: unknown }).error === \"object\" &&\n (parsed as { error?: unknown }).error !== null &&\n typeof (parsed as { error: { code?: unknown } }).error.code === \"number\"));\n\n if (isJsonRpcEnvelope && !isTransportStatus(response.status)) {\n // A well-formed JSON-RPC error that merely arrived over a non-200 status. Hand it back\n // so starknet.js raises a proper RpcError instead of a parse error, and so the chain\n // does NOT burn other endpoints on a question they would all answer identically.\n return new Response(body, { status: 200, headers: { \"content-type\": \"application/json\" } });\n }\n\n // Label only: never the URL (query params) and never the headers (API key).\n throw new Error(`${TRANSPORT_MARKER} endpoint \"${label}\" returned HTTP ${response.status}`);\n };\n}\n\nconst TRANSPORT_MESSAGE_HINTS = [\n TRANSPORT_MARKER,\n // network / socket\n \"fetch failed\",\n \"failed to fetch\",\n \"network error\",\n \"networkerror\",\n \"socket hang up\",\n \"econnreset\",\n \"econnrefused\",\n \"econnaborted\",\n \"enotfound\",\n \"etimedout\",\n \"ehostunreach\",\n \"enetunreach\",\n \"epipe\",\n // timeouts / cancellation\n \"timeout\",\n \"timed out\",\n \"aborted\",\n // JSON parse failure: an error page or truncated body instead of a JSON-RPC envelope\n \"unexpected token\",\n \"unexpected end of json\",\n \"is not valid json\",\n \"invalid json\",\n \"json parse\",\n];\n\n/**\n * True only for transport-class failures (network/fetch error, timeout, HTTP 401/403/404/\n * 429/5xx, JSON parse failure).\n *\n * A well-formed JSON-RPC error (\"Contract not found\", \"Invalid params\") means the node\n * answered correctly: it is NOT a transport failure, so the caller rethrows immediately\n * instead of burning the rest of the chain on a question every node answers the same way.\n */\n/**\n * Starkscan's gateway code for \"this credential cannot do this here\" (missing RPC scope, rate\n * cap). Live 2026-08-15 as HTTP 403 + `{error:{code:-32012}}`, and also observed on HTTP 200.\n */\nconst STARKSCAN_GATEWAY_REFUSAL = -32012;\n\n/** Reads a JSON-RPC error code off whatever shape starknet.js hands us, or undefined. */\nfunction jsonRpcErrorCode(err: unknown): number | undefined {\n const e = err as { code?: unknown; baseError?: { code?: unknown } } | null | undefined;\n const raw = e?.baseError?.code ?? e?.code;\n return typeof raw === \"number\" ? raw : undefined;\n}\n\nfunction isTransportFailure(err: unknown): boolean {\n if (!err) return false;\n\n const e = err as {\n name?: string;\n message?: string;\n baseError?: unknown;\n status?: number;\n statusCode?: number;\n cause?: unknown;\n };\n\n // Starkscan's gateway signals a per-endpoint refusal (missing key scope, rate cap) with\n // this code, sometimes on an HTTP 200. Neither is chain truth, so it must fail over even\n // though it arrives as a well-formed JSON-RPC error. Auth is a property of OUR credential\n // at THIS endpoint, never of the chain.\n if (jsonRpcErrorCode(err) === STARKSCAN_GATEWAY_REFUSAL) return true;\n\n // starknet.js RpcError: the node replied with a JSON-RPC error envelope. Duck-typed\n // rather than `instanceof` so unit tests that mock the starknet module still take this path.\n if (e.name === \"RpcError\" || e.baseError !== undefined) return false;\n\n const status = typeof e.status === \"number\" ? e.status : e.statusCode;\n if (typeof status === \"number\" && isTransportStatus(status)) return true;\n\n if (e.name === \"AbortError\" || e.name === \"TimeoutError\" || e.name === \"SyntaxError\") return true;\n\n const message = typeof e.message === \"string\" ? e.message.toLowerCase() : \"\";\n if (message && TRANSPORT_MESSAGE_HINTS.some((hint) => message.includes(hint))) return true;\n\n // Node's fetch wraps the underlying socket error in `cause`.\n if (e.cause && e.cause !== err) return isTransportFailure(e.cause);\n\n return false;\n}\n\nconst providerCache = new Map<string, RpcProvider>();\n\n/** Memoized provider for one endpoint. */\nexport function rpcProviderFor(endpoint: RpcEndpoint): RpcProvider {\n const cacheKey = `${endpoint.label}|${endpoint.url}|${endpoint.headers ? \"auth\" : \"anon\"}`;\n const cached = providerCache.get(cacheKey);\n if (cached) return cached;\n\n const provider = new RpcProvider({\n nodeUrl: endpoint.url,\n baseFetch: makeRpcBaseFetch(endpoint.label),\n ...(endpoint.headers ? { headers: endpoint.headers } : {}),\n });\n providerCache.set(cacheKey, provider);\n return provider;\n}\n\n/**\n * Run a read against the endpoint chain, advancing to the next endpoint only when the\n * current one fails at transport level.\n *\n * Use for reads and for confirmation polling (both idempotent). Do NOT use it to wrap a\n * transaction submission: a retry on a different node could double-submit.\n */\nexport async function withRpcFallback<T>(\n fn: (provider: RpcProvider) => Promise<T>,\n opts?: { fallbackUrl?: string }\n): Promise<T> {\n const chain = buildRpcChain(opts);\n if (chain.length === 0) {\n // Defensive: buildRpcChain always appends a keyless endpoint, so this is unreachable.\n throw new Error(\"No Starknet RPC endpoint configured\");\n }\n\n let lastError: unknown;\n\n for (let i = 0; i < chain.length; i++) {\n const endpoint = chain[i];\n const isLast = i === chain.length - 1;\n\n try {\n const result = await fn(rpcProviderFor(endpoint));\n\n // An empty result is a transport failure in disguise, NOT a valid answer.\n // Starkscan rejects a bad/missing/expired API key with HTTP 401 carrying a\n // REST-shaped body (`{\"code\":\"unauthorized\",\"message\":\"Unauthorized\",...}`)\n // instead of a JSON-RPC error object. starknet.js cannot parse that: on both\n // 9.2.1 and 9.4.2, `getBlockNumber()` / `callContract()` resolve to `undefined`\n // and DO NOT THROW. Without this guard a wrong key would silently return\n // `undefined` from every SDK read with no error at all. Discriminate on\n // `undefined`/`null` ONLY: `0`, `\"0x0\"`, `false` and `[]` are legitimate\n // results (a balance read legitimately returns `[\"0x0\",\"0x0\"]`).\n if (result === undefined || result === null) {\n if (isLast) {\n throw new Error(\n `Starknet RPC endpoint \"${endpoint.label}\" returned an empty response ` +\n `(no JSON-RPC result). If this endpoint requires an API key, the key is ` +\n `likely missing, wrong or expired.`\n );\n }\n lastError = new Error(\n `${TRANSPORT_MARKER} endpoint \"${endpoint.label}\" returned an empty response`\n );\n continue;\n }\n\n return result;\n } catch (error) {\n if (isLast || !isTransportFailure(error)) throw error;\n lastError = error;\n // Label only: never the endpoint URL, headers or the API key.\n console.warn(\n `[chipi:rpc] transport failure on \"${endpoint.label}\" (${i + 1}/${chain.length}), falling through`\n );\n }\n }\n\n throw lastError instanceof Error\n ? lastError\n : new Error(`All Starknet RPC endpoints failed: ${String(lastError)}`);\n}\n","/**\n * Constants used across Chipi SDK packages\n */\n\nimport type { ShhhSignerKind, WalletType } from \"@chipi-stack/types\";\nimport { CARTRIDGE_MAINNET_RPC, DEFAULT_MAINNET_RPC, DEFAULT_SEPOLIA_RPC, readEnv } from \"./rpc\";\n\n// Ordered RPC chain + transport-level failover (Starkscan is primary only when\n// STARKSCAN_API_KEY is set; keyless integrators keep today's endpoint).\nexport * from \"./rpc\";\n\n/**\n * API Versioning\n * - VERSION: Major version for path-based versioning (/v1, /v2, etc.)\n * - VERSION_DATE: Detailed version for tracking breaking changes (YYYY-MM-DD format)\n *\n * Update VERSION_DATE when making API changes.\n * Update VERSION when making major breaking changes (typically 1-2 times per year).\n */\nexport const API_VERSIONING = {\n VERSION: \"1\", // Major version - used in URL path\n VERSION_DATE: \"2025-12-30\", // Detailed version - sent as query param for tracking\n} as const;\n\n// Default RPC URLs — override via STARKNET_RPC_URL / STARKNET_RPC_URL_SEPOLIA env vars.\n// The URL literals now live in ./rpc.ts alongside the failover chain that uses them;\n// the resolved values here are unchanged.\n\n// These evaluate at MODULE SCOPE, and this module is bundled into browser-facing\n// packages, so a bare `process.env` read throws at import time anywhere `process`\n// is not defined. It has worked so far only because bundlers inject a shim, which\n// makes client-side imports of this package accidental rather than supported.\n// `readEnv` is the same guard ./rpc.ts already uses; server behaviour is identical.\nexport const STARKNET_NETWORKS = {\n MAINNET: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n // Last resort of the mainnet chain built by buildRpcChain(), no longer a dead constant.\n MAINNET_FALLBACK: CARTRIDGE_MAINNET_RPC,\n SEPOLIA: readEnv(\"STARKNET_RPC_URL_SEPOLIA\") ?? DEFAULT_SEPOLIA_RPC,\n} as const;\n\nexport const CONTRACT_ADDRESSES = {\n USDC_MAINNET: \"0x033068F6539f8e6e6b131e6B2B814e6c34A5224bC66947c47DaB9dFeE93b35fb\", // Changed to Native USDC (was bridged USDC.e)\n VESU_USDC_MAINNET: \"0x017f19582c61479f2fe0b6606300e975c0a8f439102f43eeecc1d0e9b3d84350\",\n} as const;\n\nexport const TOKEN_DECIMALS = {\n USDC: 6,\n USDT: 6,\n ETH: 18,\n STRK: 18,\n DAI: 18,\n} as const;\n\nexport const API_ENDPOINTS = {\n CHIPI_WALLETS: \"/chipi-wallets\",\n TRANSACTIONS: \"/transactions\",\n SKUS: \"/skus\",\n SKU_PURCHASES: \"/sku-purchases\",\n EXCHANGES: \"/exchanges\",\n USERS: \"/users\",\n // SHHH multisig coordination (Plus Wave 9 / P1): SDK-exposed treasury\n // propose / sign / execute / list, owner-signature-authed.\n TREASURIES: \"/treasuries\",\n} as const;\n\nexport const ERRORS = {\n INVALID_API_KEY: \"INVALID_API_KEY\",\n WALLET_NOT_FOUND: \"WALLET_NOT_FOUND\",\n INSUFFICIENT_BALANCE: \"INSUFFICIENT_BALANCE\",\n TRANSACTION_FAILED: \"TRANSACTION_FAILED\",\n INVALID_SIGNATURE: \"INVALID_SIGNATURE\",\n SKU_NOT_FOUND: \"SKU_NOT_FOUND\",\n SKU_UNAVAILABLE: \"SKU_UNAVAILABLE\",\n} as const;\n\nexport const SKU_CONTRACTS = {\n RECHARGER_WITH_STRK_MAINNET: \"0x02d65bb726d2c29e3c97669cf297c5145eac19284fb6f935c05c0bfc68dae2b7\", //changed contract address used to be 0x0f3\n CHIPI_BILL_SERVICE: \"0x4e8150110d580069de26adec9b179023289d55859ea07487aaade5458d7aa8b\",\n} as const;\n\n// Service types\nexport const SERVICE_TYPES = {\n BUY_SERVICE: \"BUY_SERVICE\",\n} as const;\n\n// Carrier IDs\nexport const CARRIER_IDS = {\n CHIPI_PAY: \"chipi_pay\",\n} as const;\n\nexport const CHAIN_TYPES = {\n STARKNET: \"STARKNET\",\n} as const;\n\nexport const CHAIN_TOKEN_TYPES = {\n USDC: \"USDC\", // Changed to Native USDC (was bridged USDC.e)\n USDT: \"USDT\",\n ETH: \"ETH\",\n STRK: \"STRK\",\n DAI: \"DAI\",\n WBTC: \"WBTC\",\n OTHER: \"OTHER\",\n} as const;\n\nexport const WALLET_CLASS_HASHES: Record<string, string> = {\n CHIPI: \"0x053f4f8791ed5bed0fddaa553d180c664e32cfaf8316bb232ae77bb08f459f2a\", // v29 — must match backend until coordinated v33 upgrade\n READY: \"0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f\",\n // V8.5 ShhhAccount — declared 2026-10-14. The single-owner envelope must\n // carry the threshold (V8.4 ignored it). Needs chipi-back with\n // OPT_IN_SHHH_CLASS_HASHES: createWallet names this class explicitly.\n SHHH: \"0x067828c8b82ac723b4adb141f9aa8975e296d8c11179d22bb8d7203b32abd96a\",\n};\n\n/**\n * Previous CHIPI wallet class hashes that are still deployed on-chain.\n * Used by getWalletTypeFromClassHash() to identify legacy wallets.\n * Ordered newest → oldest.\n */\nexport const LEGACY_CHIPI_CLASS_HASHES: string[] = [\n \"0x0484bbd2404b3c7264bea271f7267d6d4004821ac7787a9eed7f472e79ef40d1\", // v33 — wallets created during brief v33 window\n \"0x035a2251aca25daba18a5d8950deffa8372a7d84774554e75283cb85552eebc9\", // v32 — audit 3\n \"0x0254f6dd0427319ec614c29e4e3929500d1ba95d0da87ff81d67051ce572667\", // v31\n \"0x072b77b033a874fa1b8f7ff52e18be8fb5ce01a00c59cd184ae15f5b29bc0e57\", // v30\n \"0x02de1565226d5215a38b68c4d9a4913989b54edff64c68c45e453c417b44cd83\", // v28\n];\n\n/**\n * Deprecated SHHH class hashes that may exist on-chain but must NOT be routed\n * for new deploys. V8 series ships without an `upgrade` selector, so existing\n * instances at deprecated classes cannot self-upgrade — they redeploy at the\n * current SHHH class hash.\n */\nexport const LEGACY_SHHH_CLASS_HASHES: string[] = [\n \"0x075dfb396145926bffa6beb659897f46cc082a50b211d80871cff7f1038fa58a\", // V8.4 — deprecated 2026-10-14, single-owner path ignores the threshold (safe at threshold 1)\n \"0x03bc539295abd3e59bd9ea799d12fe3331748d484bc77bff45b302b1636a87d9\", // V8.3 — deprecated 2026-05-15, no stranded-bootstrap recovery\n];\n\n/**\n * SHHH ShhhAccount verifier class hashes (V8.4, mainnet).\n *\n * The ShhhAccount dispatches `verify` to one of these verifier classes via\n * `library_call_syscall` based on the owner's `kind_tag`. Verifier classes are\n * pinned to deterministic outputs of `scarb build` at commit `3975532` (tag\n * v8.4) — Chipi routes to these hashes as a consumer; we do not redeclare.\n */\nexport const SHHH_VERIFIER_CLASS_HASHES: Record<ShhhSignerKind, string> = {\n STARK: \"0x00d09209b2da9d49fc805ba26380ba4ce25aa641116c10eb178e1051a71dbf68\",\n ED25519: \"0x030a7dfc03e59cef6e41699e734abd2df53ce393a052221c02c6e07665949f74\",\n SECP256K1: \"0x03e81667a46bd5287e09a9600fa98d28fdc477735f2689f5f4e8e95f37b67b74\",\n EIP191_SECP256K1: \"0x03a75997862059c36cb8e204fb3027eb6d1fdf933488d42c2db4528118d084e6\",\n EIP712_SECP256K1: \"0x072a3f77e8c28bfea2ade91ec3fb83b6290169d1ed8c1b2396704231841c6474\",\n // Starknet browser wallets (Bramble, Braavos, Ready/Argent, OZ) via\n // wallet_signTypedData. Built from shhh-wallet-cairo PR #23 with Scarb 2.14.0\n // (same toolchain that reproduces every hash above). Declared on mainnet\n // 2026-10-14 (block 16377651); isShhhVerifierDeclared() checks other networks.\n STARK_SNIP12: \"0x017884125977631bee198b34cd3e3fcf975a543e453c8b996a818910a964b5e\",\n P256: \"0x01b600709af54c8838e5f18ddad3a26feeb47cb124c239f55a0f1b7a780e2d8a\",\n WEBAUTHN_P256: \"0x074f6efd2af9025cd8cab41a4565bc73b6ef097214c31352838fcdbac0a44657\",\n JWT_ES256: \"0x002efce875fa3e73e04d825d8ebade53e188cc995dfe0c55a6a2f7fa6c59f497\",\n JWT_ES256_APPLE_SUB: \"0x06b67762218a25fdd28e25b063480893a5cef9cdeecbc663e32d444d5734c471\",\n BLS12_381: \"0x02623721e74a9ad3e0ba639065f5631a09bf900913de6ab21ea6984973cd2cd1\",\n};\n\n/**\n * Upper-bound l2_gas overhead per SHHH signer kind, in addition to base\n * paymaster execution cost. Numbers from snforge runs at tag v8.4\n * (252-byte calls, single owner, no session key). Paymaster adds ~5M safety\n * margin on top.\n *\n * Threshold envelopes: sum the per-owner cost + ~3M aggregation overhead.\n * Session-key envelopes (SNIP-163 4-felt): ~2M + session-policy enforcement.\n */\nexport const SHHH_KIND_GAS_OVERHEAD: Record<ShhhSignerKind, number> = {\n STARK: 2_000_000,\n SECP256K1: 5_000_000,\n EIP191_SECP256K1: 10_000_000,\n EIP712_SECP256K1: 12_000_000,\n STARK_SNIP12: 2_500_000,\n P256: 30_000_000,\n ED25519: 33_000_000,\n WEBAUTHN_P256: 35_000_000,\n JWT_ES256: 60_000_000,\n JWT_ES256_APPLE_SUB: 62_000_000,\n BLS12_381: 80_000_000,\n};\n\n/**\n * Inner-envelope routing tags per the V8.4 Pluggable-Signer SNIP draft.\n * The ShhhAccount strips the version tag and library_calls the verifier;\n * Chipi paymaster does NOT need to parse the inner payload but DOES need\n * to pass the entire signature span verbatim to `execute_from_outside_v2`.\n */\nexport const SHHH_ENVELOPE_TAGS = {\n V2_SNIP12: \"V2_SNIP12\",\n V2_THRESHOLD: \"V2_THRESHOLD\",\n // Session-key envelopes are the SNIP-163 4-felt format (no version tag prefix).\n} as const;\n\n/**\n * Determine wallet type from an on-chain class hash.\n * - If it matches the READY hash → READY\n * - If it matches the current CHIPI hash or a legacy CHIPI hash → CHIPI\n * - If it matches the current SHHH hash or a legacy SHHH hash → SHHH\n * - Otherwise → null (unknown class hash, caller should handle accordingly)\n */\nexport function getWalletTypeFromClassHash(classHash: string): WalletType | null {\n const normalize = (h: string) => h.toLowerCase().replace(/^0x0+/, \"0x\");\n const normalized = normalize(classHash);\n\n if (normalize(WALLET_CLASS_HASHES.READY) === normalized) {\n return \"READY\";\n }\n if (normalize(WALLET_CLASS_HASHES.CHIPI) === normalized) {\n return \"CHIPI\";\n }\n if (LEGACY_CHIPI_CLASS_HASHES.some((h) => normalize(h) === normalized)) {\n return \"CHIPI\";\n }\n if (normalize(WALLET_CLASS_HASHES.SHHH) === normalized) {\n return \"SHHH\";\n }\n if (LEGACY_SHHH_CLASS_HASHES.some((h) => normalize(h) === normalized)) {\n return \"SHHH\";\n }\n // Unknown class hash — return null so callers can handle explicitly\n return null;\n}\n\n/**\n * Returns true if a class hash is a registered SHHH ShhhAccount class\n * (current or legacy) OR one of the 10 V8.4 verifier classes. Used by the\n * backend to reject unknown class hashes when an integrator opts into SHHH\n * via `walletType: \"SHHH\"` (D4 safety net — open SDK option, no per-org gate).\n */\nexport function isKnownShhhClassHash(classHash: string): boolean {\n const normalize = (h: string) => h.toLowerCase().replace(/^0x0+/, \"0x\");\n const normalized = normalize(classHash);\n\n if (normalize(WALLET_CLASS_HASHES.SHHH) === normalized) return true;\n if (LEGACY_SHHH_CLASS_HASHES.some((h) => normalize(h) === normalized)) return true;\n return Object.values(SHHH_VERIFIER_CLASS_HASHES).some((h) => normalize(h) === normalized);\n}\n\n// RPC endpoints per wallet type — any standard Starknet RPC works for all wallet types.\n// Override via STARKNET_RPC_URL env var; falls back to the default Infura endpoint.\n//\n// Deliberately still a Record<string, string> of plain URLs: it is a published API\n// consumed as URL strings in ~8 places, so widening it would be a breaking change.\n// A Starkscan endpoint cannot be represented here anyway (its key must travel in a\n// header, never in the URL). Pass these values as `buildRpcChain({ fallbackUrl })` /\n// `withRpcFallback(fn, { fallbackUrl })` to get the header-authed chain on top.\nexport const WALLET_RPC_ENDPOINTS: Record<string, string> = {\n CHIPI: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n READY: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n SHHH: readEnv(\"STARKNET_RPC_URL\") ?? DEFAULT_MAINNET_RPC,\n};\n\n// Paymaster configuration\nexport const PAYMASTER_CONFIG = {\n URL: \"https://paymaster.chipipay.com\",\n} as const;\n\n// Session key configuration (CHIPI wallets only - SNIP-9 compatible)\nexport const SESSION_DEFAULTS = {\n /** Default session duration: 6 hours in seconds */\n DURATION_SECONDS: 21600,\n /** Default max calls per session */\n MAX_CALLS: 1000,\n} as const;\n\n// Session-specific error codes\nexport const SESSION_ERRORS = {\n /** Session keys only work with CHIPI wallets */\n INVALID_WALLET_TYPE_FOR_SESSION: \"INVALID_WALLET_TYPE_FOR_SESSION\",\n /** Session has expired (validUntil < now) */\n SESSION_EXPIRED: \"SESSION_EXPIRED\",\n /** Session key not registered on contract */\n SESSION_NOT_REGISTERED: \"SESSION_NOT_REGISTERED\",\n /** Session key has been revoked */\n SESSION_REVOKED: \"SESSION_REVOKED\",\n /** Session has exceeded max calls */\n SESSION_MAX_CALLS_EXCEEDED: \"SESSION_MAX_CALLS_EXCEEDED\",\n /** Entrypoint not allowed for this session */\n SESSION_ENTRYPOINT_NOT_ALLOWED: \"SESSION_ENTRYPOINT_NOT_ALLOWED\",\n /** Failed to decrypt session private key */\n SESSION_DECRYPTION_FAILED: \"SESSION_DECRYPTION_FAILED\",\n /** Failed to create session key */\n SESSION_CREATION_FAILED: \"SESSION_CREATION_FAILED\",\n /** Backend returned an invalid response shape */\n SESSION_INVALID_RESPONSE: \"SESSION_INVALID_RESPONSE\",\n /** Invalid spending policy configuration */\n INVALID_SPENDING_POLICY: \"INVALID_SPENDING_POLICY\",\n} as const;\n\n// Session contract entrypoint names\nexport const SESSION_ENTRYPOINTS = {\n /** Add or update a session key (owner only) */\n ADD_OR_UPDATE: \"add_or_update_session_key\",\n /** Revoke a session key (owner only) */\n REVOKE: \"revoke_session_key\",\n /** Query session data (public read) */\n GET_DATA: \"get_session_data\",\n /** Set a spending policy for a session key + token pair (owner only) */\n SET_SPENDING_POLICY: \"set_spending_policy\",\n /** Query a spending policy (public read) */\n GET_SPENDING_POLICY: \"get_spending_policy\",\n /** Remove a spending policy (owner only) */\n REMOVE_SPENDING_POLICY: \"remove_spending_policy\",\n} as const;\n"]}
|
package/dist/index.js
CHANGED
|
@@ -331,8 +331,10 @@ var WALLET_CLASS_HASHES = {
|
|
|
331
331
|
CHIPI: "0x053f4f8791ed5bed0fddaa553d180c664e32cfaf8316bb232ae77bb08f459f2a",
|
|
332
332
|
// v29 — must match backend until coordinated v33 upgrade
|
|
333
333
|
READY: "0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f",
|
|
334
|
-
|
|
335
|
-
// V8.4
|
|
334
|
+
// V8.5 ShhhAccount — declared 2026-10-14. The single-owner envelope must
|
|
335
|
+
// carry the threshold (V8.4 ignored it). Needs chipi-back with
|
|
336
|
+
// OPT_IN_SHHH_CLASS_HASHES: createWallet names this class explicitly.
|
|
337
|
+
SHHH: "0x067828c8b82ac723b4adb141f9aa8975e296d8c11179d22bb8d7203b32abd96a"
|
|
336
338
|
};
|
|
337
339
|
var LEGACY_CHIPI_CLASS_HASHES = [
|
|
338
340
|
"0x0484bbd2404b3c7264bea271f7267d6d4004821ac7787a9eed7f472e79ef40d1",
|
|
@@ -347,6 +349,8 @@ var LEGACY_CHIPI_CLASS_HASHES = [
|
|
|
347
349
|
// v28
|
|
348
350
|
];
|
|
349
351
|
var LEGACY_SHHH_CLASS_HASHES = [
|
|
352
|
+
"0x075dfb396145926bffa6beb659897f46cc082a50b211d80871cff7f1038fa58a",
|
|
353
|
+
// V8.4 — deprecated 2026-10-14, single-owner path ignores the threshold (safe at threshold 1)
|
|
350
354
|
"0x03bc539295abd3e59bd9ea799d12fe3331748d484bc77bff45b302b1636a87d9"
|
|
351
355
|
// V8.3 — deprecated 2026-05-15, no stranded-bootstrap recovery
|
|
352
356
|
];
|
|
@@ -356,6 +360,11 @@ var SHHH_VERIFIER_CLASS_HASHES = {
|
|
|
356
360
|
SECP256K1: "0x03e81667a46bd5287e09a9600fa98d28fdc477735f2689f5f4e8e95f37b67b74",
|
|
357
361
|
EIP191_SECP256K1: "0x03a75997862059c36cb8e204fb3027eb6d1fdf933488d42c2db4528118d084e6",
|
|
358
362
|
EIP712_SECP256K1: "0x072a3f77e8c28bfea2ade91ec3fb83b6290169d1ed8c1b2396704231841c6474",
|
|
363
|
+
// Starknet browser wallets (Bramble, Braavos, Ready/Argent, OZ) via
|
|
364
|
+
// wallet_signTypedData. Built from shhh-wallet-cairo PR #23 with Scarb 2.14.0
|
|
365
|
+
// (same toolchain that reproduces every hash above). Declared on mainnet
|
|
366
|
+
// 2026-10-14 (block 16377651); isShhhVerifierDeclared() checks other networks.
|
|
367
|
+
STARK_SNIP12: "0x017884125977631bee198b34cd3e3fcf975a543e453c8b996a818910a964b5e",
|
|
359
368
|
P256: "0x01b600709af54c8838e5f18ddad3a26feeb47cb124c239f55a0f1b7a780e2d8a",
|
|
360
369
|
WEBAUTHN_P256: "0x074f6efd2af9025cd8cab41a4565bc73b6ef097214c31352838fcdbac0a44657",
|
|
361
370
|
JWT_ES256: "0x002efce875fa3e73e04d825d8ebade53e188cc995dfe0c55a6a2f7fa6c59f497",
|
|
@@ -367,6 +376,7 @@ var SHHH_KIND_GAS_OVERHEAD = {
|
|
|
367
376
|
SECP256K1: 5e6,
|
|
368
377
|
EIP191_SECP256K1: 1e7,
|
|
369
378
|
EIP712_SECP256K1: 12e6,
|
|
379
|
+
STARK_SNIP12: 25e5,
|
|
370
380
|
P256: 3e7,
|
|
371
381
|
ED25519: 33e6,
|
|
372
382
|
WEBAUTHN_P256: 35e6,
|