@panoptic-eng/sdk 1.0.67 → 1.0.69

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.
Files changed (42) hide show
  1. package/dist/{chainDeployments-CwnYHCg7.js → chainDeployments-BGvEeQSH.js} +24 -6
  2. package/dist/cow/index.d.ts.map +1 -1
  3. package/dist/cow/index.js +47 -2
  4. package/dist/cow/index.js.map +1 -1
  5. package/dist/{cow-CGgPXhY6.js → cow-BBPknr5W.js} +1 -1
  6. package/dist/deployments.d.ts +2 -0
  7. package/dist/deployments.d.ts.map +1 -1
  8. package/dist/deployments.js +24 -6
  9. package/dist/deployments.js.map +1 -1
  10. package/dist/{greeks-CGtgLUyh.js → greeks-DNPP24KL.js} +115 -9
  11. package/dist/index.d.ts +197 -46
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2359 -2180
  14. package/dist/index.js.map +1 -1
  15. package/dist/{irm-BDxwCFDm.js → irm-DurYJ0ht.js} +3 -3
  16. package/dist/panoptic/v2/greeks/index.d.ts +7 -4
  17. package/dist/panoptic/v2/greeks/index.d.ts.map +1 -1
  18. package/dist/panoptic/v2/greeks/index.js +74 -7
  19. package/dist/panoptic/v2/greeks/index.js.map +1 -1
  20. package/dist/panoptic/v2/index.d.ts +89 -5
  21. package/dist/panoptic/v2/index.d.ts.map +1 -1
  22. package/dist/panoptic/v2/index.js +699 -55
  23. package/dist/panoptic/v2/index.js.map +1 -1
  24. package/dist/panoptic/v2/react-public.d.ts +80 -6
  25. package/dist/panoptic/v2/react-public.d.ts.map +1 -1
  26. package/dist/panoptic/v2/react-public.js +2717 -2463
  27. package/dist/panoptic/v2/react-public.js.map +1 -1
  28. package/dist/{rates-BHS-Qiu7.js → rates-B-eRYOTS.js} +39 -3
  29. package/dist/{router-BW6TqwOO.js → router-ChMhfTqT.js} +969 -39
  30. package/dist/rpc/index.d.ts +3 -0
  31. package/dist/rpc/index.d.ts.map +1 -1
  32. package/dist/rpc/index.js +31 -3
  33. package/dist/rpc/index.js.map +1 -1
  34. package/dist/{transactionFees-B4jz-v7d.js → transactionFees-BGfyq3Jo.js} +1 -1
  35. package/dist/uniswap/index.js +53 -13
  36. package/dist/uniswap/index.js.map +1 -1
  37. package/dist/{v2-Dgh6JxG_.js → v2-Bo1vZXvR.js} +150 -10
  38. package/dist/vault-transaction-fees.js +24 -6
  39. package/dist/vault-transaction-fees.js.map +1 -1
  40. package/dist/{writes-CG612Vuk.js → writes-D53wWDT-.js} +2 -2
  41. package/package.json +1 -1
  42. package/dist/router-IDtCENST.js +0 -942
@@ -87,6 +87,8 @@ type RpcTransportOptions = RpcHttpConfig & {
87
87
  * another surfaces as "already known" / "nonce too low" although it was sent.
88
88
  */
89
89
  failover?: boolean;
90
+ /** Shared HTTP attempt limit, including retries and failover. Disables HTTP batching. */
91
+ requestsPerSecond?: number;
90
92
  };
91
93
  /**
92
94
  * Transport over resolved endpoints: plain HTTP for one endpoint, otherwise an
@@ -94,6 +96,7 @@ type RpcTransportOptions = RpcHttpConfig & {
94
96
  */
95
97
  declare function rpcTransport(endpoints: readonly RpcEndpoint[], {
96
98
  failover,
99
+ requestsPerSecond,
97
100
  ...config
98
101
  }?: RpcTransportOptions): Transport;
99
102
  /** anvil fork arguments for the primary endpoint (`--fork-header` only when it needs one). */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["RpcProviderPreset","Record","alchemyChains","AlchemyChainId","RpcProviderName","RPC_PROVIDER_PRESETS","Readonly","isRpcProviderName","getAlchemyRpcUrl","getAlchemyWsRpcUrl","redactRpcSecrets","RpcProviderName","RpcEnv","Record","Readonly","RpcEndpoint","ResolveRpcEndpointsOptions","DEFAULT_RPC_PROVIDERS","resolveRpcEndpoints","viem1","HttpTransportConfig","Transport","RpcEndpoint","RpcHttpConfig","Omit","rpcHttp","viem0","RpcSchema","HttpTransport","RpcTransportOptions","rpcTransport","failover","rpcForkArgs","ponderRpc"],"sources":["../../src/rpc/providers.d.ts","../../src/rpc/redact.d.ts","../../src/rpc/resolve.d.ts","../../src/rpc/transport.d.ts"],"sourcesContent":null,"mappings":";;;;;;;;;;;;;;;KAKYA,iBAAAA;;;;;IAAAA,GAAAA,EAAAA,MAAAA;IASEE,OAAAA,CAAAA,EAHIW,MAYjB,CAAA,MAAA,EAAA,MAAA,CAAA;EACWV,CAAAA,GAAAA,SAAAA;AACZ,CAAA;AACA,cAZcD,aAYiF,EAAA;EAAA,SAAA,CAAA,EAAA,aAAA;EAAA,SAApCS,GAAAA,EAAAA,iBAAAA;EAAe,SAAEX,KAAAA,EAAAA,aAAAA;EAAiB,SAAzCa,IAAAA,EAAAA,cAAAA;EAAM,SAAfC,EAAAA,EAAAA,aAAAA;EAAQ,SAAA,GAAA,EAAA,kBAAA;EAE3BN,SAAAA,IAAAA,EAAAA,mBAA0BL;EAC1BM,SAAAA,QAAAA,EAAAA,aAA4BN;;KALxCA,cAAAA,gBAA8BD;KAC9BS,eAAAA;cACSN,sBAAsBS,SAASD,OAAOF,iBAAiBX;iBAEpDQ,gBAAAA,UAA0BL;iBAC1BM,kBAAAA,UAA4BN;;;;;;;iBCxB5BO,gBAAAA;;;;KCJZE,MAAAA,GAASE,SAASD;KAClBS,WAAAA;;UAEAX;;;WAGCE;;KAEDG,0BAAAA;EFJAhB;EASEE,YAAAA,CAAAA,EAAAA,SASb,MAAA,EAAA;EACWC;EACAQ,gBAAAA,CAAAA,EAAe,SEZKA,eFYL,EAAA;AAC3B,CAAA;AAA+F,cEX1EM,qBFW0E,EAAA,SEX1CN,eFW0C,EAAA;;;;;AAA5C;AAEnD;AACA;;;;;iBEFwBO,mBAAAA,uBAA0CN,kBAAkBI,6BAA6BM;;;;KCzBrGC,aAAAA,GAAgBC,KAAKJ;;iBAETK,OAAAA,WAAkBH,sBAAsBC,gBAAqEJ,KAAAA,CAAtCS,cAAlBF,KAAAA,CAA+CC,SAAAA;KAChHE,mBAAAA,GAAsBN;;;;;AHAlC;EAScrB,QAAAA,CAAAA,EAAAA,OASb;AACD,CAAA;AACA;AACA;;;AAA4EF,iBGTpD8B,YAAAA,CHSoD9B,SAAAA,EAAAA,SGTnBsB,WHSmBtB,EAAAA,EAAAA;EAAAA,QAAAA;EAAAA,GAAAA;AAAAA,CAAAA,CAAAA,EGTsB6B,mBHStB7B,CAAAA,EGT4CqB,SHS5CrB;;AAAjCc,iBGPnBkB,WAAAA,CHOmBlB,SAAAA,EAAAA,SGPaQ,WHObR,EAAAA,CAAAA,EAAAA;EAAQ,OAAA,EAAA,MAAA;EAE3BN,UAAAA,CAAAA,EAAAA,MAAgB;AACxC,CAAA;;;;;iBGFwByB,SAAAA,qBAA8BX,oCAAoCD"}
