{"_id":"@1001-digital/proxies","_rev":"4-251ed4f5a83c1371e9d7c17b166de931","name":"@1001-digital/proxies","dist-tags":{"latest":"0.2.0"},"versions":{"0.0.1":{"name":"@1001-digital/proxies","version":"0.0.1","keywords":["ethereum","proxy","erc-2535","diamond","eip-1967","eip-1167","eip-1822","eip-897","beacon","gnosis-safe","loupe","facets","abi"],"license":"MIT","_id":"@1001-digital/proxies@0.0.1","maintainers":[{"name":"jwahdatehagh","email":"jalil@1001.digital"}],"homepage":"https://github.com/1001-digital/diamonds#readme","bugs":{"url":"https://github.com/1001-digital/diamonds/issues"},"dist":{"shasum":"806f6b9089bca2064b4997b5edba3e470301bb61","tarball":"https://registry.npmjs.org/@1001-digital/proxies/-/proxies-0.0.1.tgz","fileCount":22,"integrity":"sha512-/mEb0Giqa1zoCXW+tNIRvOYxLFFwMkDAj5OyCS/sbiWT6UQpcUyCWtiZHYa6zd4/KKYQPpxM7Zwo2huUw3Lj8w==","signatures":[{"sig":"MEQCICLQY/nv6776WHu+DewbqBIqFrTNSpEdS1N24jlvlmtJAiAybAQTVCIQcJ98lXySUjX+nvctRB05kXsmEaVWIynBPA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69484},"main":"./dist/index.js","type":"module","_from":"file:1001-digital-proxies-0.0.1.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"vite build","changeset":"changeset","test:watch":"vitest"},"_npmUser":{"name":"jwahdatehagh","email":"jalil@1001.digital"},"_resolved":"/tmp/2e60a6e2740168c8be8c2351ffef0126/1001-digital-proxies-0.0.1.tgz","_integrity":"sha512-/mEb0Giqa1zoCXW+tNIRvOYxLFFwMkDAj5OyCS/sbiWT6UQpcUyCWtiZHYa6zd4/KKYQPpxM7Zwo2huUw3Lj8w==","repository":{"url":"git+https://github.com/1001-digital/diamonds.git","type":"git"},"_npmVersion":"11.11.0","description":"Ethereum proxy pattern detection primitives — ERC-2535 diamonds, EIP-1967, EIP-1167, beacon, Safe, EIP-1822, EIP-897. Detect, enrich, compose.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"@noble/hashes":"^1.7.0"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","vitest":"^3.0.0","@changesets/cli":"^2.30.0","vite-plugin-dts":"^4.0.0","@changesets/changelog-github":"^0.6.0"},"_npmOperationalInternal":{"tmp":"tmp/proxies_0.0.1_1776005876694_0.8970875024934697","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@1001-digital/proxies","version":"0.1.0","keywords":["ethereum","proxy","erc-2535","diamond","eip-1967","eip-1167","eip-1822","eip-897","beacon","gnosis-safe","loupe","facets","abi"],"license":"MIT","_id":"@1001-digital/proxies@0.1.0","maintainers":[{"name":"jwahdatehagh","email":"jalil@1001.digital"}],"homepage":"https://github.com/1001-digital/proxies#readme","bugs":{"url":"https://github.com/1001-digital/proxies/issues"},"dist":{"shasum":"eaef1fd56e1c783814405881c38bb9e2a96893cc","tarball":"https://registry.npmjs.org/@1001-digital/proxies/-/proxies-0.1.0.tgz","fileCount":22,"integrity":"sha512-y9lsswLMY7rWnMUGrKKsJu7NTKk7IGg2qCmKWXw5HkUl2ZJk+3019GAEAy1FRRt4M9KtRvUeweBcidr4Vwjuaw==","signatures":[{"sig":"MEUCIDAiz8U3twfsff+iTzvPbBfEjD3MDdXMr0EZVzDyTkUVAiEArgB+1dVbV30/081ie8/a4YbPsMnG7PYrzlrjvECMYuU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":71039},"main":"./dist/index.js","type":"module","_from":"file:1001-digital-proxies-0.1.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"vite build","changeset":"changeset","test:watch":"vitest"},"_npmUser":{"name":"jwahdatehagh","email":"jalil@1001.digital"},"_resolved":"/tmp/a3e04645d353c81476b43508997395af/1001-digital-proxies-0.1.0.tgz","_integrity":"sha512-y9lsswLMY7rWnMUGrKKsJu7NTKk7IGg2qCmKWXw5HkUl2ZJk+3019GAEAy1FRRt4M9KtRvUeweBcidr4Vwjuaw==","repository":{"url":"git+https://github.com/1001-digital/proxies.git","type":"git"},"_npmVersion":"11.11.0","description":"Ethereum proxy pattern detection primitives — ERC-2535 diamonds, EIP-1967, EIP-1167, beacon, Safe, EIP-1822, EIP-897. Detect, enrich, compose.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"@noble/hashes":"^1.7.0"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","vitest":"^3.0.0","@changesets/cli":"^2.30.0","vite-plugin-dts":"^4.0.0","@changesets/changelog-github":"^0.6.0"},"_npmOperationalInternal":{"tmp":"tmp/proxies_0.1.0_1776006692607_0.3561665291123419","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@1001-digital/proxies","version":"0.1.1","keywords":["ethereum","proxy","erc-2535","diamond","eip-1967","eip-1167","eip-1822","eip-897","beacon","gnosis-safe","loupe","facets","abi"],"license":"MIT","_id":"@1001-digital/proxies@0.1.1","maintainers":[{"name":"jwahdatehagh","email":"jalil@1001.digital"}],"homepage":"https://github.com/1001-digital/proxies#readme","bugs":{"url":"https://github.com/1001-digital/proxies/issues"},"dist":{"shasum":"4ddad9a798373bb3567af662530a16723d978667","tarball":"https://registry.npmjs.org/@1001-digital/proxies/-/proxies-0.1.1.tgz","fileCount":22,"integrity":"sha512-T1GAOvFIV+ao7saTmYA4oNNWoXNemooaoBveAOq3J6rX3THsViQUo1jVNikeaD1VP0hmQj3yMFtMW1BGJFuSag==","signatures":[{"sig":"MEUCIQDb4RiU5C8YEcZwntGU2YNJ2lGch5nCWf2Eux8xv7OHzwIgRnXLtbUVIaSMgNowoxUwM+Bwr9Mk+XWFblCmuNo9Mkk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":72812},"main":"./dist/index.js","type":"module","_from":"file:1001-digital-proxies-0.1.1.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"vite build","changeset":"changeset","test:watch":"vitest"},"_npmUser":{"name":"jwahdatehagh","email":"jalil@1001.digital"},"_resolved":"/tmp/f70dc016332b2634ceee22f0380a9ff5/1001-digital-proxies-0.1.1.tgz","_integrity":"sha512-T1GAOvFIV+ao7saTmYA4oNNWoXNemooaoBveAOq3J6rX3THsViQUo1jVNikeaD1VP0hmQj3yMFtMW1BGJFuSag==","repository":{"url":"git+https://github.com/1001-digital/proxies.git","type":"git"},"_npmVersion":"11.11.0","description":"Ethereum proxy pattern detection primitives — ERC-2535 diamonds, EIP-1967, EIP-1167, beacon, Safe, EIP-1822, EIP-897. Detect, enrich, compose.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"@noble/hashes":"^1.7.0"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","vitest":"^3.0.0","@changesets/cli":"^2.30.0","vite-plugin-dts":"^4.0.0","@changesets/changelog-github":"^0.6.0"},"_npmOperationalInternal":{"tmp":"tmp/proxies_0.1.1_1776253331648_0.5544482281855909","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@1001-digital/proxies","version":"0.2.0","description":"Ethereum proxy pattern detection primitives — ERC-2535 diamonds, EIP-1967, EIP-1167, beacon, Safe, EIP-1822, legacy ZeppelinOS, EIP-897. Detect, enrich, compose.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/1001-digital/proxies.git"},"keywords":["ethereum","proxy","erc-2535","diamond","eip-1967","eip-1167","eip-1822","eip-897","zeppelinos","beacon","gnosis-safe","loupe","facets","abi"],"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"main":"./dist/index.js","types":"./dist/index.d.ts","dependencies":{"@noble/hashes":"^1.7.0"},"devDependencies":{"@changesets/changelog-github":"^0.6.0","@changesets/cli":"^2.30.0","vite":"^6.0.0","vite-plugin-dts":"^4.0.0","vitest":"^3.0.0"},"scripts":{"build":"vite build","test":"vitest run","test:watch":"vitest","changeset":"changeset"},"_id":"@1001-digital/proxies@0.2.0","bugs":{"url":"https://github.com/1001-digital/proxies/issues"},"homepage":"https://github.com/1001-digital/proxies#readme","_integrity":"sha512-nAxt+kmQugv5RFZM+qPetSjQUPtsBPNRnlNUQ8iItbPX4NYbaC7MYSkL/631aV3204dTnj5KgfyKwrX/nmM7JA==","_resolved":"/tmp/8bcf8b35d152b1cc59b9ccd02ffd3208/1001-digital-proxies-0.2.0.tgz","_from":"file:1001-digital-proxies-0.2.0.tgz","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-nAxt+kmQugv5RFZM+qPetSjQUPtsBPNRnlNUQ8iItbPX4NYbaC7MYSkL/631aV3204dTnj5KgfyKwrX/nmM7JA==","shasum":"7c2c03702d0f7533758cf5ac317517cad0548ddd","tarball":"https://registry.npmjs.org/@1001-digital/proxies/-/proxies-0.2.0.tgz","fileCount":23,"unpackedSize":77718,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD+RujDN4iXhopZjpGrcKM0D840KexL3aV41Ca+UuOjagIgB46xeWEDIoFC74ENxiFJ+CH+Df5eOlpSrO1ezDfvUUo="}]},"_npmUser":{"name":"jwahdatehagh","email":"jalil@1001.digital"},"directories":{},"maintainers":[{"name":"jwahdatehagh","email":"jalil@1001.digital"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/proxies_0.2.0_1783286009262_0.9263949919026198"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-12T14:57:56.635Z","modified":"2026-07-05T21:13:29.523Z","0.0.1":"2026-04-12T14:57:56.844Z","0.1.0":"2026-04-12T15:11:32.766Z","0.1.1":"2026-04-15T11:42:11.827Z","0.2.0":"2026-07-05T21:13:29.401Z"},"bugs":{"url":"https://github.com/1001-digital/proxies/issues"},"license":"MIT","homepage":"https://github.com/1001-digital/proxies#readme","keywords":["ethereum","proxy","erc-2535","diamond","eip-1967","eip-1167","eip-1822","eip-897","zeppelinos","beacon","gnosis-safe","loupe","facets","abi"],"repository":{"type":"git","url":"git+https://github.com/1001-digital/proxies.git"},"description":"Ethereum proxy pattern detection primitives — ERC-2535 diamonds, EIP-1967, EIP-1167, beacon, Safe, EIP-1822, legacy ZeppelinOS, EIP-897. Detect, enrich, compose.","maintainers":[{"name":"jwahdatehagh","email":"jalil@1001.digital"}],"readme":"# @1001-digital/proxies\n\nEthereum proxy pattern detection primitives for TypeScript — ERC-2535 diamonds, EIP-1967, EIP-1167, beacon, Safe, EIP-1822, legacy ZeppelinOS, EIP-897.\n\nGiven a contract address, resolve where the real code lives: one implementation (plain proxy) or N facets (diamond). Uniform detect → enrich → compose pipeline across all patterns.\n\nNarrow on purpose: this package knows proxy conventions, selectors, and ABIs. Anything richer — Sourcify, NatSpec, repository metadata — is the consumer's concern. Bring your own enricher.\n\n## Who this is for\n\nUse this package when you need a small, composable proxy-resolution layer in:\n\n- explorer and indexer backends\n- contract introspection CLIs\n- ABI fetchers and decoding pipelines\n- developer tooling that needs implementation or facet discovery without owning proxy-specific logic\n\n## What this package is not\n\nThis package intentionally does not try to be:\n\n- a contract metadata SDK\n- a verification or source-code retrieval client\n- a recursive proxy resolver\n- an upgrade history tracker\n- an opinionated registry or indexing layer\n\nIf you need sources, NatSpec, repository metadata, verification status, or custom per-target fields, use `detect()` and own enrichment yourself.\n\n## Install\n\n```bash\npnpm add @1001-digital/proxies\n```\n\n## Usage\n\n### Detect + fetch a proxy\n\n```ts\nimport { createProxies } from '@1001-digital/proxies'\n\nconst proxies = createProxies()\n\nconst result = await proxies.fetch(\n  'https://eth.llamarpc.com',\n  '0xProxyAddress…',\n)\n\nif (result) {\n  console.log(result.pattern)        // 'eip-1967' | 'eip-2535-diamond' | …\n  console.log(result.targets)        // [{ address, selectors?, abi? }, …]\n  console.log(result.compositeAbi)   // undefined — no enricher configured\n}\n```\n\n### Enrich with Sourcify (or anything else)\n\nThe enricher returns each target's ABI. Anything richer (sources, bytecode,\ndocumentation, …) is the consumer's concern — see *Detect and do your own\nenrichment* below.\n\n```ts\nimport { createProxies } from '@1001-digital/proxies'\n\nasync function sourcifyAbi(address: string) {\n  const res = await fetch(\n    `https://sourcify.dev/server/v2/contract/1/${address}?fields=abi`,\n  )\n  if (!res.ok) return null\n  const { abi } = await res.json()\n  return { abi }\n}\n\nconst proxies = createProxies({ enrich: sourcifyAbi })\n\nconst result = await proxies.fetch(\n  'https://eth.llamarpc.com',\n  '0xProxyAddress…',\n)\n\nif (result) {\n  console.log(result.targets[0].abi) // ABI (filtered to selectors for diamonds, full for plain proxies)\n  console.log(result.compositeAbi)   // all target ABIs deduped by selector\n}\n```\n\n### Detect and do your own enrichment\n\nFor richer per-target metadata, use `detect` and own the enrichment step\nend-to-end. `filterAbiBySelectors` and `buildCompositeAbi` remain useful\nprimitives.\n\n```ts\nimport {\n  createProxies,\n  filterAbiBySelectors,\n  buildCompositeAbi,\n} from '@1001-digital/proxies'\n\nconst proxies = createProxies()\nconst raw = await proxies.detect(rpc, address)\n\nif (raw) {\n  const enriched = await Promise.all(raw.targets.map(async t => {\n    const src = await mySource(t.address)\n    return {\n      ...t,\n      abi: src?.abi && t.selectors\n        ? filterAbiBySelectors(src.abi, t.selectors)\n        : src?.abi,\n      metadata: src?.metadata,\n    }\n  }))\n\n  const compositeAbi = buildCompositeAbi(\n    enriched.map(t => t.abi).filter((a): a is unknown[] => !!a),\n  )\n}\n```\n\n### Standalone primitives\n\nAll low-level utilities are exported directly — use them without the factory:\n\n```ts\nimport {\n  detectProxy,\n  detectDiamond,\n  detectEip1967,\n  decodeFacets,\n  computeSelector,\n  canonicalSignature,\n  filterAbiBySelectors,\n  buildCompositeAbi,\n  enrichTargets,\n} from '@1001-digital/proxies'\n\ndecodeFacets('0x…')                            // parse a facets() return value\ncomputeSelector('transfer(address,uint256)')   // '0xa9059cbb'\ncanonicalSignature({ type: 'function', name: 'transfer', inputs: [/*…*/] })\n```\n\n## API\n\n### `createProxies(config?)`\n\nCreates a proxies client.\n\n**Config options:**\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `enrich` | `TargetEnricher` | — | Default per-target enricher. Called with each target address; return `{ abi? }` or `null`. Errors are swallowed per-target. |\n| `fetch` | `typeof fetch` | `globalThis.fetch` | Custom fetch function. |\n\n**Returns** a `ProxiesClient` with:\n\n- **`detect(rpc, address)`** — `Promise<RawProxy | null>`. On-chain probe only.\n- **`fetch(rpc, address, options?)`** — `Promise<Proxy | null>`. Detect, enrich, and compose.\n  - `options.enrich` — per-call enricher (overrides config-level)\n  - `options.enrich = false` — skip enrichment for this call\n\n### Detection\n\n- **`detectProxy(rpc, address, fetchFn)`** — tries all patterns in priority order (`diamond → 1967 → 1967-beacon → 1822 → zeppelinos → 1167 → safe → 897`), returns the first match.\n- **`detectDiamond`** — ERC-165 probe, then `facets()` fallback.\n- **`detectEip1967`** — reads impl slot `0x3608…3bc3`; optionally admin slot.\n- **`detectEip1967Beacon`** — reads beacon slot `0xa3f0…750d`, then `implementation()` on the beacon.\n- **`detectEip1822`** — reads PROXIABLE slot `0xc5f1…f8e2`.\n- **`detectZeppelinOs`** — reads legacy ZeppelinOS slot `keccak256('org.zeppelinos.proxy.implementation')` (`0x7050…f8c3`); optionally admin slot. Pre-EIP-1967 upgradeable proxies — most prominently USDC's `FiatTokenProxy`.\n- **`detectEip1167`** — `eth_getCode`, matches minimal proxy bytecode (`363d3d…bf3`).\n- **`detectGnosisSafe`** — reads storage slot 0.\n- **`detectEip897`** — calls `implementation()` as a last resort.\n\nEach detector returns `null` if the pattern doesn't match; otherwise a `RawProxy`.\n\n### Detection tradeoffs\n\n- **First match wins** — detector order is intentional. If a contract could satisfy multiple heuristics, `detectProxy` returns the first supported pattern in priority order.\n- **Single-hop resolution** — if a resolved implementation is itself a proxy, detection stops there. Beacon remains supported as a defined two-step pattern.\n- **Error isolation** — one failed RPC probe does not poison the full detection pipeline.\n\n### Composition\n\n- **`enrichTargets(targets, enricher | null)`** — applies the enricher to each target; ABIs are filtered to live selectors for diamonds, passed through for plain proxies.\n- **`buildCompositeAbi(abis)`** — pure; dedupes functions/events/errors across ABIs (first-wins).\n\n### Utilities\n\n- **`decodeFacets(hex)`** — pure; decodes `(address, bytes4[])[]` loupe return.\n- **`computeSelector(signature)`** — pure; keccak256-based 4-byte selector.\n- **`canonicalSignature(abiEntry)`** — pure; normalizes tuples/arrays into a signature string.\n- **`filterAbiBySelectors(abi, selectors)`** — pure; keeps non-functions, filters functions by selector.\n- **`ethCall`**, **`ethGetStorageAt`**, **`ethGetCode`** — minimal JSON-RPC helpers.\n\n### Constants\n\n```ts\nSUPPORTS_INTERFACE_SELECTOR      // '0x01ffc9a7'\nDIAMOND_LOUPE_INTERFACE_ID       // '0x48e2b093'\nFACETS_SELECTOR                  // '0x7a0ed627'\nIMPLEMENTATION_SELECTOR          // '0x5c60da1b'\nEIP1967_IMPL_SLOT\nEIP1967_BEACON_SLOT\nEIP1967_ADMIN_SLOT\nEIP1822_PROXIABLE_SLOT\nZEPPELINOS_IMPL_SLOT\nZEPPELINOS_ADMIN_SLOT\nEIP1167_BYTECODE_PREFIX\nEIP1167_BYTECODE_SUFFIX\nZERO_ADDRESS\n```\n\n### Errors\n\n- **`ProxiesError`** — base class.\n- **`ProxiesDecodeError`** — malformed `facets()` return.\n- **`ProxiesFetchError`** — JSON-RPC transport error.\n\nThe client's `detect` and `fetch` methods swallow RPC-layer errors and return\n`null`; only `decodeFacets` (called directly) can throw `ProxiesDecodeError`\non malformed input.\n\n## Shapes\n\n### `ProxyPattern`\n\n```ts\ntype ProxyPattern =\n  | 'eip-2535-diamond'\n  | 'eip-1967'\n  | 'eip-1967-beacon'\n  | 'eip-1822'\n  | 'zeppelinos'\n  | 'eip-1167'\n  | 'gnosis-safe'\n  | 'eip-897'\n```\n\n### `ResolvedTarget`\n\n```ts\n{\n  address: string\n  // undefined = all selectors route here (plain proxy)\n  // defined = diamond facet selector scope\n  selectors?: string[]\n}\n```\n\n### `RawProxy`\n\n```ts\n{\n  pattern: ProxyPattern\n  targets: ResolvedTarget[]   // 1 entry except for diamonds\n  beacon?: string             // only for eip-1967-beacon\n  admin?: string              // for eip-1967 / zeppelinos when admin slot is set\n}\n```\n\n### `EnrichedTarget`\n\n```ts\n{\n  address: string\n  selectors?: string[]\n  abi?: unknown[]\n}\n```\n\n### `Proxy`\n\n```ts\n{\n  pattern: ProxyPattern\n  targets: EnrichedTarget[]\n  beacon?: string\n  admin?: string\n  compositeAbi?: unknown[]   // deduped by selector\n}\n```\n\n### `TargetEnrichment`\n\n```ts\n{ abi?: unknown[] }\n```\n\n### `TargetEnricher`\n\n```ts\ntype TargetEnricher = (address: string) => Promise<TargetEnrichment | null>\n```\n\n## Design notes\n\n- **Narrow scope** — detects patterns and composes ABIs; no opinion on documentation formats or richer per-target metadata.\n- **Dependency-injected enrichment** — the factory wires I/O when you ask; the primitives work offline.\n- **First-wins ABI dedup** — pass the most authoritative ABI first (e.g. main contract → impl, or main diamond → facets).\n- **Single-hop resolution** — if a resolved implementation is itself a proxy, `detectProxy` does not recurse. Beacon stays supported as a defined two-step pattern.\n- **Minimal runtime deps** — only `@noble/hashes` for keccak256.\n\n## Example consumers\n\n- An explorer backend can call `detect()` to resolve a proxy and then enrich targets from Sourcify or an internal cache.\n- A CLI can call `fetch()` to print the detected pattern, target addresses, and a composite ABI for downstream decoding.\n- An indexing pipeline can treat `detectProxy → enrichTargets → buildCompositeAbi` as a reusable normalization step before storage.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}