{"id":49096401,"url":"https://github.com/scopelift/stealth-address-sdk","last_synced_at":"2026-04-20T21:00:51.868Z","repository":{"id":222724862,"uuid":"750544575","full_name":"ScopeLift/stealth-address-sdk","owner":"ScopeLift","description":"⌨️ TypeScript SDK for ERC-5564 Stealth Addresses and ERC-6538 Stealth Meta-Address Registry","archived":false,"fork":false,"pushed_at":"2026-04-20T19:03:57.000Z","size":1099,"stargazers_count":51,"open_issues_count":5,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-04-20T20:16:56.847Z","etag":null,"topics":["erc-5564","erc-6538","ethereum","evm","privacy","stealth-addresses"],"latest_commit_sha":null,"homepage":"https://stealthaddress.dev/SDK/overview","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ScopeLift.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-01-30T20:55:14.000Z","updated_at":"2026-04-20T19:03:41.000Z","dependencies_parsed_at":"2026-03-31T22:03:00.196Z","dependency_job_id":null,"html_url":"https://github.com/ScopeLift/stealth-address-sdk","commit_stats":null,"previous_names":["scopelift/stealth-address-sdk"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/ScopeLift/stealth-address-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScopeLift%2Fstealth-address-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScopeLift%2Fstealth-address-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScopeLift%2Fstealth-address-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScopeLift%2Fstealth-address-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ScopeLift","download_url":"https://codeload.github.com/ScopeLift/stealth-address-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScopeLift%2Fstealth-address-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32065584,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["erc-5564","erc-6538","ethereum","evm","privacy","stealth-addresses"],"created_at":"2026-04-20T21:00:30.861Z","updated_at":"2026-04-20T21:00:51.861Z","avatar_url":"https://github.com/ScopeLift.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stealth Address SDK\n\nThis TypeScript SDK provides tools for working with Ethereum stealth addresses as defined in [EIP-5564](https://eips.ethereum.org/EIPS/eip-5564) and [EIP-6538](https://eips.ethereum.org/EIPS/eip-6538). It aims to offer a comprehensive suite of functionalities for both generating stealth addresses and interacting with stealth transactions.\n\n## Documentation\n\nFor comprehensive documentation and to learn more about stealth addresses, please visit our [official documentation site](https://stealthaddress.dev/).\n\n## Contract Deployments\n\nInformation about contract deployments can be found on the [deployments page](https://stealthaddress.dev/contracts/deployments) of our official documentation site.\n\n## Features\n\n- Generate Ethereum stealth addresses.\n- Compute stealth address private keys.\n- Check stealth address announcements to determine if they are intended for a specific user.\n- Look up the stealth meta address for a registrant\n- Fetch announcements\n- Watch announcements for a user\n- Prepare the payload for announcing stealth address details\n- Prepare the payload for registering a stealth meta-address on someone's behalf\n\n## Installation\n\n```bash\nnpm install @scopelift/stealth-address-sdk\n# or\nyarn add @scopelift/stealth-address-sdk\n# or\nbun install @scopelift/stealth-address-sdk\n```\n\n## Testing\n\nTests default to using your local [anvil](https://book.getfoundry.sh/anvil/) node\n\n```bash\nanvil\nbun run test\n```\n\nAlternatively, run your tests using a fork of your provided (`RPC_URL` in `env`) rpc url\n\n```bash\nbun run anvil-fork\n# run all tests\nbun run test-fork\n# or for a specific file\nbun run test-fork FILE={file path}\n```\n\n## Quick Start\n\n### Generating a Stealth Address\n\n```ts\nimport { generateStealthAddress } from \"@scopelift/stealth-address-sdk\";\n\n// Your stealth meta-address URI\n// Follows the format: \"st:\u003cchain\u003e:\u003cstealthMetaAddress\u003e\", where \u003cchain\u003e is the chain identifier (https://eips.ethereum.org/EIPS/eip-3770#examples) and \u003cstealthMetaAddress\u003e is the stealth meta-address.\nconst stealthMetaAddressURI = \"...\";\n\n// Generate a stealth address using the default scheme (1)\n// To learn more about the initial implementation scheme using SECP256k1, please see the reference here (https://eips.ethereum.org/EIPS/eip-5564)\nconst result = generateStealthAddress({ stealthMetaAddressURI });\n\n// Use the stealth address\nconsole.log(result.stealthAddress);\n```\n\n### Computing Stealth Key\n\n```ts\nimport {\n  computeStealthKey,\n  VALID_SCHEME_ID,\n} from \"@scopelift/stealth-address-sdk\";\n\n// Example inputs\nconst viewingPrivateKey = \"0x...\"; // Viewing private key of the recipient\nconst spendingPrivateKey = \"0x...\"; // Spending private key of the recipient\nconst ephemeralPublicKey = \"0x...\"; // Ephemeral public key from the sender's announcement\nconst schemeId = VALID_SCHEME_ID.SCHEME_ID_1; // Scheme ID, currently only '1' is supported\n\n// Compute the stealth private key\nconst stealthPrivateKey = computeStealthKey({\n  viewingPrivateKey,\n  spendingPrivateKey,\n  ephemeralPublicKey,\n  schemeId,\n});\n```\n\n### Checking Stealth Address Announcements\n\n```ts\nimport {\n  checkStealthAddress,\n  VALID_SCHEME_ID,\n} from \"@scopelift/stealth-address-sdk\";\n\n// Example inputs\nconst ephemeralPublicKey = \"0x...\"; // The ephemeral public key from the announcement\nconst spendingPublicKey = \"0x...\"; // The user's spending public key\nconst userStealthAddress = \"0x...\"; // The user's stealth address\nconst viewingPrivateKey = \"0x...\"; // The user's viewing private key\nconst viewTag = \"0x...\"; // The view tag from the announcement\nconst schemeId = VALID_SCHEME_ID.SCHEME_ID_1; // Scheme ID, currently only '1' is supported\n\n// Check if the announcement is intended for the user\nconst isForUser = checkStealthAddress({\n  ephemeralPublicKey,\n  schemeId,\n  spendingPublicKey,\n  userStealthAddress,\n  viewingPrivateKey,\n  viewTag,\n});\n\nconsole.log(\n  isForUser\n    ? \"Announcement is for the user\"\n    : \"Announcement is not for the user\"\n);\n```\n\n### Fetching announcements, and checking if the associated stealth address is for the user\n\n```ts\nimport {\n  ERC5564_CONTRACT_ADDRESS,\n  VALID_SCHEME_ID,\n  createStealthClient,\n} from \"@scopelift/stealth-address-sdk\";\n\n// Example parameters\nconst chainId = 11155111; // Example chain ID for Sepolia\nconst rpcUrl = process.env.RPC_URL; // Your env rpc url that aligns with the chainId;\nconst fromBlock = BigInt(12345678); // Example ERC5564 announcer contract deploy block for Sepolia, or the block in which the user registered their stealth meta address (as an example)\n\n// Initialize the stealth client\nconst stealthClient = createStealthClient({ chainId, rpcUrl: rpcUrl! });\n\n// Use the address of your calling contract if applicable\nconst caller = \"0xYourCallingContractAddress\";\n\n// Your scheme id\nconst schemeId = BigInt(VALID_SCHEME_ID.SCHEME_ID_1);\n\n// The contract address of the ERC5564Announcer on your target blockchain\n// You can use the provided ERC5564_CONTRACT_ADDRESS get the singleton contract address for a valid chain ID\nconst ERC5564Address = ERC5564_CONTRACT_ADDRESS;\n\nasync function fetchAnnouncementsForUser() {\n  // Example call to getAnnouncements action on the stealth client to get all potential announcements\n  // Use your preferred method to get announcements if different, and\n  // adjust parameters according to your requirements\n  const announcements = await stealthClient.getAnnouncements({\n    ERC5564Address,\n    args: {\n      schemeId,\n      caller,\n      // Additional args for filtering, if necessary\n    },\n    fromBlock, // Optional fromBlock parameter (defaults to 0, which can be slow for many blocks)\n  });\n\n  // Example call to getAnnouncementsForUser action on the stealth client\n  // Adjust parameters according to your requirements\n  const userAnnouncements = await stealthClient.getAnnouncementsForUser({\n    announcements,\n    spendingPublicKey: \"0xUserSpendingPublicKey\",\n    viewingPrivateKey: \"0xUserViewingPrivateKey\",\n  });\n\n  return userAnnouncements;\n}\n```\n\n### Fetching announcements from a subgraph\n\nUse `getAnnouncementsPageUsingSubgraph` when you want deterministic cursor-based\npagination without building raw filter strings yourself.\n\n```ts\nimport { getAnnouncementsPageUsingSubgraph } from \"@scopelift/stealth-address-sdk\";\n\nconst firstPage = await getAnnouncementsPageUsingSubgraph({\n  subgraphUrl: \"https://your-subgraph.example/api\",\n});\n\nconsole.log(firstPage.announcements);\nconsole.log(firstPage.nextCursor); // present only when another page exists\nconsole.log(firstPage.snapshotBlock); // required for every later page in the same scan\n```\n\nScan filters are optional on the initial page.\n\n- `pageSize` defaults to `999`\n- `pageSize` must be between `1` and `999`\n- omitting `fromBlock`, `toBlock`, `schemeId`, and `caller` means no filter\n- the initial page must omit both `cursor` and `snapshotBlock`\n- the SDK resolves `snapshotBlock` on the initial page and returns it\n- every subsequent page must provide both `cursor` and `snapshotBlock`\n\n```ts\nimport { getAnnouncementsPageUsingSubgraph } from \"@scopelift/stealth-address-sdk\";\n\nconst firstPage = await getAnnouncementsPageUsingSubgraph({\n  subgraphUrl: \"https://your-subgraph.example/api\",\n  fromBlock: 12345678,\n  toBlock: 12349999,\n  schemeId: 1n,\n  caller: \"0x1234567890123456789012345678901234567890\",\n  pageSize: 100,\n});\n\nfor (const announcement of firstPage.announcements) {\n  console.log(announcement.transactionHash);\n}\n\nlet cursor = firstPage.nextCursor;\n\nwhile (cursor) {\n  const page = await getAnnouncementsPageUsingSubgraph({\n    subgraphUrl: \"https://your-subgraph.example/api\",\n    fromBlock: 12345678,\n    toBlock: 12349999,\n    schemeId: 1n,\n    caller: \"0x1234567890123456789012345678901234567890\",\n    pageSize: 100,\n    cursor,\n    snapshotBlock: firstPage.snapshotBlock,\n  });\n\n  for (const announcement of page.announcements) {\n    console.log(announcement.transactionHash);\n  }\n\n  cursor = page.nextCursor;\n}\n```\n\nPass the previous page's `nextCursor` and the initial page's `snapshotBlock`\nback into the same bounded query to fetch the next older page deterministically.\nIf `nextCursor` is undefined, you are on the terminal page and no extra probe\nrequest is needed.\n\n`cursor` is pagination position. `snapshotBlock` is consistency. Reuse the same\n`snapshotBlock` for every page in a multi-page scan so each request reads the\nsame frozen subgraph view.\n\nPagination is ordered by subgraph announcement `id` in descending order. The\ncursor is the last returned `id`, reused as an exclusive `id_lt` boundary for\nthe next page, and page queries are pinned to one subgraph block snapshot.\n\n`getAnnouncementsUsingSubgraph` remains available as the legacy eager helper.\nIt preserves the historical `pageSize` behavior for compatibility, while\n`getAnnouncementsPageUsingSubgraph` is the typed cursor-based API.\n\n## License\n\n[MIT](/LICENSE) License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscopelift%2Fstealth-address-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscopelift%2Fstealth-address-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscopelift%2Fstealth-address-sdk/lists"}