@utxopia/sdk 0.1.0-alpha.1

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 (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +171 -0
  3. package/package.json +108 -0
  4. package/packages/btc-client/src/esplora-client.ts +153 -0
  5. package/packages/btc-client/src/index.ts +3 -0
  6. package/packages/btc-client/src/op-return.ts +93 -0
  7. package/packages/btc-client/src/types.ts +112 -0
  8. package/packages/sdk/README.md +277 -0
  9. package/packages/sdk/dist/announcement-client.d.ts +64 -0
  10. package/packages/sdk/dist/announcement-client.js +337 -0
  11. package/packages/sdk/dist/auditor-ciphertext.d.ts +72 -0
  12. package/packages/sdk/dist/auditor-ciphertext.js +135 -0
  13. package/packages/sdk/dist/auditor.d.ts +115 -0
  14. package/packages/sdk/dist/auditor.js +292 -0
  15. package/packages/sdk/dist/bitcoin/ika.d.ts +47 -0
  16. package/packages/sdk/dist/bitcoin/ika.js +74 -0
  17. package/packages/sdk/dist/bitcoin/index.d.ts +2 -0
  18. package/packages/sdk/dist/bitcoin/index.js +1 -0
  19. package/packages/sdk/dist/bound-params.d.ts +96 -0
  20. package/packages/sdk/dist/bound-params.js +249 -0
  21. package/packages/sdk/dist/chadbuffer.d.ts +124 -0
  22. package/packages/sdk/dist/chadbuffer.js +405 -0
  23. package/packages/sdk/dist/claim-link.d.ts +30 -0
  24. package/packages/sdk/dist/claim-link.js +50 -0
  25. package/packages/sdk/dist/client.d.ts +233 -0
  26. package/packages/sdk/dist/client.js +416 -0
  27. package/packages/sdk/dist/commitment-tree.d.ts +268 -0
  28. package/packages/sdk/dist/commitment-tree.js +564 -0
  29. package/packages/sdk/dist/config.d.ts +177 -0
  30. package/packages/sdk/dist/config.js +426 -0
  31. package/packages/sdk/dist/core/esplora.d.ts +110 -0
  32. package/packages/sdk/dist/core/esplora.js +187 -0
  33. package/packages/sdk/dist/core/mempool.d.ts +60 -0
  34. package/packages/sdk/dist/core/mempool.js +107 -0
  35. package/packages/sdk/dist/crypto-babyjub.d.ts +105 -0
  36. package/packages/sdk/dist/crypto-babyjub.js +312 -0
  37. package/packages/sdk/dist/crypto-ed25519.d.ts +116 -0
  38. package/packages/sdk/dist/crypto-ed25519.js +235 -0
  39. package/packages/sdk/dist/crypto.d.ts +59 -0
  40. package/packages/sdk/dist/crypto.js +140 -0
  41. package/packages/sdk/dist/event-client.d.ts +64 -0
  42. package/packages/sdk/dist/event-client.js +165 -0
  43. package/packages/sdk/dist/events.d.ts +127 -0
  44. package/packages/sdk/dist/events.js +305 -0
  45. package/packages/sdk/dist/explorer.d.ts +86 -0
  46. package/packages/sdk/dist/explorer.js +197 -0
  47. package/packages/sdk/dist/index.d.ts +61 -0
  48. package/packages/sdk/dist/index.js +216 -0
  49. package/packages/sdk/dist/instructions.d.ts +1125 -0
  50. package/packages/sdk/dist/instructions.js +1760 -0
  51. package/packages/sdk/dist/keys.d.ts +467 -0
  52. package/packages/sdk/dist/keys.js +799 -0
  53. package/packages/sdk/dist/logger.d.ts +10 -0
  54. package/packages/sdk/dist/logger.js +40 -0
  55. package/packages/sdk/dist/magicblock.d.ts +90 -0
  56. package/packages/sdk/dist/magicblock.js +164 -0
  57. package/packages/sdk/dist/merkle.d.ts +82 -0
  58. package/packages/sdk/dist/merkle.js +141 -0
  59. package/packages/sdk/dist/note.d.ts +348 -0
  60. package/packages/sdk/dist/note.js +483 -0
  61. package/packages/sdk/dist/pda.d.ts +160 -0
  62. package/packages/sdk/dist/pda.js +384 -0
  63. package/packages/sdk/dist/pool-state.d.ts +100 -0
  64. package/packages/sdk/dist/pool-state.js +126 -0
  65. package/packages/sdk/dist/poseidon.d.ts +53 -0
  66. package/packages/sdk/dist/poseidon.js +136 -0
  67. package/packages/sdk/dist/prover/index.d.ts +10 -0
  68. package/packages/sdk/dist/prover/index.js +10 -0
  69. package/packages/sdk/dist/prover/mobile.d.ts +45 -0
  70. package/packages/sdk/dist/prover/mobile.js +227 -0
  71. package/packages/sdk/dist/prover/web.d.ts +136 -0
  72. package/packages/sdk/dist/prover/web.js +597 -0
  73. package/packages/sdk/dist/psbt.d.ts +73 -0
  74. package/packages/sdk/dist/psbt.js +202 -0
  75. package/packages/sdk/dist/selective-disclosure.d.ts +181 -0
  76. package/packages/sdk/dist/selective-disclosure.js +172 -0
  77. package/packages/sdk/dist/sender-memo.d.ts +149 -0
  78. package/packages/sdk/dist/sender-memo.js +250 -0
  79. package/packages/sdk/dist/sns-resolver.d.ts +121 -0
  80. package/packages/sdk/dist/sns-resolver.js +229 -0
  81. package/packages/sdk/dist/solana/connection.d.ts +77 -0
  82. package/packages/sdk/dist/solana/connection.js +133 -0
  83. package/packages/sdk/dist/solana/priority-fee.d.ts +78 -0
  84. package/packages/sdk/dist/solana/priority-fee.js +137 -0
  85. package/packages/sdk/dist/stealth.d.ts +429 -0
  86. package/packages/sdk/dist/stealth.js +703 -0
  87. package/packages/sdk/dist/taproot.d.ts +172 -0
  88. package/packages/sdk/dist/taproot.js +494 -0
  89. package/packages/sdk/dist/token-registry.d.ts +96 -0
  90. package/packages/sdk/dist/token-registry.js +122 -0
  91. package/packages/sdk/dist/utils/encoding.d.ts +19 -0
  92. package/packages/sdk/dist/utils/encoding.js +29 -0
  93. package/packages/sdk/dist/vk-registry.d.ts +100 -0
  94. package/packages/sdk/dist/vk-registry.js +212 -0
@@ -0,0 +1,177 @@
1
+ /**
2
+ * UTXOPIA SDK Configuration
3
+ *
4
+ * Centralized configuration for all network-specific addresses, endpoints, and settings.
5
+ * This is the SINGLE SOURCE OF TRUTH for all on-chain addresses and configuration.
6
+ *
7
+ * When deploying to a new network or updating addresses:
8
+ * 1. Update the relevant network config below
9
+ * 2. Bump SDK version
10
+ * 3. Publish to npm
11
+ *
12
+ * @module config
13
+ */
14
+ import { type Address } from "@solana/kit";
15
+ /**
16
+ * Safe address wrapper — catches codec validation errors that occur during
17
+ * Vercel's build phase when @solana/kit validates byte lengths at module load.
18
+ * Returns the input string cast as Address on failure (safe for config objects
19
+ * that are only used at runtime, not build time).
20
+ */
21
+ export declare function address(input: string): Address;
22
+ export type NetworkType = "devnet" | "mainnet" | "localnet";
23
+ export type AppNetworkId = NetworkType | "devnet-regtest";
24
+ export interface NetworkConfig {
25
+ /** Network identifier */
26
+ network: NetworkType;
27
+ /** UTXOpia main program ID */
28
+ utxopiaProgramId: Address;
29
+ /** Minimal PER PolicyApproval coprocessor. Falls back to the asset program on older networks. */
30
+ policyProgramId?: Address;
31
+ /** BTC Light Client program ID (manages light client + block headers for SPV) */
32
+ btcLightClientProgramId: Address;
33
+ /** ChadBuffer program ID (for SPV verification) */
34
+ chadbufferProgramId: Address;
35
+ /** Token-2022 program ID */
36
+ token2022ProgramId: Address;
37
+ /** Associated Token Account program ID */
38
+ ataProgramId: Address;
39
+ /** Pool State PDA address */
40
+ poolStatePda: Address;
41
+ /** Commitment Tree PDA address */
42
+ commitmentTreePda: Address;
43
+ /** zkBTC Mint address (Token-2022) */
44
+ zkbtcMint: Address;
45
+ /** Pool Vault (ATA for pool holding zkBTC) */
46
+ poolVault: Address;
47
+ /** Solana RPC endpoint */
48
+ solanaRpcUrl: string;
49
+ /** Solana WebSocket endpoint */
50
+ solanaWsUrl: string;
51
+ /** Bitcoin network */
52
+ bitcoinNetwork: "mainnet" | "testnet" | "testnet4" | "signet" | "regtest";
53
+ /** Esplora API endpoint */
54
+ esploraUrl: string;
55
+ /** Base URL for circuit artifacts */
56
+ circuitCdnUrl: string;
57
+ /** Groth16 verifier program ID (browser proof generation via snarkjs) */
58
+ groth16VerifierProgramId: Address;
59
+ /** VK hashes for each circuit type (32 bytes each, hex-encoded) */
60
+ vkHashes: {
61
+ claim: string;
62
+ split: string;
63
+ spendPartialPublic: string;
64
+ };
65
+ /** VK hashes for JoinSplit variants, keyed by "NxM" (e.g., "1x2" -> "abc...") */
66
+ joinSplitVkHashes: Record<string, string>;
67
+ /** Ika dWallet x-only secp256k1 pubkey (hex, 64 chars = 32 bytes).
68
+ * The sole Taproot internal key for deposit-address derivation. Read from
69
+ * `pool_config.ika_dwallet_xonly_pubkey` (offset 68..100) on chain. All-zero
70
+ * indicates the pool's PoolConfig has not been initialized yet. */
71
+ ikaDwalletXOnlyPubkey: string;
72
+ /** BTC deposit custody mode.
73
+ * "sweep" keeps legacy per-deposit tweaked Taproot addresses.
74
+ * "direct" sends deposits directly to the Ika raw x-only vault address. */
75
+ depositMode?: "sweep" | "direct" | "direct_vault" | "ika_direct";
76
+ /** SPL Name Service program ID (stores name records / PDAs) */
77
+ snsNameServiceProgramId: string;
78
+ /** SNS Registrar program ID (for domain registration) */
79
+ snsRegistrarProgramId: string;
80
+ /** SNS Sub-Registrar program ID (for subdomain registration) */
81
+ snsSubRegistrarProgramId: string;
82
+ /** SNS root domain account (.sol TLD — differs per network) */
83
+ snsRootDomain: string;
84
+ /** Parent domain for stealth address subdomains (e.g., "utxopia" for *.utxopia.sol) */
85
+ snsParentDomain: string;
86
+ /** SNS reverse lookup class key (used for reverse name resolution) */
87
+ snsReverseLookupClass: string;
88
+ /** Stealth data version expected in SNS records */
89
+ snsStealthDataVersion: number;
90
+ }
91
+ /** Legacy Token Program ID */
92
+ export declare const TOKEN_PROGRAM_ID: Address;
93
+ /** Token-2022 Program ID */
94
+ export declare const TOKEN_2022_PROGRAM_ID: Address;
95
+ /** Associated Token Account Program ID */
96
+ export declare const ATA_PROGRAM_ID: Address;
97
+ /** ChadBuffer Program ID (deployed to devnet 2025-01-30) */
98
+ export declare const CHADBUFFER_PROGRAM_ID: Address;
99
+ /** ChadBuffer Program ID for localnet testing */
100
+ export declare const LOCALNET_CHADBUFFER_PROGRAM_ID: Address;
101
+ /**
102
+ * Fresh multi-pool devnet deployment (2026-07-26).
103
+ * The default domain is public; institution pools are selected explicitly.
104
+ */
105
+ export declare const DEVNET_CONFIG: NetworkConfig;
106
+ /**
107
+ * Mainnet Configuration (placeholder - not yet deployed)
108
+ */
109
+ export declare const MAINNET_CONFIG: NetworkConfig;
110
+ /**
111
+ * Localnet Configuration (for local development)
112
+ * Synced with .localnet-config.json (2026-02-22)
113
+ */
114
+ export declare const LOCALNET_CONFIG: NetworkConfig;
115
+ /**
116
+ * Get the current network configuration.
117
+ * Respects NEXT_PUBLIC_BTC_NETWORK env var to override Bitcoin network
118
+ * (e.g., "testnet" for testnet3, "testnet4" for testnet4).
119
+ */
120
+ export declare function getConfig(): NetworkConfig;
121
+ /**
122
+ * Set the network configuration
123
+ *
124
+ * @param network - Network type or custom config
125
+ * @throws Error if mainnet is selected (not yet deployed)
126
+ */
127
+ export declare function setConfig(network: AppNetworkId | NetworkConfig): void;
128
+ /**
129
+ * Create a custom configuration by overriding specific values
130
+ *
131
+ * @param base - Base configuration to extend
132
+ * @param overrides - Values to override
133
+ */
134
+ export declare function createConfig(base: NetworkConfig, overrides: Partial<NetworkConfig>): NetworkConfig;
135
+ /**
136
+ * Initialize SDK configuration with optional overrides.
137
+ *
138
+ * Reads `utxopiaProgramId` and `zkbtcMint` from params, then env vars, then
139
+ * falls back to DEVNET_CONFIG defaults. All PDAs are auto-derived from these
140
+ * two values.
141
+ *
142
+ * Env vars checked (in order):
143
+ * - NEXT_PUBLIC_UTXOPIA_PROGRAM_ID / UTXOPIA_PROGRAM_ID
144
+ * - NEXT_PUBLIC_ZKBTC_MINT / UTXOPIA_ZKBTC_MINT
145
+ *
146
+ * @example
147
+ * // Use env vars (set NEXT_PUBLIC_UTXOPIA_PROGRAM_ID + NEXT_PUBLIC_ZKBTC_MINT)
148
+ * await initConfig();
149
+ *
150
+ * // Or pass explicitly
151
+ * await initConfig({ utxopiaProgramId: "...", zkbtcMint: "..." });
152
+ */
153
+ export type NetworkId = AppNetworkId;
154
+ export declare function initConfig(overrides?: {
155
+ network?: NetworkId;
156
+ utxopiaProgramId?: string;
157
+ policyProgramId?: string;
158
+ zkbtcMint?: string;
159
+ solanaRpcUrl?: string;
160
+ ikaDwalletXOnlyPubkey?: string;
161
+ depositMode?: "sweep" | "direct" | "direct_vault" | "ika_direct";
162
+ }): Promise<NetworkConfig>;
163
+ /** Default UTXOpia program ID (from current config) */
164
+ export declare const UTXOPIA_PROGRAM_ID: Address;
165
+ export declare const UTXOPIA_POLICY_PROGRAM_ID: Address;
166
+ /** BTC Light Client program ID (manages light client + block headers) */
167
+ export declare const BTC_LIGHT_CLIENT_PROGRAM_ID: Address;
168
+ export declare const SDK_VERSION = "3.3.0";
169
+ /** JoinSplit Merkle tree depth */
170
+ export declare const JOINSPLIT_TREE_DEPTH = 16;
171
+ export declare const DEPLOYMENT_INFO: {
172
+ version: string;
173
+ deployedAt: string;
174
+ network: NetworkType;
175
+ features: string[];
176
+ notes: string;
177
+ };
@@ -0,0 +1,426 @@
1
+ /**
2
+ * UTXOPIA SDK Configuration
3
+ *
4
+ * Centralized configuration for all network-specific addresses, endpoints, and settings.
5
+ * This is the SINGLE SOURCE OF TRUTH for all on-chain addresses and configuration.
6
+ *
7
+ * When deploying to a new network or updating addresses:
8
+ * 1. Update the relevant network config below
9
+ * 2. Bump SDK version
10
+ * 3. Publish to npm
11
+ *
12
+ * @module config
13
+ */
14
+ import { address as _address, getAddressEncoder, getProgramDerivedAddress } from "@solana/kit";
15
+ /**
16
+ * Safe address wrapper — catches codec validation errors that occur during
17
+ * Vercel's build phase when @solana/kit validates byte lengths at module load.
18
+ * Returns the input string cast as Address on failure (safe for config objects
19
+ * that are only used at runtime, not build time).
20
+ */
21
+ export function address(input) {
22
+ try {
23
+ return _address(input);
24
+ }
25
+ catch {
26
+ console.warn(`[utxopia-sdk] address() failed for "${input.slice(0, 12)}..." — returning raw string (build-time fallback)`);
27
+ return input;
28
+ }
29
+ }
30
+ // =============================================================================
31
+ // Program IDs (Constants)
32
+ // =============================================================================
33
+ /** Legacy Token Program ID */
34
+ export const TOKEN_PROGRAM_ID = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
35
+ /** Token-2022 Program ID */
36
+ export const TOKEN_2022_PROGRAM_ID = address("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb");
37
+ /** Associated Token Account Program ID */
38
+ export const ATA_PROGRAM_ID = address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
39
+ /** ChadBuffer Program ID (deployed to devnet 2025-01-30) */
40
+ export const CHADBUFFER_PROGRAM_ID = address("C5RpjtTMFXKVZCtXSzKXD4CDNTaWBg3dVeMfYvjZYHDF");
41
+ /** ChadBuffer Program ID for localnet testing */
42
+ export const LOCALNET_CHADBUFFER_PROGRAM_ID = address("EgWyMVFZewHmjJ9GGvVBTyaC376Xp7qu7CAFjWYPYYDv");
43
+ // =============================================================================
44
+ // Network Configurations
45
+ // =============================================================================
46
+ /**
47
+ * Fresh multi-pool devnet deployment (2026-07-26).
48
+ * The default domain is public; institution pools are selected explicitly.
49
+ */
50
+ export const DEVNET_CONFIG = {
51
+ network: "devnet",
52
+ utxopiaProgramId: address("CvfSyACR8xemPdeJsB3D8Xh15rKUQ3b5c1PvnmABCBJp"),
53
+ policyProgramId: address("9asWYKVriWGpExW5xM44ChHjZtispkLCiWKkM8SQi8Rs"),
54
+ btcLightClientProgramId: address("859B7kw1xDyY8rzSXY6pAPNxaAsPWrsaAPJk3iivd43g"),
55
+ chadbufferProgramId: CHADBUFFER_PROGRAM_ID,
56
+ token2022ProgramId: TOKEN_2022_PROGRAM_ID,
57
+ ataProgramId: ATA_PROGRAM_ID,
58
+ poolStatePda: address("9xeWc39r3Z176MUpMpaqCGJGneHMj4pfMRv9u6dp2Qgd"),
59
+ commitmentTreePda: address("4FvM9dCzDvr39Xu5xRUQc6EEm3UjSikyWUY5Hzpc5C4A"),
60
+ zkbtcMint: address("GuruxfN5irYcCyDiKFMeDRTNbP2WeHF1oWjQ8q8Esc16"),
61
+ poolVault: address("3GffHxesFsGj4QmgQ8ozs17dZFNTv4AAhdwyR2XZPzkm"),
62
+ // RPC Endpoints
63
+ solanaRpcUrl: "https://api.devnet.solana.com",
64
+ solanaWsUrl: "wss://api.devnet.solana.com",
65
+ // Bitcoin Network
66
+ bitcoinNetwork: "testnet4",
67
+ esploraUrl: "https://mempool.space/testnet4/api",
68
+ // Circuit CDN (Groth16 artifacts: .wasm, .zkey files)
69
+ circuitCdnUrl: "https://circuit.utxopia.com/circuits/v2/groth16",
70
+ // Groth16 Verifier: verification is inline in the UTXOpia program (no separate verifier program)
71
+ groth16VerifierProgramId: address("AjbX243s2JMFG2uhfTjKkadjPvQEPgcuyV3vfLJv36MT"), // inline in utxopia program
72
+ // VK Hashes (SHA256 of serialized VK bytes, generated from circom trusted setup)
73
+ vkHashes: {
74
+ claim: "7af0e702e7b595fbdb62fd268e6c529481003e07957e0f60e4fb23cd9fe6a77f",
75
+ split: "00fb9e4c3fcc7b99fec5191370b516537f74831ad868a18c4ab2d519f332cc4f",
76
+ spendPartialPublic: "732126aaec8355efdfb1b96aee1c9014506c99815a81057edbefd775b1b10663",
77
+ },
78
+ // JoinSplit VK hashes (populated after trusted setup for new circuits)
79
+ joinSplitVkHashes: {
80
+ "1x1": "745d536fb3a86424ee9560cb7b630bb0eb3d3c3af06c85bcda1eb7bcc5b1a07a",
81
+ "1x2": "f782d4bc2f696417688cdec3cb4f822d6961892192e13e8842505bd8d119fa6d",
82
+ "2x1": "3af6cdad3c1f4de9e088975a1ac5b20e0445d7f3fea0a5038f300102cf98fd98",
83
+ "2x2": "6fffc4962028d0ac69f4d7877badc9f5adea4b83e6224ebb8db22657e847e7b8",
84
+ "1x3": "ca396f36bbd1b07255b7a2f5585cedb4a51f925149747dd6ab4f695d19aa6ff8",
85
+ "3x1": "4e0c5cbea0ccf80302d2589e41a2f22e19287f5acc5d0577451680fd909e1942",
86
+ "2x3": "bf398583f064de96560cb9092b1357b0d742991a88f18a351e5b8793fed4b7a7",
87
+ "3x2": "9da8d33d57896e76aadf3f5c66295774bd3273511af6e733ca7f9446ab58d42e",
88
+ "1x4": "01728b82e810a8ba604cc66aa6a563444d18f4598c402d11767d0a7e5049a9be",
89
+ "4x1": "0362b306b17dae916d836d9448a26c97e51b1b0a1a0ed052ebfbd4800e5000cf",
90
+ },
91
+ // Ika dWallet x-only pubkey — populated by ./scripts/sync-env.sh from devnet-state.json.
92
+ ikaDwalletXOnlyPubkey: "0000000000000000000000000000000000000000000000000000000000000000",
93
+ // SNS Subdomain Resolution (devnet)
94
+ snsNameServiceProgramId: "namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX", // SPL Name Service (devnet)
95
+ snsRegistrarProgramId: "snshBoEQ9jx4QoHBpZDQPYdNCtw7RMxJvYrKFEhwaPJ", // SNS Registrar (devnet)
96
+ snsSubRegistrarProgramId: "31tT5CmpphAtRL3mstu962zeYH7C6TEkJWLB5nYxciBB", // Sub-Registrar (devnet)
97
+ snsRootDomain: "5eoDkP6vCQBXqDV9YN2NdUs3nmML3dMRNmEYpiyVNBm2", // .sol TLD (devnet)
98
+ snsParentDomain: "utxopia",
99
+ snsReverseLookupClass: "7NbD1vprif6apthEZAqhRfYuhrqnuderB8qpnfXGCc8H", // Reverse lookup class (devnet)
100
+ snsStealthDataVersion: 1,
101
+ };
102
+ /**
103
+ * Mainnet Configuration (placeholder - not yet deployed)
104
+ */
105
+ export const MAINNET_CONFIG = {
106
+ network: "mainnet",
107
+ // Program IDs (placeholder - update when deployed)
108
+ utxopiaProgramId: address("11111111111111111111111111111111"),
109
+ btcLightClientProgramId: address("11111111111111111111111111111111"),
110
+ chadbufferProgramId: CHADBUFFER_PROGRAM_ID,
111
+ token2022ProgramId: TOKEN_2022_PROGRAM_ID,
112
+ ataProgramId: ATA_PROGRAM_ID,
113
+ // Deployed Accounts (placeholder - update when deployed)
114
+ poolStatePda: address("11111111111111111111111111111111"),
115
+ commitmentTreePda: address("11111111111111111111111111111111"),
116
+ zkbtcMint: address("11111111111111111111111111111111"),
117
+ poolVault: address("11111111111111111111111111111111"),
118
+ // RPC Endpoints
119
+ solanaRpcUrl: "https://api.mainnet-beta.solana.com",
120
+ solanaWsUrl: "wss://api.mainnet-beta.solana.com",
121
+ // Bitcoin Network
122
+ bitcoinNetwork: "mainnet",
123
+ esploraUrl: "https://mempool.space/api",
124
+ // Circuit CDN
125
+ circuitCdnUrl: "https://circuit.utxopia.com",
126
+ // Groth16 Verifier (placeholder)
127
+ groth16VerifierProgramId: address("11111111111111111111111111111111"),
128
+ // VK Hashes (placeholder - update when deployed)
129
+ vkHashes: {
130
+ claim: "0000000000000000000000000000000000000000000000000000000000000000",
131
+ split: "0000000000000000000000000000000000000000000000000000000000000000",
132
+ spendPartialPublic: "171daac7e5ff45e2d0e736ac0d28f5fe8e0cc8fc9961efa4dd9ee18e4413f755",
133
+ },
134
+ joinSplitVkHashes: {},
135
+ ikaDwalletXOnlyPubkey: "0000000000000000000000000000000000000000000000000000000000000000",
136
+ // SNS Subdomain Resolution (mainnet)
137
+ snsNameServiceProgramId: "namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX", // SPL Name Service (mainnet)
138
+ snsRegistrarProgramId: "jCebN34bUfdeUYJT13J1yG16XWQpt5PDx6Mse9GUqhR", // SNS Registrar (mainnet)
139
+ snsSubRegistrarProgramId: "2KkyPzjaAYaz2ojQZ9P3xYakLd96B5UH6a2isLaZ4Cgs", // Sub-Registrar (mainnet)
140
+ snsRootDomain: "58PwtjSDuFHuUkYjH9BYod9SZaELfsvdrNMryy9iYNvo", // .sol TLD (mainnet)
141
+ snsParentDomain: "utxopia",
142
+ snsReverseLookupClass: "33m47vH6Eav6jr5Ry86XjhRft2jRBLDnDgPSHoquXi2Z", // Reverse lookup class (mainnet)
143
+ snsStealthDataVersion: 1,
144
+ };
145
+ /**
146
+ * Localnet Configuration (for local development)
147
+ * Synced with .localnet-config.json (2026-02-22)
148
+ */
149
+ export const LOCALNET_CONFIG = {
150
+ network: "localnet",
151
+ // Program IDs
152
+ utxopiaProgramId: address("2dBmKyfLibkqdxgyEWUhHos3g56oU2wXLVrucY2dCpGV"),
153
+ btcLightClientProgramId: address("Ho6UTeF8yFnRdCK15tSZtcJozvkDABJZWYxkgGyWAfyq"),
154
+ chadbufferProgramId: LOCALNET_CHADBUFFER_PROGRAM_ID,
155
+ token2022ProgramId: TOKEN_2022_PROGRAM_ID,
156
+ ataProgramId: ATA_PROGRAM_ID,
157
+ // Deployed Accounts (synced with .localnet-config.json 2026-02-23)
158
+ poolStatePda: address("E6DVestxC5dn5ixvLa3FcYodcVtwUAyanpVPbs4y3p16"),
159
+ commitmentTreePda: address("JCiGqC1a1rjfqk2dqcybU2e3FQjAQ19x8ts9fQCtTFCq"),
160
+ zkbtcMint: address("CHg1f85uxw4HrVkj3ianLezVAJTv29VcCWiBxjZ4YFdF"),
161
+ poolVault: address("7vpuYKngG75Km1bbZ5TZJZzRn2BBtkh9BaqPS814tPLg"),
162
+ // RPC Endpoints
163
+ solanaRpcUrl: "http://127.0.0.1:8899",
164
+ solanaWsUrl: "ws://127.0.0.1:8900",
165
+ // Bitcoin Network (regtest for local dev)
166
+ bitcoinNetwork: "regtest",
167
+ esploraUrl: "http://localhost:2140",
168
+ // Circuit CDN (use local files for development)
169
+ circuitCdnUrl: "/circuits",
170
+ // Groth16 Verifier: verification is inline in the UTXOpia program
171
+ groth16VerifierProgramId: address("RoqAPQgZ5ztdhV3jHBKgTmeLBAfyYcaBsjKiXHNwXf3"),
172
+ // VK Hashes (same as devnet - generated from same trusted setup)
173
+ vkHashes: {
174
+ claim: "7af0e702e7b595fbdb62fd268e6c529481003e07957e0f60e4fb23cd9fe6a77f",
175
+ split: "00fb9e4c3fcc7b99fec5191370b516537f74831ad868a18c4ab2d519f332cc4f",
176
+ spendPartialPublic: "732126aaec8355efdfb1b96aee1c9014506c99815a81057edbefd775b1b10663",
177
+ },
178
+ joinSplitVkHashes: {
179
+ "1x1": "745d536fb3a86424ee9560cb7b630bb0eb3d3c3af06c85bcda1eb7bcc5b1a07a",
180
+ "1x2": "f782d4bc2f696417688cdec3cb4f822d6961892192e13e8842505bd8d119fa6d",
181
+ "2x1": "3af6cdad3c1f4de9e088975a1ac5b20e0445d7f3fea0a5038f300102cf98fd98",
182
+ "2x2": "6fffc4962028d0ac69f4d7877badc9f5adea4b83e6224ebb8db22657e847e7b8",
183
+ },
184
+ // Ika dWallet x-only pubkey — populated by ./scripts/sync-env.sh from localnet-state.json.
185
+ ikaDwalletXOnlyPubkey: "0000000000000000000000000000000000000000000000000000000000000000",
186
+ // SNS Subdomain Resolution (not available on localnet)
187
+ snsNameServiceProgramId: "",
188
+ snsRegistrarProgramId: "",
189
+ snsSubRegistrarProgramId: "",
190
+ snsRootDomain: "",
191
+ snsParentDomain: "",
192
+ snsReverseLookupClass: "",
193
+ snsStealthDataVersion: 1,
194
+ };
195
+ // =============================================================================
196
+ // Default Configuration
197
+ // =============================================================================
198
+ /** Current active configuration (defaults to devnet, overridden by env vars) */
199
+ let currentConfig = DEVNET_CONFIG;
200
+ // Eagerly apply env var overrides synchronously (program ID + mint only).
201
+ // PDA derivation happens async in initConfig(), but at least getConfig()
202
+ // returns the correct program ID immediately.
203
+ if (typeof process !== "undefined") {
204
+ const _pid = process.env?.NEXT_PUBLIC_UTXOPIA_PROGRAM_ID || process.env?.UTXOPIA_PROGRAM_ID;
205
+ const _mint = process.env?.NEXT_PUBLIC_ZKBTC_MINT || process.env?.UTXOPIA_ZKBTC_MINT;
206
+ if (_pid) {
207
+ currentConfig = { ...currentConfig, utxopiaProgramId: address(_pid), groth16VerifierProgramId: address(_pid) };
208
+ }
209
+ if (_mint) {
210
+ currentConfig = { ...currentConfig, zkbtcMint: address(_mint) };
211
+ }
212
+ }
213
+ /** Esplora URL for a given Bitcoin network */
214
+ function esploraUrlForNetwork(net) {
215
+ switch (net) {
216
+ case "mainnet": return "https://mempool.space/api";
217
+ case "testnet": return "https://mempool.space/testnet/api";
218
+ case "testnet4": return "https://mempool.space/testnet4/api";
219
+ case "signet": return "https://mempool.space/signet/api";
220
+ case "regtest": return "http://localhost:2140";
221
+ default: return `https://mempool.space/${net}/api`;
222
+ }
223
+ }
224
+ function normalizeAppNetwork(network) {
225
+ switch (network) {
226
+ case "mainnet":
227
+ return "mainnet";
228
+ case "localnet":
229
+ return "localnet";
230
+ case "devnet":
231
+ case "devnet-regtest":
232
+ default:
233
+ return "devnet";
234
+ }
235
+ }
236
+ function bitcoinNetworkForAppNetwork(network) {
237
+ switch (network) {
238
+ case "localnet":
239
+ case "devnet-regtest":
240
+ return "regtest";
241
+ case "devnet":
242
+ return "testnet4";
243
+ case "mainnet":
244
+ return "mainnet";
245
+ default:
246
+ return undefined;
247
+ }
248
+ }
249
+ /**
250
+ * Get the current network configuration.
251
+ * Respects NEXT_PUBLIC_BTC_NETWORK env var to override Bitcoin network
252
+ * (e.g., "testnet" for testnet3, "testnet4" for testnet4).
253
+ */
254
+ export function getConfig() {
255
+ const btcNetOverride = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_BTC_NETWORK;
256
+ if (btcNetOverride && btcNetOverride !== currentConfig.bitcoinNetwork) {
257
+ return {
258
+ ...currentConfig,
259
+ bitcoinNetwork: btcNetOverride,
260
+ esploraUrl: esploraUrlForNetwork(btcNetOverride),
261
+ };
262
+ }
263
+ return currentConfig;
264
+ }
265
+ /**
266
+ * Set the network configuration
267
+ *
268
+ * @param network - Network type or custom config
269
+ * @throws Error if mainnet is selected (not yet deployed)
270
+ */
271
+ export function setConfig(network) {
272
+ if (typeof network === "string") {
273
+ const baseNetwork = normalizeAppNetwork(network);
274
+ switch (baseNetwork) {
275
+ case "devnet":
276
+ currentConfig = DEVNET_CONFIG;
277
+ break;
278
+ case "mainnet":
279
+ throw new Error("Mainnet is not yet deployed. " +
280
+ "UTXOpia is currently available on devnet only. " +
281
+ "Use setConfig('devnet') or wait for mainnet deployment announcement.");
282
+ case "localnet":
283
+ currentConfig = LOCALNET_CONFIG;
284
+ break;
285
+ default:
286
+ throw new Error(`Unknown network: ${network}`);
287
+ }
288
+ const bitcoinNetwork = bitcoinNetworkForAppNetwork(network);
289
+ if (bitcoinNetwork) {
290
+ currentConfig = {
291
+ ...currentConfig,
292
+ bitcoinNetwork,
293
+ esploraUrl: esploraUrlForNetwork(bitcoinNetwork),
294
+ };
295
+ }
296
+ }
297
+ else {
298
+ // Check if custom config is using placeholder mainnet addresses
299
+ if (network.network === "mainnet" && network.utxopiaProgramId === MAINNET_CONFIG.utxopiaProgramId) {
300
+ throw new Error("Cannot use placeholder mainnet configuration. " +
301
+ "Mainnet is not yet deployed.");
302
+ }
303
+ currentConfig = network;
304
+ }
305
+ }
306
+ /**
307
+ * Create a custom configuration by overriding specific values
308
+ *
309
+ * @param base - Base configuration to extend
310
+ * @param overrides - Values to override
311
+ */
312
+ export function createConfig(base, overrides) {
313
+ return { ...base, ...overrides };
314
+ }
315
+ export async function initConfig(overrides) {
316
+ // Pick base config from network: param > env > devnet
317
+ const appNetworkId = overrides?.network ||
318
+ (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_NETWORK || process.env?.UTXOPIA_NETWORK)) ||
319
+ "devnet";
320
+ const networkId = normalizeAppNetwork(appNetworkId);
321
+ const baseConfig = networkId === "localnet"
322
+ ? LOCALNET_CONFIG
323
+ : networkId === "mainnet"
324
+ ? MAINNET_CONFIG
325
+ : DEVNET_CONFIG;
326
+ const config = { ...baseConfig };
327
+ const appBitcoinNetwork = bitcoinNetworkForAppNetwork(appNetworkId);
328
+ const btcNetOverride = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_BTC_NETWORK;
329
+ const bitcoinNetwork = btcNetOverride || appBitcoinNetwork;
330
+ if (bitcoinNetwork) {
331
+ config.bitcoinNetwork = bitcoinNetwork;
332
+ config.esploraUrl = esploraUrlForNetwork(bitcoinNetwork);
333
+ }
334
+ // Resolve program ID: param > env > base config default
335
+ const programId = overrides?.utxopiaProgramId ||
336
+ (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_UTXOPIA_PROGRAM_ID || process.env?.UTXOPIA_PROGRAM_ID)) ||
337
+ undefined;
338
+ const policyProgramId = overrides?.policyProgramId ||
339
+ (typeof process !== "undefined" &&
340
+ (process.env?.NEXT_PUBLIC_UTXOPIA_POLICY_PROGRAM_ID ||
341
+ process.env?.UTXOPIA_POLICY_PROGRAM_ID)) ||
342
+ undefined;
343
+ if (policyProgramId) {
344
+ config.policyProgramId = address(policyProgramId);
345
+ }
346
+ // Resolve mint: param > env > default
347
+ const mint = overrides?.zkbtcMint ||
348
+ (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_ZKBTC_MINT || process.env?.UTXOPIA_ZKBTC_MINT)) ||
349
+ config.zkbtcMint;
350
+ // Resolve RPC URL for on-chain fetching
351
+ const rpcUrl = overrides?.solanaRpcUrl ||
352
+ (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_SOLANA_RPC_URL || process.env?.UTXOPIA_SOLANA_RPC)) ||
353
+ undefined;
354
+ if (programId) {
355
+ config.utxopiaProgramId = address(programId);
356
+ config.groth16VerifierProgramId = address(programId); // same program
357
+ // Fresh multi-pool deployments use zkBTC mint as the pool namespace.
358
+ const encoder = getAddressEncoder();
359
+ config.zkbtcMint = address(mint);
360
+ const [poolStatePda] = await getProgramDerivedAddress({
361
+ programAddress: config.utxopiaProgramId,
362
+ seeds: [
363
+ new TextEncoder().encode("pool_state"),
364
+ encoder.encode(config.zkbtcMint),
365
+ ],
366
+ });
367
+ const treeIndex = new Uint8Array(4);
368
+ const [commitmentTreePda] = await getProgramDerivedAddress({
369
+ programAddress: config.utxopiaProgramId,
370
+ seeds: [
371
+ new TextEncoder().encode("commitment_tree"),
372
+ encoder.encode(poolStatePda),
373
+ treeIndex,
374
+ ],
375
+ });
376
+ config.poolStatePda = poolStatePda;
377
+ config.commitmentTreePda = commitmentTreePda;
378
+ }
379
+ if (mint) {
380
+ config.zkbtcMint = address(mint);
381
+ // Derive pool vault (ATA: seeds = [owner, TOKEN_2022, mint] under ATA program)
382
+ const encoder = getAddressEncoder();
383
+ const [poolVault] = await getProgramDerivedAddress({
384
+ programAddress: config.ataProgramId,
385
+ seeds: [
386
+ encoder.encode(config.poolStatePda),
387
+ encoder.encode(config.token2022ProgramId),
388
+ encoder.encode(config.zkbtcMint),
389
+ ],
390
+ });
391
+ config.poolVault = poolVault;
392
+ }
393
+ // Apply Ika dWallet x-only pubkey override (sole Taproot custody key)
394
+ if (overrides?.ikaDwalletXOnlyPubkey) {
395
+ config.ikaDwalletXOnlyPubkey = overrides.ikaDwalletXOnlyPubkey;
396
+ }
397
+ if (overrides?.depositMode) {
398
+ config.depositMode = overrides.depositMode;
399
+ }
400
+ currentConfig = config;
401
+ return config;
402
+ }
403
+ // =============================================================================
404
+ // Convenience Exports
405
+ // =============================================================================
406
+ /** Default UTXOpia program ID (from current config) */
407
+ export const UTXOPIA_PROGRAM_ID = DEVNET_CONFIG.utxopiaProgramId;
408
+ export const UTXOPIA_POLICY_PROGRAM_ID = DEVNET_CONFIG.policyProgramId ?? DEVNET_CONFIG.utxopiaProgramId;
409
+ /** BTC Light Client program ID (manages light client + block headers) */
410
+ export const BTC_LIGHT_CLIENT_PROGRAM_ID = DEVNET_CONFIG.btcLightClientProgramId;
411
+ // =============================================================================
412
+ // Version Info
413
+ // =============================================================================
414
+ export const SDK_VERSION = "3.3.0";
415
+ /** JoinSplit Merkle tree depth */
416
+ export const JOINSPLIT_TREE_DEPTH = 16;
417
+ export const DEPLOYMENT_INFO = {
418
+ version: SDK_VERSION,
419
+ deployedAt: "2026-03-03",
420
+ network: "devnet",
421
+ features: [
422
+ "stealth-addresses",
423
+ "groth16-browser-proving",
424
+ ],
425
+ notes: "Client-side Groth16 proof generation via snarkjs",
426
+ };