1
+ {"version":3,"file":"index.d.ts","names":["RpcProviderPreset","Record","alchemyChains","AlchemyChainId","RpcProviderName","RPC_PROVIDER_PRESETS","Readonly","isRpcProviderName","getAlchemyRpcUrl","getAlchemyWsRpcUrl","redactRpcSecrets","RpcProviderName","RpcEnv","Record","Readonly","RpcEndpoint","ResolveRpcEndpointsOptions","DEFAULT_RPC_PROVIDERS","resolveRpcEndpoints","viem1","HttpTransportConfig","Transport","RpcEndpoint","RpcHttpConfig","Omit","rpcHttp","viem0","RpcSchema","HttpTransport","RpcTransportOptions","rpcTransport","failover","requestsPerSecond","rpcForkArgs","ponderRpc"],"sources":["../../src/rpc/providers.d.ts","../../src/rpc/redact.d.ts","../../src/rpc/resolve.d.ts","../../src/rpc/transport.d.ts"],"sourcesContent":null,"mappings":";;;;;;;;;;;;;;;KAKYA,iBAAAA;;;;;IAAAA,GAAAA,EAAAA,MAAAA;IASEE,OAAAA,CAAAA,EAHIW,MAYjB,CAAA,MAAA,EAAA,MAAA,CAAA;EACWV,CAAAA,GAAAA,SAAAA;AACZ,CAAA;AACA,cAZcD,aAYiF,EAAA;EAAA,SAAA,CAAA,EAAA,aAAA;EAAA,SAApCS,GAAAA,EAAAA,iBAAAA;EAAe,SAAEX,KAAAA,EAAAA,aAAAA;EAAiB,SAAzCa,IAAAA,EAAAA,cAAAA;EAAM,SAAfC,EAAAA,EAAAA,aAAAA;EAAQ,SAAA,GAAA,EAAA,kBAAA;EAE3BN,SAAAA,IAAAA,EAAAA,mBAA0BL;EAC1BM,SAAAA,QAAAA,EAAAA,aAA4BN;;KALxCA,cAAAA,gBAA8BD;KAC9BS,eAAAA;cACSN,sBAAsBS,SAASD,OAAOF,iBAAiBX;iBAEpDQ,gBAAAA,UAA0BL;iBAC1BM,kBAAAA,UAA4BN;;;;;;;iBCxB5BO,gBAAAA;;;;KCJZE,MAAAA,GAASE,SAASD;KAClBS,WAAAA;;UAEAX;;;WAGCE;;KAEDG,0BAAAA;EFJAhB;EASEE,YAAAA,CAAAA,EAAAA,SASb,MAAA,EAAA;EACWC;EACAQ,gBAAAA,CAAAA,EAAe,SEZKA,eFYL,EAAA;AAC3B,CAAA;AAA+F,cEX1EM,qBFW0E,EAAA,SEX1CN,eFW0C,EAAA;;;;;AAA5C;AAEnD;AACA;;;;;iBEFwBO,mBAAAA,uBAA0CN,kBAAkBI,6BAA6BM;;;;KCzBrGC,aAAAA,GAAgBC,KAAKJ;;iBAETK,OAAAA,WAAkBH,sBAAsBC,gBAAqEJ,KAAAA,CAAtCS,cAAlBF,KAAAA,CAA+CC,SAAAA;KAChHE,mBAAAA,GAAsBN;;;;;AHAlC;EAScrB,QAAAA,CAAAA,EAAAA,OASb;EACWC;EACAQ,iBAAAA,CAAe,EAAA,MAAA;AAC3B,CAAA;;;;;AAA2CG,iBGPnBgB,YAAAA,CHOmBhB,SAAAA,EAAAA,SGPcQ,WHOdR,EAAAA,EAAAA;EAAAA,QAAAA;EAAAA,iBAAAA;EAAAA,GAAAA;AAAAA,CAAAA,CAAAA,EGP0Ee,mBHO1Ef,CAAAA,EGPgGO,SHOhGP;AAAQ;AAE3BN,iBGPAyB,WAAAA,CHO0B9B,SAAAA,EAAc,SGPRmB,WHOQ,EAAA,CAAA,EAAA;EACxCb,OAAAA,EAAAA,MAAAA;;;;;;;iBGAAyB,SAAAA,qBAA8BZ,oCAAoCD"}
package/dist/rpc/index.js CHANGED
@@ -195,6 +195,29 @@ function resolveRpcEndpoints(chainId, env, options = {}) {
195
195
  ].join(", ")}`);
196
196
  }
197
197
 
198
+ //#endregion
199
+ //#region src/rpc/rateLimit.ts
200
+ /** Limits HTTP attempts, including retries, across clients sharing this fetch function. */
201
+ function rateLimitedRpcFetch(requestsPerSecond, fetchFn = fetch) {
202
+ if (!Number.isFinite(requestsPerSecond) || requestsPerSecond <= 0) throw new Error("RPC requestsPerSecond must be positive and finite");
203
+ const intervalMs = Math.ceil(1e3 / requestsPerSecond);
204
+ let nextStart = 0;
205
+ let tail = Promise.resolve();
206
+ return (input, init) => {
207
+ const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
208
+ const request = tail.then(async () => {
209
+ signal?.throwIfAborted();
210
+ const delay = nextStart - Date.now();
211
+ if (delay > 0) await new Promise((resolve) => setTimeout(resolve, delay));
212
+ signal?.throwIfAborted();
213
+ nextStart = Date.now() + intervalMs;
214
+ return fetchFn(input, init);
215
+ });
216
+ tail = request.then(() => void 0, () => void 0);
217
+ return request;
218
+ };
219
+ }
220
+
198
221
  //#endregion
199
222
  //#region src/rpc/transport.ts
200
223
  /** viem HTTP transport for one endpoint, carrying its credential headers. */
@@ -208,11 +231,16 @@ function rpcHttp(endpoint, config = {}) {
208
231
  * Transport over resolved endpoints: plain HTTP for one endpoint, otherwise an
209
232
  * unranked viem `fallback` in configured order.
210
233
  */
211
- function rpcTransport(endpoints, { failover = true,...config } = {}) {
234
+ function rpcTransport(endpoints, { failover = true, requestsPerSecond,...config } = {}) {
235
+ const httpConfig = requestsPerSecond === void 0 ? config : {
236
+ ...config,
237
+ batch: false,
238
+ fetchFn: rateLimitedRpcFetch(requestsPerSecond, config.fetchFn)
239
+ };
212
240
  const [primary, ...rest] = endpoints;
213
241
  if (primary === void 0) throw new Error("rpcTransport needs at least one endpoint");
214
- if (!failover || rest.length === 0) return rpcHttp(primary, config);
215
- return fallback(endpoints.map((endpoint) => rpcHttp(endpoint, config)), { rank: false });
242
+ if (!failover || rest.length === 0) return rpcHttp(primary, httpConfig);
243
+ return fallback(endpoints.map((endpoint) => rpcHttp(endpoint, httpConfig)), { rank: false });
216
244
  }
217
245
  /** anvil fork arguments for the primary endpoint (`--fork-header` only when it needs one). */
218
246
  function rpcForkArgs(endpoints) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["chainId: number","infuraChains: Record<number, string>","RPC_PROVIDER_PRESETS: Readonly<Record<RpcProviderName, RpcProviderPreset>>","name: string","chainId: AlchemyChainId","alchemyApiKey: string","raw: string","text: string | undefined","DEFAULT_RPC_PROVIDERS: readonly RpcProviderName[]","value: string | undefined","envName: string","headers: Record<string, string>","value: string","name: RpcProviderName","chainId: number","env: RpcEnv","legacyUrlEnv: readonly string[]","providers: readonly string[]","endpoints: RpcEndpoint[]","options: ResolveRpcEndpointsOptions","endpoint: RpcEndpoint","config: RpcHttpConfig","endpoints: readonly RpcEndpoint[]"],"sources":["../../src/rpc/providers.ts","../../src/rpc/redact.ts","../../src/rpc/resolve.ts","../../src/rpc/transport.ts"],"sourcesContent":["/**\n * The only place that knows RPC vendor URL formats and credentials. Supporting\n * a new vendor means adding one preset here; services select it through env\n * (see `resolveRpcEndpoints`).\n */\n\nexport type RpcProviderPreset = {\n /** Env vars holding the API key for `chainId`, highest precedence first. */\n apiKeyEnv: (chainId: number) => readonly string[]\n /** Endpoint for `chainId`, or undefined when the vendor does not serve it. */\n endpoint: (\n chainId: number,\n apiKey: string,\n ) => { url: string; headers?: Record<string, string> } | undefined\n}\n\nconst alchemyChains = {\n 1: 'eth-mainnet',\n 137: 'polygon-mainnet',\n 42161: 'arb-mainnet',\n 8453: 'base-mainnet',\n 10: 'opt-mainnet',\n 130: 'unichain-mainnet',\n 4663: 'robinhood-mainnet',\n 11155111: 'eth-sepolia',\n} as const\n\nexport type AlchemyChainId = keyof typeof alchemyChains\n\nfunction isAlchemyChainId(chainId: number): chainId is AlchemyChainId {\n return chainId in alchemyChains\n}\n\nconst infuraChains: Record<number, string> = {\n 1: 'mainnet',\n 10: 'optimism-mainnet',\n 137: 'polygon-mainnet',\n 8453: 'base-mainnet',\n 42161: 'arbitrum-mainnet',\n 43114: 'avalanche-mainnet',\n 11155111: 'sepolia',\n}\n\nexport type RpcProviderName = 'alchemy' | 'infura' | 'uniblock'\n\nexport const RPC_PROVIDER_PRESETS: Readonly<Record<RpcProviderName, RpcProviderPreset>> = {\n alchemy: {\n apiKeyEnv: () => ['ALCHEMY_API_KEY'],\n endpoint: (chainId, apiKey) =>\n isAlchemyChainId(chainId)\n ? { url: `https://${alchemyChains[chainId]}.g.alchemy.com/v2/${apiKey}` }\n : undefined,\n },\n infura: {\n apiKeyEnv: () => ['INFURA_API_KEY'],\n endpoint: (chainId, apiKey) =>\n infuraChains[chainId]\n ? { url: `https://${infuraChains[chainId]}.infura.io/v3/${apiKey}` }\n : undefined,\n },\n uniblock: {\n apiKeyEnv: () => ['UNIBLOCK_API_KEY'],\n // Uniblock accepts the key only as a header, and serves keyless requests\n // from an anonymous tier — callers must never send it without one.\n endpoint: (chainId, apiKey) => ({\n url: `https://api.uniblock.dev/uni/v1/json-rpc?chainId=${chainId}`,\n headers: { 'x-api-key': apiKey },\n }),\n },\n}\n\nexport function isRpcProviderName(name: string): name is RpcProviderName {\n return Object.prototype.hasOwnProperty.call(RPC_PROVIDER_PRESETS, name)\n}\n\nexport function getAlchemyRpcUrl(chainId: AlchemyChainId, alchemyApiKey: string): string {\n if (alchemyChains[chainId]) {\n return `https://${alchemyChains[chainId]}.g.alchemy.com/v2/${alchemyApiKey}`\n } else {\n throw new Error(`Unsupported chainId: ${chainId}`)\n }\n}\n\nexport function getAlchemyWsRpcUrl(chainId: AlchemyChainId, alchemyApiKey: string): string {\n if (alchemyChains[chainId]) {\n return `wss://${alchemyChains[chainId]}.g.alchemy.com/v2/${alchemyApiKey}`\n } else {\n throw new Error(`Unsupported chainId: ${chainId}`)\n }\n}\n","const URL_PATTERN = /\\b(?:https?|wss?):\\/\\/[^\\s\"'<>)]+/giu\n// Unquoted authentication values can contain commas and quotes, so mask through the line boundary.\nconst CREDENTIAL_HEADER_PATTERN =\n /\\b(x-api-key|authorization|proxy-authorization)([\"']?\\s*[:=]\\s*)(?:([\"'])(?:\\\\.|(?!\\3)[^\\\\\\r\\n])*\\3|[^\\r\\n]+)/giu\n\nfunction redactUrl(raw: string): string {\n try {\n const url = new URL(raw)\n const port = url.port ? `:${url.port}` : ''\n return `${url.protocol}//${url.hostname}${port}/<redacted>`\n } catch {\n return '<redacted-url>'\n }\n}\n\n/**\n * Strip RPC credentials from text before it is logged or shown. Providers\n * embed keys in the URL path or query, so every URL keeps only its origin;\n * credential header values are masked too.\n */\nexport function redactRpcSecrets(text: string | undefined): string {\n if (!text) return ''\n return text\n .replace(CREDENTIAL_HEADER_PATTERN, '$1$2$3<redacted>$3')\n .replace(URL_PATTERN, redactUrl)\n}\n","import { type RpcProviderName, isRpcProviderName, RPC_PROVIDER_PRESETS } from './providers'\n\nexport type RpcEnv = Readonly<Record<string, string | undefined>>\n\nexport type RpcEndpoint = {\n /** Preset name, or `'url'` for an explicit URL entry. */\n source: RpcProviderName | 'url'\n url: string\n /** Credentials that must accompany every request to `url`, and only to `url`. */\n headers: Record<string, string>\n}\n\nexport type ResolveRpcEndpointsOptions = {\n /** Service-specific URL variables honoured when `RPC_URL_<chainId>` is unset, in order. */\n legacyUrlEnv?: readonly string[]\n /** Presets tried, in order, when no URL is configured. Overridden by `RPC_PROVIDERS`. */\n defaultProviders?: readonly RpcProviderName[]\n}\n\nexport const DEFAULT_RPC_PROVIDERS: readonly RpcProviderName[] = ['alchemy', 'uniblock']\n\nfunction present(value: string | undefined): string | undefined {\n const trimmed = value?.trim()\n return trimmed ? trimmed : undefined\n}\n\nfunction splitList(value: string | undefined): string[] {\n return (value ?? '')\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry !== '')\n}\n\nfunction parseHeaders(value: string | undefined, envName: string): Record<string, string> {\n const headers: Record<string, string> = {}\n for (const pair of splitHeaderPairs(value)) {\n const separator = pair.indexOf(':')\n const name = pair.slice(0, separator).trim()\n if (separator <= 0 || name === '') {\n throw new Error(`${envName} must be \"Name: value\" pairs separated by \";\"`)\n }\n headers[name] = pair.slice(separator + 1).trim()\n }\n return headers\n}\n\nfunction splitHeaderPairs(value: string | undefined): string[] {\n return (value ?? '')\n .split(';')\n .map((pair) => pair.trim())\n .filter((pair) => pair !== '')\n}\n\nfunction isHttpUrl(value: string): boolean {\n try {\n const { protocol } = new URL(value)\n return protocol === 'http:' || protocol === 'https:'\n } catch {\n return false\n }\n}\n\nfunction presetApiKey(name: RpcProviderName, chainId: number, env: RpcEnv) {\n for (const envName of RPC_PROVIDER_PRESETS[name].apiKeyEnv(chainId)) {\n const key = present(env[envName])\n if (key !== undefined) return key\n }\n return undefined\n}\n\nfunction presetEndpoint(\n name: RpcProviderName,\n chainId: number,\n env: RpcEnv,\n): RpcEndpoint | undefined {\n const apiKey = presetApiKey(name, chainId, env)\n if (apiKey === undefined) return undefined\n const endpoint = RPC_PROVIDER_PRESETS[name].endpoint(chainId, apiKey)\n return endpoint && { source: name, url: endpoint.url, headers: endpoint.headers ?? {} }\n}\n\nfunction explicitEndpoints(chainId: number, env: RpcEnv): RpcEndpoint[] {\n const listEnv = `RPC_URL_${chainId}`\n return splitList(env[listEnv]).map((entry, index) => {\n if (isHttpUrl(entry)) {\n const headersEnv = `RPC_HEADERS_${chainId}_${index}`\n return { source: 'url', url: entry, headers: parseHeaders(env[headersEnv], headersEnv) }\n }\n if (!isRpcProviderName(entry)) {\n throw new Error(`${listEnv} entry \"${entry}\" is neither an http(s) URL nor a known provider`)\n }\n const endpoint = presetEndpoint(entry, chainId, env)\n if (endpoint === undefined) {\n const keyEnv = RPC_PROVIDER_PRESETS[entry].apiKeyEnv(chainId).join(' or ')\n throw new Error(\n `${listEnv} lists \"${entry}\", which needs ${keyEnv} and must serve chain ${chainId}`,\n )\n }\n return endpoint\n })\n}\n\nfunction legacyEndpoints(env: RpcEnv, legacyUrlEnv: readonly string[]): RpcEndpoint[] {\n return legacyUrlEnv.flatMap((envName) =>\n splitList(env[envName]).map((url): RpcEndpoint => ({ source: 'url', url, headers: {} })),\n )\n}\n\nfunction firstPresetEndpoint(\n chainId: number,\n env: RpcEnv,\n providers: readonly string[],\n): RpcEndpoint | undefined {\n for (const name of providers) {\n if (!isRpcProviderName(name)) {\n throw new Error(`RPC_PROVIDERS entry \"${name}\" is not a known provider`)\n }\n const endpoint = presetEndpoint(name, chainId, env)\n if (endpoint !== undefined) return endpoint\n }\n return undefined\n}\n\nfunction dedupe(endpoints: RpcEndpoint[]): RpcEndpoint[] {\n const seen = new Set<string>()\n return endpoints.filter((endpoint) => {\n const key = `${endpoint.url}\\n${JSON.stringify(endpoint.headers)}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\n/**\n * Ordered RPC endpoints for `chainId` (primary first, the rest failover):\n *\n * 1. `RPC_URL_<chainId>` — comma-separated URLs and/or preset names; entry `n`\n * gets headers from `RPC_HEADERS_<chainId>_<n>` (\"Name: value;Name: value\").\n * 2. Otherwise the service's legacy URL variables (`legacyUrlEnv`).\n * 3. Otherwise the first preset in `RPC_PROVIDERS` (or `defaultProviders`)\n * that has an API key and serves the chain.\n *\n * Blank values count as unset. Throws when nothing resolves.\n */\nexport function resolveRpcEndpoints(\n chainId: number,\n env: RpcEnv,\n options: ResolveRpcEndpointsOptions = {},\n): RpcEndpoint[] {\n const explicit = explicitEndpoints(chainId, env)\n if (explicit.length > 0) return dedupe(explicit)\n\n const legacyUrlEnv = options.legacyUrlEnv ?? []\n const legacy = legacyEndpoints(env, legacyUrlEnv)\n if (legacy.length > 0) return dedupe(legacy)\n\n const providers = present(env.RPC_PROVIDERS)\n ? splitList(env.RPC_PROVIDERS)\n : (options.defaultProviders ?? DEFAULT_RPC_PROVIDERS)\n const preset = firstPresetEndpoint(chainId, env, providers)\n if (preset !== undefined) return [preset]\n\n const keyEnv = [\n ...new Set(\n providers.flatMap((name) =>\n isRpcProviderName(name) ? RPC_PROVIDER_PRESETS[name].apiKeyEnv(chainId) : [],\n ),\n ),\n ]\n throw new Error(\n `No RPC configured for chain ${chainId}: set ${[`RPC_URL_${chainId}`, ...legacyUrlEnv, ...keyEnv].join(', ')}`,\n )\n}\n","import { type HttpTransportConfig, type Transport, fallback, http } from 'viem'\n\nimport type { RpcEndpoint } from './resolve'\n\nexport type RpcHttpConfig = Omit<HttpTransportConfig, 'fetchOptions'>\n\n/** viem HTTP transport for one endpoint, carrying its credential headers. */\nexport function rpcHttp(endpoint: RpcEndpoint, config: RpcHttpConfig = {}) {\n return http(endpoint.url, { ...config, fetchOptions: { headers: endpoint.headers } })\n}\n\nexport type RpcTransportOptions = RpcHttpConfig & {\n /**\n * Fail over to later endpoints. Disable for clients that submit\n * transactions: a tx broadcast through one provider and retried through\n * another surfaces as \"already known\" / \"nonce too low\" although it was sent.\n */\n failover?: boolean\n}\n\n/**\n * Transport over resolved endpoints: plain HTTP for one endpoint, otherwise an\n * unranked viem `fallback` in configured order.\n */\nexport function rpcTransport(\n endpoints: readonly RpcEndpoint[],\n { failover = true, ...config }: RpcTransportOptions = {},\n): Transport {\n const [primary, ...rest] = endpoints\n if (primary === undefined) throw new Error('rpcTransport needs at least one endpoint')\n if (!failover || rest.length === 0) return rpcHttp(primary, config)\n return fallback(\n endpoints.map((endpoint) => rpcHttp(endpoint, config)),\n { rank: false },\n )\n}\n\n/** anvil fork arguments for the primary endpoint (`--fork-header` only when it needs one). */\nexport function rpcForkArgs(endpoints: readonly RpcEndpoint[]): {\n forkUrl: string\n forkHeader?: string\n} {\n const [primary] = endpoints\n if (primary === undefined) throw new Error('rpcForkArgs needs at least one endpoint')\n const headers = Object.entries(primary.headers)\n if (headers.length === 0) return { forkUrl: primary.url }\n if (headers.length > 1) throw new Error('anvil --fork-header supports one header per fork')\n const [[name, value]] = headers\n return { forkUrl: primary.url, forkHeader: `${name}: ${value}` }\n}\n\n/**\n * Value for a Ponder chain's `rpc`. Header-free endpoints stay plain URLs so\n * Ponder keeps its own load balancing; credential headers need a transport.\n */\nexport function ponderRpc(endpoints: readonly RpcEndpoint[]): string | string[] | Transport {\n if (endpoints.some((endpoint) => Object.keys(endpoint.headers).length > 0)) {\n return rpcTransport(endpoints)\n }\n const urls = endpoints.map((endpoint) => endpoint.url)\n return urls.length === 1 ? urls[0] : urls\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["chainId: number","infuraChains: Record<number, string>","RPC_PROVIDER_PRESETS: Readonly<Record<RpcProviderName, RpcProviderPreset>>","name: string","chainId: AlchemyChainId","alchemyApiKey: string","raw: string","text: string | undefined","DEFAULT_RPC_PROVIDERS: readonly RpcProviderName[]","value: string | undefined","envName: string","headers: Record<string, string>","value: string","name: RpcProviderName","chainId: number","env: RpcEnv","legacyUrlEnv: readonly string[]","providers: readonly string[]","endpoints: RpcEndpoint[]","options: ResolveRpcEndpointsOptions","requestsPerSecond: number","fetchFn: NonNullable<HttpTransportConfig['fetchFn']>","endpoint: RpcEndpoint","config: RpcHttpConfig","endpoints: readonly RpcEndpoint[]"],"sources":["../../src/rpc/providers.ts","../../src/rpc/redact.ts","../../src/rpc/resolve.ts","../../src/rpc/rateLimit.ts","../../src/rpc/transport.ts"],"sourcesContent":["/**\n * The only place that knows RPC vendor URL formats and credentials. Supporting\n * a new vendor means adding one preset here; services select it through env\n * (see `resolveRpcEndpoints`).\n */\n\nexport type RpcProviderPreset = {\n /** Env vars holding the API key for `chainId`, highest precedence first. */\n apiKeyEnv: (chainId: number) => readonly string[]\n /** Endpoint for `chainId`, or undefined when the vendor does not serve it. */\n endpoint: (\n chainId: number,\n apiKey: string,\n ) => { url: string; headers?: Record<string, string> } | undefined\n}\n\nconst alchemyChains = {\n 1: 'eth-mainnet',\n 137: 'polygon-mainnet',\n 42161: 'arb-mainnet',\n 8453: 'base-mainnet',\n 10: 'opt-mainnet',\n 130: 'unichain-mainnet',\n 4663: 'robinhood-mainnet',\n 11155111: 'eth-sepolia',\n} as const\n\nexport type AlchemyChainId = keyof typeof alchemyChains\n\nfunction isAlchemyChainId(chainId: number): chainId is AlchemyChainId {\n return chainId in alchemyChains\n}\n\nconst infuraChains: Record<number, string> = {\n 1: 'mainnet',\n 10: 'optimism-mainnet',\n 137: 'polygon-mainnet',\n 8453: 'base-mainnet',\n 42161: 'arbitrum-mainnet',\n 43114: 'avalanche-mainnet',\n 11155111: 'sepolia',\n}\n\nexport type RpcProviderName = 'alchemy' | 'infura' | 'uniblock'\n\nexport const RPC_PROVIDER_PRESETS: Readonly<Record<RpcProviderName, RpcProviderPreset>> = {\n alchemy: {\n apiKeyEnv: () => ['ALCHEMY_API_KEY'],\n endpoint: (chainId, apiKey) =>\n isAlchemyChainId(chainId)\n ? { url: `https://${alchemyChains[chainId]}.g.alchemy.com/v2/${apiKey}` }\n : undefined,\n },\n infura: {\n apiKeyEnv: () => ['INFURA_API_KEY'],\n endpoint: (chainId, apiKey) =>\n infuraChains[chainId]\n ? { url: `https://${infuraChains[chainId]}.infura.io/v3/${apiKey}` }\n : undefined,\n },\n uniblock: {\n apiKeyEnv: () => ['UNIBLOCK_API_KEY'],\n // Uniblock accepts the key only as a header, and serves keyless requests\n // from an anonymous tier — callers must never send it without one.\n endpoint: (chainId, apiKey) => ({\n url: `https://api.uniblock.dev/uni/v1/json-rpc?chainId=${chainId}`,\n headers: { 'x-api-key': apiKey },\n }),\n },\n}\n\nexport function isRpcProviderName(name: string): name is RpcProviderName {\n return Object.prototype.hasOwnProperty.call(RPC_PROVIDER_PRESETS, name)\n}\n\nexport function getAlchemyRpcUrl(chainId: AlchemyChainId, alchemyApiKey: string): string {\n if (alchemyChains[chainId]) {\n return `https://${alchemyChains[chainId]}.g.alchemy.com/v2/${alchemyApiKey}`\n } else {\n throw new Error(`Unsupported chainId: ${chainId}`)\n }\n}\n\nexport function getAlchemyWsRpcUrl(chainId: AlchemyChainId, alchemyApiKey: string): string {\n if (alchemyChains[chainId]) {\n return `wss://${alchemyChains[chainId]}.g.alchemy.com/v2/${alchemyApiKey}`\n } else {\n throw new Error(`Unsupported chainId: ${chainId}`)\n }\n}\n","const URL_PATTERN = /\\b(?:https?|wss?):\\/\\/[^\\s\"'<>)]+/giu\n// Unquoted authentication values can contain commas and quotes, so mask through the line boundary.\nconst CREDENTIAL_HEADER_PATTERN =\n /\\b(x-api-key|authorization|proxy-authorization)([\"']?\\s*[:=]\\s*)(?:([\"'])(?:\\\\.|(?!\\3)[^\\\\\\r\\n])*\\3|[^\\r\\n]+)/giu\n\nfunction redactUrl(raw: string): string {\n try {\n const url = new URL(raw)\n const port = url.port ? `:${url.port}` : ''\n return `${url.protocol}//${url.hostname}${port}/<redacted>`\n } catch {\n return '<redacted-url>'\n }\n}\n\n/**\n * Strip RPC credentials from text before it is logged or shown. Providers\n * embed keys in the URL path or query, so every URL keeps only its origin;\n * credential header values are masked too.\n */\nexport function redactRpcSecrets(text: string | undefined): string {\n if (!text) return ''\n return text\n .replace(CREDENTIAL_HEADER_PATTERN, '$1$2$3<redacted>$3')\n .replace(URL_PATTERN, redactUrl)\n}\n","import { type RpcProviderName, isRpcProviderName, RPC_PROVIDER_PRESETS } from './providers'\n\nexport type RpcEnv = Readonly<Record<string, string | undefined>>\n\nexport type RpcEndpoint = {\n /** Preset name, or `'url'` for an explicit URL entry. */\n source: RpcProviderName | 'url'\n url: string\n /** Credentials that must accompany every request to `url`, and only to `url`. */\n headers: Record<string, string>\n}\n\nexport type ResolveRpcEndpointsOptions = {\n /** Service-specific URL variables honoured when `RPC_URL_<chainId>` is unset, in order. */\n legacyUrlEnv?: readonly string[]\n /** Presets tried, in order, when no URL is configured. Overridden by `RPC_PROVIDERS`. */\n defaultProviders?: readonly RpcProviderName[]\n}\n\nexport const DEFAULT_RPC_PROVIDERS: readonly RpcProviderName[] = ['alchemy', 'uniblock']\n\nfunction present(value: string | undefined): string | undefined {\n const trimmed = value?.trim()\n return trimmed ? trimmed : undefined\n}\n\nfunction splitList(value: string | undefined): string[] {\n return (value ?? '')\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry !== '')\n}\n\nfunction parseHeaders(value: string | undefined, envName: string): Record<string, string> {\n const headers: Record<string, string> = {}\n for (const pair of splitHeaderPairs(value)) {\n const separator = pair.indexOf(':')\n const name = pair.slice(0, separator).trim()\n if (separator <= 0 || name === '') {\n throw new Error(`${envName} must be \"Name: value\" pairs separated by \";\"`)\n }\n headers[name] = pair.slice(separator + 1).trim()\n }\n return headers\n}\n\nfunction splitHeaderPairs(value: string | undefined): string[] {\n return (value ?? '')\n .split(';')\n .map((pair) => pair.trim())\n .filter((pair) => pair !== '')\n}\n\nfunction isHttpUrl(value: string): boolean {\n try {\n const { protocol } = new URL(value)\n return protocol === 'http:' || protocol === 'https:'\n } catch {\n return false\n }\n}\n\nfunction presetApiKey(name: RpcProviderName, chainId: number, env: RpcEnv) {\n for (const envName of RPC_PROVIDER_PRESETS[name].apiKeyEnv(chainId)) {\n const key = present(env[envName])\n if (key !== undefined) return key\n }\n return undefined\n}\n\nfunction presetEndpoint(\n name: RpcProviderName,\n chainId: number,\n env: RpcEnv,\n): RpcEndpoint | undefined {\n const apiKey = presetApiKey(name, chainId, env)\n if (apiKey === undefined) return undefined\n const endpoint = RPC_PROVIDER_PRESETS[name].endpoint(chainId, apiKey)\n return endpoint && { source: name, url: endpoint.url, headers: endpoint.headers ?? {} }\n}\n\nfunction explicitEndpoints(chainId: number, env: RpcEnv): RpcEndpoint[] {\n const listEnv = `RPC_URL_${chainId}`\n return splitList(env[listEnv]).map((entry, index) => {\n if (isHttpUrl(entry)) {\n const headersEnv = `RPC_HEADERS_${chainId}_${index}`\n return { source: 'url', url: entry, headers: parseHeaders(env[headersEnv], headersEnv) }\n }\n if (!isRpcProviderName(entry)) {\n throw new Error(`${listEnv} entry \"${entry}\" is neither an http(s) URL nor a known provider`)\n }\n const endpoint = presetEndpoint(entry, chainId, env)\n if (endpoint === undefined) {\n const keyEnv = RPC_PROVIDER_PRESETS[entry].apiKeyEnv(chainId).join(' or ')\n throw new Error(\n `${listEnv} lists \"${entry}\", which needs ${keyEnv} and must serve chain ${chainId}`,\n )\n }\n return endpoint\n })\n}\n\nfunction legacyEndpoints(env: RpcEnv, legacyUrlEnv: readonly string[]): RpcEndpoint[] {\n return legacyUrlEnv.flatMap((envName) =>\n splitList(env[envName]).map((url): RpcEndpoint => ({ source: 'url', url, headers: {} })),\n )\n}\n\nfunction firstPresetEndpoint(\n chainId: number,\n env: RpcEnv,\n providers: readonly string[],\n): RpcEndpoint | undefined {\n for (const name of providers) {\n if (!isRpcProviderName(name)) {\n throw new Error(`RPC_PROVIDERS entry \"${name}\" is not a known provider`)\n }\n const endpoint = presetEndpoint(name, chainId, env)\n if (endpoint !== undefined) return endpoint\n }\n return undefined\n}\n\nfunction dedupe(endpoints: RpcEndpoint[]): RpcEndpoint[] {\n const seen = new Set<string>()\n return endpoints.filter((endpoint) => {\n const key = `${endpoint.url}\\n${JSON.stringify(endpoint.headers)}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\n/**\n * Ordered RPC endpoints for `chainId` (primary first, the rest failover):\n *\n * 1. `RPC_URL_<chainId>` — comma-separated URLs and/or preset names; entry `n`\n * gets headers from `RPC_HEADERS_<chainId>_<n>` (\"Name: value;Name: value\").\n * 2. Otherwise the service's legacy URL variables (`legacyUrlEnv`).\n * 3. Otherwise the first preset in `RPC_PROVIDERS` (or `defaultProviders`)\n * that has an API key and serves the chain.\n *\n * Blank values count as unset. Throws when nothing resolves.\n */\nexport function resolveRpcEndpoints(\n chainId: number,\n env: RpcEnv,\n options: ResolveRpcEndpointsOptions = {},\n): RpcEndpoint[] {\n const explicit = explicitEndpoints(chainId, env)\n if (explicit.length > 0) return dedupe(explicit)\n\n const legacyUrlEnv = options.legacyUrlEnv ?? []\n const legacy = legacyEndpoints(env, legacyUrlEnv)\n if (legacy.length > 0) return dedupe(legacy)\n\n const providers = present(env.RPC_PROVIDERS)\n ? splitList(env.RPC_PROVIDERS)\n : (options.defaultProviders ?? DEFAULT_RPC_PROVIDERS)\n const preset = firstPresetEndpoint(chainId, env, providers)\n if (preset !== undefined) return [preset]\n\n const keyEnv = [\n ...new Set(\n providers.flatMap((name) =>\n isRpcProviderName(name) ? RPC_PROVIDER_PRESETS[name].apiKeyEnv(chainId) : [],\n ),\n ),\n ]\n throw new Error(\n `No RPC configured for chain ${chainId}: set ${[`RPC_URL_${chainId}`, ...legacyUrlEnv, ...keyEnv].join(', ')}`,\n )\n}\n","import type { HttpTransportConfig } from 'viem'\n\n/** Limits HTTP attempts, including retries, across clients sharing this fetch function. */\nexport function rateLimitedRpcFetch(\n requestsPerSecond: number,\n fetchFn: NonNullable<HttpTransportConfig['fetchFn']> = fetch,\n): NonNullable<HttpTransportConfig['fetchFn']> {\n if (!Number.isFinite(requestsPerSecond) || requestsPerSecond <= 0) {\n throw new Error('RPC requestsPerSecond must be positive and finite')\n }\n const intervalMs = Math.ceil(1_000 / requestsPerSecond)\n let nextStart = 0\n let tail = Promise.resolve()\n\n return (input, init) => {\n const signal = init?.signal ?? (input instanceof Request ? input.signal : undefined)\n const request = tail.then(async () => {\n signal?.throwIfAborted()\n const delay = nextStart - Date.now()\n if (delay > 0) await new Promise<void>((resolve) => setTimeout(resolve, delay))\n signal?.throwIfAborted()\n nextStart = Date.now() + intervalMs\n return fetchFn(input, init)\n })\n tail = request.then(\n () => undefined,\n () => undefined,\n )\n return request\n }\n}\n","import { type HttpTransportConfig, type Transport, fallback, http } from 'viem'\n\nimport { rateLimitedRpcFetch } from './rateLimit'\nimport type { RpcEndpoint } from './resolve'\n\nexport type RpcHttpConfig = Omit<HttpTransportConfig, 'fetchOptions'>\n\n/** viem HTTP transport for one endpoint, carrying its credential headers. */\nexport function rpcHttp(endpoint: RpcEndpoint, config: RpcHttpConfig = {}) {\n return http(endpoint.url, { ...config, fetchOptions: { headers: endpoint.headers } })\n}\n\nexport type RpcTransportOptions = RpcHttpConfig & {\n /**\n * Fail over to later endpoints. Disable for clients that submit\n * transactions: a tx broadcast through one provider and retried through\n * another surfaces as \"already known\" / \"nonce too low\" although it was sent.\n */\n failover?: boolean\n /** Shared HTTP attempt limit, including retries and failover. Disables HTTP batching. */\n requestsPerSecond?: number\n}\n\n/**\n * Transport over resolved endpoints: plain HTTP for one endpoint, otherwise an\n * unranked viem `fallback` in configured order.\n */\nexport function rpcTransport(\n endpoints: readonly RpcEndpoint[],\n { failover = true, requestsPerSecond, ...config }: RpcTransportOptions = {},\n): Transport {\n const httpConfig =\n requestsPerSecond === undefined\n ? config\n : {\n ...config,\n batch: false as const,\n fetchFn: rateLimitedRpcFetch(requestsPerSecond, config.fetchFn),\n }\n const [primary, ...rest] = endpoints\n if (primary === undefined) throw new Error('rpcTransport needs at least one endpoint')\n if (!failover || rest.length === 0) return rpcHttp(primary, httpConfig)\n return fallback(\n endpoints.map((endpoint) => rpcHttp(endpoint, httpConfig)),\n { rank: false },\n )\n}\n\n/** anvil fork arguments for the primary endpoint (`--fork-header` only when it needs one). */\nexport function rpcForkArgs(endpoints: readonly RpcEndpoint[]): {\n forkUrl: string\n forkHeader?: string\n} {\n const [primary] = endpoints\n if (primary === undefined) throw new Error('rpcForkArgs needs at least one endpoint')\n const headers = Object.entries(primary.headers)\n if (headers.length === 0) return { forkUrl: primary.url }\n if (headers.length > 1) throw new Error('anvil --fork-header supports one header per fork')\n const [[name, value]] = headers\n return { forkUrl: primary.url, forkHeader: `${name}: ${value}` }\n}\n\n/**\n * Value for a Ponder chain's `rpc`. Header-free endpoints stay plain URLs so\n * Ponder keeps its own load balancing; credential headers need a transport.\n */\nexport function ponderRpc(endpoints: readonly RpcEndpoint[]): string | string[] | Transport {\n if (endpoints.some((endpoint) => Object.keys(endpoint.headers).length > 0)) {\n return rpcTransport(endpoints)\n }\n const urls = endpoints.map((endpoint) => endpoint.url)\n return urls.length === 1 ? urls[0] : urls\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ROBINHOOD_CHAIN_ID } from "./chainDeployments-CwnYHCg7.js";
