Skip to main content
Do not hardcode addresses in your app; read them from the SDK. All bundled addresses come from one generated package, @opaquecash/deployments, which the chain repos emit from their canonical deployment records:
Source of truthGeneratorOutput
ethereum/infra/deployments/*.json + hardhat artifactsnpm run generate in ethereum/infraEVM addresses + contract ABIs
solana/Anchor.toml program tablesnpm run generate in solanaProgram ids + Wormhole core per cluster
A redeploy is therefore a regenerate + rebuild, never a code change. Higher SDK packages (@opaquecash/opaque, uab, stealth-chain-solana, psr-chain) and the reference app all source their addresses from it.

Reading addresses

Most apps use the convenience getters re-exported from @opaquecash/opaque:
import { getChainDeployment, getSolanaDeployment } from "@opaquecash/opaque";

const evm = getChainDeployment(11155111);   // registry, announcer, verifier, tokens
const sol = getSolanaDeployment("devnet");  // program ids as PublicKey
Or read the registry directly (string ids, zero dependencies):
import {
  requireEvmDeployment,
  requireSolanaProgramIds,
  stealthAddressAnnouncerAbi,   // generated ABIs ship here too
} from "@opaquecash/deployments";

const evm = requireEvmDeployment(11155111);
// evm.contracts.{stealthMetaAddressRegistry, uabSender, ...}, evm.wormhole, evm.tokens

const sol = requireSolanaProgramIds("devnet");
// sol.{stealthRegistry, stealthAnnouncer, uabReceiver, wormholeCore, ...}
Override any address per client via OpaqueClient.create({ contracts: { ... } }).

Ethereum Sepolia (chainId: 11155111)

ContractAddress
StealthMetaAddressRegistry0x77425e04163d608B876c7f50E34A378624A12067
StealthAddressAnnouncer0x840f72249A8bF6F10b0eB64412E315efBD730865
UABSender0x872787c0BD1A0C71e6D1be5a144EB044e0CB2069
UABReceiver0x9eF189f7a263F870Cf80f9A89d1349A6AF7b15cF
Wormhole Core Bridge (external)0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78
OpaqueSchemaRegistry0xAA5F3942117bD48E7Cd81A500A8b7Bbb122ae80f
AttestationRegistry (V2)0x049aF9CBB62387034CDd5403794a94E9c000ACCc
OpaqueReputationVerifier (V2)0x18cEc2812953c2E9bcADE20CbF6415BD36aEb44f
Groth16Verifier (V2)0x49A212bdbc52F1cb6C93623FC7814a61Fc71ddB5
OpaqueNameRegistry (ONS, parent opqtest.eth)0x6e18a2faaa929848a3377C28Cf250795E20Fce02
RelayerRegistry (gas-private market)0x5fA252e2D22058a4ec3420573a3B3A5dca025837
OpaquePrivacyPool0x49a5bB6d079a43d50596069b4F2632005CFe729E
WithdrawalVerifier (privacy pool)0xa1add9daa1F4D0f9190c13fb9AD52e525f4726b5
Default tracked tokens: native ETH plus testnet USDC (0x73197e8303904862d543f9706E8422F634D713cb) and USDT (0x6Ff8Afb2aA9eB5A89Ce86c44DD460bD17C92f644). UAB deployment details (Wormhole chain ids, fromBlock): getUabDeployment(11155111) from @opaquecash/opaque.

Solana devnet

ProgramAddress
StealthMetaAddressRegistryE9LBRG5eP2kvuNfveouqQ9tA5P6nrpyLyWFjH9MFYVno
StealthAddressAnnouncerHGFn2fH7bVQ5cSuiG52NjzN9m11YrB3FZUfoN9b9A5jf
SchemaRegistryFbgMJYGWnLKLcrKYS1NxM5uER1ihQkYLMTLs4STuDMWB
AttestationEngineV24T9kPCVCFGdEuLpEqRJihsPCbEEo2LWWDEPFvUESEqtM
Groth16Verifier6mFaKyp7F4NqNeoiBLEWSqy5wJSk7rWf1EYumVXgHvhQ
ReputationVerifierBSnkCDoTpgNVN5BbF3aN5L5EJPiaYUkqqj9MHp8kaqWM
UAB Receiver7d4Sbmmpy954JwSNdjwf31pgbeWUQqwpgNdte5iy3vuM
ONS MirrorD7EXuwcsGrUAYC6k69jrKvsKethsKYgR1pokkTcFvWsk
ONS Registration5gfK9J8FJi3FpsQD33Hkrfwq8KqN4yadB2PDF9REnwMT
relayer-registry (gas-private market)E4xmYaAU31dbNTbhfMfp2F24b48DAxJigvZTVbsKJREg
opaque-privacy-pool5NjweHM4z7NrG4NLVUyJ8rtX8jLM3xtBWAR1wSJZ7vjY
Wormhole Core Bridge (external)3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5
import { getSolanaDeployment } from "@opaquecash/opaque";

const d = getSolanaDeployment("devnet");
console.log(d.schemaRegistry, d.attestationEngineV2);

Supported chain IDs

OpaqueClient.supportedChainIds();  // [11155111] in the current SDK version
Mainnet addresses will land in the same registry when they deploy: the chain repos run npm run generate against the mainnet records, and every consumer picks them up on rebuild.