1
+ import { ROBINHOOD_CHAIN_ID } from "./chainDeployments-BGvEeQSH.js";
2
2
  import { hexToBigInt } from "viem";
3
3
  import { estimateFeesPerGas, getBlock, getFeeHistory } from "viem/actions";
4
4
 
@@ -792,7 +792,7 @@ async function getUniswapV3LpPositionState(params) {
792
792
 
793
793
  //#endregion
794
794
  //#region src/uniswap/lpGreeks.ts
795
- const Q96$4 = 1n << 96n;
795
+ const Q96$5 = 1n << 96n;
796
796
  const Q192$5 = 1n << 192n;
797
797
  /**
798
798
  * Compute the token0/token1 amounts backing `liquidity` over `[sqrtA, sqrtB]`
@@ -803,8 +803,8 @@ const Q192$5 = 1n << 192n;
803
803
  function getAmountsForLiquidity(sqrtPriceX96, sqrtRatioAX96, sqrtRatioBX96, liquidity) {
804
804
  const [sqrtA, sqrtB] = sqrtRatioAX96 <= sqrtRatioBX96 ? [sqrtRatioAX96, sqrtRatioBX96] : [sqrtRatioBX96, sqrtRatioAX96];
805
805
  const sqrtC = sqrtPriceX96 < sqrtA ? sqrtA : sqrtPriceX96 > sqrtB ? sqrtB : sqrtPriceX96;
806
- const amount0 = sqrtC < sqrtB ? liquidity * (sqrtB - sqrtC) * Q96$4 / (sqrtC * sqrtB) : 0n;
807
- const amount1 = sqrtC > sqrtA ? liquidity * (sqrtC - sqrtA) / Q96$4 : 0n;
806
+ const amount0 = sqrtC < sqrtB ? liquidity * (sqrtB - sqrtC) * Q96$5 / (sqrtC * sqrtB) : 0n;
807
+ const amount1 = sqrtC > sqrtA ? liquidity * (sqrtC - sqrtA) / Q96$5 : 0n;
808
808
  return {
809
809
  amount0,
810
810
  amount1
@@ -833,7 +833,7 @@ function getLpGreeks(input) {
833
833
  if (assetIndex === 0) {
834
834
  const value$1 = amount1 + amount0 * sqrtP2 / Q192$5;
835
835
  const delta$1 = amount0;
836
- const gamma$1 = inRange ? -(liquidity * sqrtP) / (2n * Q96$4) : 0n;
836
+ const gamma$1 = inRange ? -(liquidity * sqrtP) / (2n * Q96$5) : 0n;
837
837
  return {
838
838
  value: value$1,
839
839
  delta: delta$1,
@@ -842,7 +842,7 @@ function getLpGreeks(input) {
842
842
  }
843
843
  const value = amount0 + amount1 * Q192$5 / sqrtP2;
844
844
  const delta = amount1;
845
- const gamma = inRange ? -(liquidity * Q96$4) / (2n * sqrtP) : 0n;
845
+ const gamma = inRange ? -(liquidity * Q96$5) / (2n * sqrtP) : 0n;
846
846
  return {
847
847
  value,
848
848
  delta,
@@ -1075,6 +1075,9 @@ var NotMarginCalledError = class extends PanopticError {
1075
1075
  */
1076
1076
  var NotEnoughTokensError = class extends PanopticError {
1077
1077
  name = "NotEnoughTokensError";
1078
+ get deficit() {
1079
+ return this.assetsRequested > this.assetBalance ? this.assetsRequested - this.assetBalance : 0n;
1080
+ }
1078
1081
  constructor(tokenAddress, assetsRequested, assetBalance, cause) {
1079
1082
  super(`Not enough tokens: requested=${assetsRequested}, balance=${assetBalance}, token=${tokenAddress}`, cause);
1080
1083
  this.tokenAddress = tokenAddress;
@@ -4764,6 +4767,39 @@ const panopticErrorsAbi = [
4764
4767
  }
4765
4768
  ]
4766
4769
  },
4770
+ {
4771
+ type: "error",
4772
+ name: "NotEnoughTokens",
4773
+ inputs: [
4774
+ {
4775
+ name: "tokenAddress",
4776
+ type: "address"
4777
+ },
4778
+ {
4779
+ name: "account",
4780
+ type: "address"
4781
+ },
4782
+ {
4783
+ name: "assetsRequested",
4784
+ type: "uint256"
4785
+ },
4786
+ {
4787
+ name: "assetBalance",
4788
+ type: "uint256"
4789
+ }
4790
+ ]
4791
+ },
4792
+ {
4793
+ type: "error",
4794
+ name: "ExecuteError",
4795
+ inputs: [{
4796
+ name: "callIndex",
4797
+ type: "uint256"
4798
+ }, {
4799
+ name: "revertData",
4800
+ type: "bytes"
4801
+ }]
4802
+ },
4767
4803
  {
4768
4804
  type: "error",
4769
4805
  name: "NotGuardian",
@@ -4905,7 +4941,7 @@ const errorConstructors = {
4905
4941
  AccountInsolvent: (args, cause) => new AccountInsolventError(args[0], args[1], cause),
4906
4942
  NotMarginCalled: (_args, cause) => new NotMarginCalledError(cause),
4907
4943
  CreateFail: (_args, cause) => new CreateFailError(cause),
4908
- NotEnoughTokens: (args, cause) => new NotEnoughTokensError(args[0], args[1], args[2], cause),
4944
+ NotEnoughTokens: (args, cause) => new NotEnoughTokensError(args[0], args[args.length === 4 ? 2 : 1], args[args.length === 4 ? 3 : 2], cause),
4909
4945
  NotEnoughLiquidityInChunk: (_args, cause) => new NotEnoughLiquidityInChunkError(cause),
4910
4946
  InsufficientCreditLiquidity: (_args, cause) => new InsufficientCreditLiquidityError(cause),
4911
4947
  DepositTooLarge: (_args, cause) => new DepositTooLargeError(cause),
@@ -5295,7 +5331,7 @@ const MAX_UINT256 = (1n << 256n) - 1n;
5295
5331
 
5296
5332
  //#endregion
5297
5333
  //#region src/uniswap/lpDeposit.ts
5298
- const Q96$3 = 1n << 96n;
5334
+ const Q96$4 = 1n << 96n;
5299
5335
  const ceilDiv = (n, d) => (n + d - 1n) / d;
5300
5336
  /** Uniswap mint principal in raw token units, rounded up per leg, plus 5% headroom. */
5301
5337
  function getLpDepositAmounts(ranges, sqrtPriceX96) {
@@ -5311,8 +5347,8 @@ function getLpDepositBreakdown(ranges, sqrtPriceX96) {
5311
5347
  const lower = tickToSqrtPriceX96(BigInt(tickLower));
5312
5348
  const upper = tickToSqrtPriceX96(BigInt(tickUpper));
5313
5349
  const price = sqrtPriceX96 < lower ? lower : sqrtPriceX96 > upper ? upper : sqrtPriceX96;
5314
- amount0 += ceilDiv(liquidity * Q96$3 * (upper - price), upper * price);
5315
- amount1 += ceilDiv(liquidity * (price - lower), Q96$3);
5350
+ amount0 += ceilDiv(liquidity * Q96$4 * (upper - price), upper * price);
5351
+ amount1 += ceilDiv(liquidity * (price - lower), Q96$4);
5316
5352
  }
5317
5353
  const buffer = {
5318
5354
  amount0: ceilDiv(amount0 * 5n, 100n),
@@ -5340,7 +5376,7 @@ function getUnhedgedLpRanges({ tokenId, positionSize, tickSpacing }) {
5340
5376
  const lower = tickToSqrtPriceX96(tickLower);
5341
5377
  const upper = tickToSqrtPriceX96(tickUpper);
5342
5378
  const amount = positionSize * leg.optionRatio;
5343
- const liquidity = leg.asset === 0n ? amount * (lower * upper / Q96$3) / (upper - lower) : amount * Q96$3 / (upper - lower);
5379
+ const liquidity = leg.asset === 0n ? amount * (lower * upper / Q96$4) / (upper - lower) : amount * Q96$4 / (upper - lower);
5344
5380
  return liquidity <= 0n ? [] : [{
5345
5381
  tickLower: Number(tickLower),
5346
5382
  tickUpper: Number(tickUpper),
@@ -5361,7 +5397,7 @@ function getLpPositionFunding(params) {
5361
5397
  });
5362
5398
  const breakdown = getLpDepositBreakdown(ranges, sqrtPriceX96);
5363
5399
  const priceSquared = valuationSqrtPriceX96 * valuationSqrtPriceX96;
5364
- const value = ({ amount0, amount1 }) => quoteTokenIndex === 0 ? amount0 + ceilDiv(amount1 * Q96$3 * Q96$3, priceSquared) : amount1 + ceilDiv(amount0 * priceSquared, Q96$3 * Q96$3);
5400
+ const value = ({ amount0, amount1 }) => quoteTokenIndex === 0 ? amount0 + ceilDiv(amount1 * Q96$4 * Q96$4, priceSquared) : amount1 + ceilDiv(amount0 * priceSquared, Q96$4 * Q96$4);
5365
5401
  const principalInQuote = value(breakdown.principal);
5366
5402
  const totalInQuote = value(breakdown.total);
5367
5403
  return {
@@ -5391,8 +5427,8 @@ function getLpFundingDeposit({ funding, availableInQuote, minimumInQuote = 0n, q
5391
5427
  requiredInQuote,
5392
5428
  shortfallInQuote,
5393
5429
  defaultQuotePercent,
5394
- amount0: quoteTokenIndex === 0 ? quoteAmount : ceilDiv(assetValue * Q96$3 * Q96$3, priceSquared),
5395
- amount1: quoteTokenIndex === 1 ? quoteAmount : ceilDiv(assetValue * priceSquared, Q96$3 * Q96$3)
5430
+ amount0: quoteTokenIndex === 0 ? quoteAmount : ceilDiv(assetValue * Q96$4 * Q96$4, priceSquared),
5431
+ amount1: quoteTokenIndex === 1 ? quoteAmount : ceilDiv(assetValue * priceSquared, Q96$4 * Q96$4)
5396
5432
  };
5397
5433
  }
5398
5434
  /** Largest raw size funded by available collateral, including native-token rounding. */
@@ -5595,6 +5631,10 @@ function summarizeLpPositionHistory(events) {
5595
5631
  };
5596
5632
  }
5597
5633
 
5634
+ //#endregion
5635
+ //#region src/panoptic/v2/greeks/legLiquidity.ts
5636
+ const Q96$3 = 1n << 96n;
5637
+
5598
5638
  //#endregion
5599
5639
  //#region src/panoptic/v2/greeks/positionVolatility.ts
5600
5640
  const Precision$1 = Decimal.clone({ precision: 80 });