@zkproofport-app/sdk 0.1.2-beta.1 → 0.2.0

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.
package/dist/index.js CHANGED
@@ -140,51 +140,6 @@ const DEFAULT_REQUEST_EXPIRY_MS = 10 * 60 * 1000;
140
140
  * ```
141
141
  */
142
142
  const MAX_QR_DATA_SIZE = 2953; // Version 40 with L error correction
143
- /**
144
- * ZKProofportNullifierRegistry contract ABI (V2).
145
- *
146
- * This is the current nullifier registry interface with relayer-only registration.
147
- * Public view functions allow checking nullifier status and verifying proofs without registration.
148
- *
149
- * Key functions:
150
- * - `isNullifierRegistered`: Check if a nullifier has been used
151
- * - `getNullifierInfo`: Get registration details for a nullifier
152
- * - `verifyOnly`: Verify a proof without registering the nullifier
153
- *
154
- * Note: Registration functions (verifyAndRegister) are relayer-only and not exposed in this ABI.
155
- *
156
- * @example
157
- * ```typescript
158
- * import { Contract } from 'ethers';
159
- *
160
- * const registry = new Contract(
161
- * registryAddress,
162
- * ZKPROOFPORT_NULLIFIER_REGISTRY_ABI,
163
- * provider
164
- * );
165
- *
166
- * const isUsed = await registry.isNullifierRegistered(nullifier);
167
- * ```
168
- */
169
- const ZKPROOFPORT_NULLIFIER_REGISTRY_ABI = [
170
- 'function isNullifierRegistered(bytes32 _nullifier) external view returns (bool)',
171
- 'function getNullifierInfo(bytes32 _nullifier) external view returns (uint64 registeredAt, bytes32 scope, bytes32 circuitId)',
172
- 'function verifyOnly(bytes32 _circuitId, bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool)',
173
- 'event NullifierRegistered(bytes32 indexed nullifier, bytes32 indexed scope, bytes32 indexed circuitId)',
174
- ];
175
-
176
- var constants = /*#__PURE__*/Object.freeze({
177
- __proto__: null,
178
- CIRCUIT_METADATA: CIRCUIT_METADATA,
179
- DEEP_LINK_HOSTS: DEEP_LINK_HOSTS,
180
- DEFAULT_REQUEST_EXPIRY_MS: DEFAULT_REQUEST_EXPIRY_MS,
181
- DEFAULT_SCHEME: DEFAULT_SCHEME,
182
- MAX_QR_DATA_SIZE: MAX_QR_DATA_SIZE,
183
- RELAY_URLS: RELAY_URLS,
184
- RPC_ENDPOINTS: RPC_ENDPOINTS,
185
- VERIFIER_ABI: VERIFIER_ABI,
186
- ZKPROOFPORT_NULLIFIER_REGISTRY_ABI: ZKPROOFPORT_NULLIFIER_REGISTRY_ABI
187
- });
188
143
 
189
144
  /**
190
145
  * Deep Link utilities for ZKProofport SDK
@@ -383,7 +338,6 @@ function parseProofResponseUrl(url) {
383
338
  if (timestamp) {
384
339
  response.timestamp = parseInt(timestamp, 10);
385
340
  }
386
- response.nullifier = urlObj.searchParams.get('nullifier') || undefined;
387
341
  }
388
342
  else if (status === 'error') {
389
343
  response.error = urlObj.searchParams.get('error') || undefined;
@@ -911,41 +865,6 @@ function extractScopeFromPublicInputs(publicInputsHex, circuit) {
911
865
  const scopeFields = publicInputsHex.slice(start, end + 1);
912
866
  return reconstructBytes32FromFields(scopeFields);
913
867
  }
914
- /**
915
- * Extract nullifier value from public inputs array.
916
- *
917
- * The nullifier is a bytes32 value encoded across 32 consecutive field elements
918
- * in the public inputs. The exact position depends on the circuit type.
919
- * Nullifiers are used for duplicate proof detection and must be unique per user+scope.
920
- *
921
- * @param publicInputsHex - Array of public input hex strings (zero-padded to 32 bytes)
922
- * @param circuit - Optional circuit identifier to determine field positions
923
- * @returns Reconstructed nullifier as hex string with 0x prefix, or null if inputs are insufficient
924
- *
925
- * @example
926
- * ```typescript
927
- * const nullifier = extractNullifierFromPublicInputs(publicInputsHex, 'coinbase_attestation');
928
- * console.log(nullifier); // '0xabcd1234...'
929
- *
930
- * // Check if nullifier is already registered
931
- * const isRegistered = await isNullifierRegistered(nullifier, registryAddress, provider);
932
- * ```
933
- */
934
- function extractNullifierFromPublicInputs(publicInputsHex, circuit) {
935
- let start, end;
936
- if (circuit === 'coinbase_country_attestation') {
937
- start = 118;
938
- end = 149;
939
- }
940
- else {
941
- start = 96;
942
- end = 127;
943
- }
944
- if (publicInputsHex.length <= end)
945
- return null;
946
- const nullifierFields = publicInputsHex.slice(start, end + 1);
947
- return reconstructBytes32FromFields(nullifierFields);
948
- }
949
868
  /** @internal Reconstruct a bytes32 value from 32 individual field elements */
950
869
  function reconstructBytes32FromFields(fields) {
951
870
  if (fields.length !== 32) {
@@ -957,83 +876,6 @@ function reconstructBytes32FromFields(fields) {
957
876
  }).join('');
958
877
  return '0x' + bytes;
959
878
  }
960
- /**
961
- * Check if a nullifier is already registered on-chain in the ZKProofport nullifier registry.
962
- *
963
- * This function queries the on-chain nullifier registry contract to determine if a nullifier
964
- * has been used before. This is used to prevent duplicate proof submissions from the same user
965
- * for the same scope.
966
- *
967
- * @param nullifier - The nullifier hash as hex string with 0x prefix
968
- * @param registryAddress - ZKProofportNullifierRegistry contract address
969
- * @param provider - ethers.js Provider instance (v5 or v6 compatible)
970
- * @returns Promise resolving to true if nullifier is registered, false otherwise
971
- *
972
- * @example
973
- * ```typescript
974
- * const nullifier = extractNullifierFromPublicInputs(publicInputsHex, circuit);
975
- * const isRegistered = await isNullifierRegistered(
976
- * nullifier,
977
- * '0x...',
978
- * provider
979
- * );
980
- *
981
- * if (isRegistered) {
982
- * console.log('This nullifier has already been used');
983
- * }
984
- * ```
985
- */
986
- async function isNullifierRegistered(nullifier, registryAddress, provider) {
987
- const { ZKPROOFPORT_NULLIFIER_REGISTRY_ABI } = await Promise.resolve().then(function () { return constants; });
988
- const contract = new ethers.ethers.Contract(registryAddress, ZKPROOFPORT_NULLIFIER_REGISTRY_ABI, provider);
989
- try {
990
- return await contract.isNullifierRegistered(nullifier);
991
- }
992
- catch {
993
- return false;
994
- }
995
- }
996
- /**
997
- * Get detailed information about a registered nullifier from the on-chain registry.
998
- *
999
- * This function retrieves the registration timestamp, scope, and circuit ID for a nullifier
1000
- * that has been registered on-chain. This metadata is useful for auditing and analytics.
1001
- *
1002
- * @param nullifier - The nullifier hash as hex string with 0x prefix
1003
- * @param registryAddress - ZKProofportNullifierRegistry contract address
1004
- * @param provider - ethers.js Provider instance (v5 or v6 compatible)
1005
- * @returns Promise resolving to nullifier info object, or null if not registered
1006
- *
1007
- * @example
1008
- * ```typescript
1009
- * const info = await getNullifierInfo(nullifier, registryAddress, provider);
1010
- *
1011
- * if (info) {
1012
- * console.log('Registered at:', new Date(info.registeredAt * 1000));
1013
- * console.log('Scope:', info.scope);
1014
- * console.log('Circuit:', info.circuitId);
1015
- * } else {
1016
- * console.log('Nullifier not registered');
1017
- * }
1018
- * ```
1019
- */
1020
- async function getNullifierInfo(nullifier, registryAddress, provider) {
1021
- const { ZKPROOFPORT_NULLIFIER_REGISTRY_ABI } = await Promise.resolve().then(function () { return constants; });
1022
- const contract = new ethers.ethers.Contract(registryAddress, ZKPROOFPORT_NULLIFIER_REGISTRY_ABI, provider);
1023
- try {
1024
- const [registeredAt, scope, circuitId] = await contract.getNullifierInfo(nullifier);
1025
- if (BigInt(registeredAt) === 0n)
1026
- return null;
1027
- return {
1028
- registeredAt: Number(registeredAt),
1029
- scope: scope,
1030
- circuitId: circuitId,
1031
- };
1032
- }
1033
- catch {
1034
- return null;
1035
- }
1036
- }
1037
879
 
1038
880
  /**
1039
881
  * Proofport SDK - Main class
@@ -1047,12 +889,15 @@ async function getNullifierInfo(nullifier, registryAddress, provider) {
1047
889
  * @example
1048
890
  * ```typescript
1049
891
  * import { ProofportSDK } from '@zkproofport-app/sdk';
892
+ * import { BrowserProvider } from 'ethers';
1050
893
  *
1051
894
  * // Initialize SDK (uses production relay by default)
1052
895
  * const sdk = ProofportSDK.create();
1053
896
  *
1054
- * // Authenticate
1055
- * await sdk.login({ clientId: 'your-id', apiKey: 'your-key' });
897
+ * // Set wallet signer for challenge-signature auth
898
+ * const provider = new BrowserProvider(window.ethereum);
899
+ * const signer = await provider.getSigner();
900
+ * sdk.setSigner(signer);
1056
901
  *
1057
902
  * // Create proof request via relay
1058
903
  * const relay = await sdk.createRelayRequest('coinbase_attestation', {
@@ -1098,14 +943,13 @@ class ProofportSDK {
1098
943
  */
1099
944
  constructor(config = {}) {
1100
945
  this.pendingRequests = new Map();
1101
- this.authToken = null;
946
+ this.signer = null;
1102
947
  this.socket = null;
1103
948
  this.config = {
1104
949
  scheme: config.scheme || DEFAULT_SCHEME,
1105
950
  verifiers: config.verifiers || {},
1106
951
  };
1107
952
  this.relayUrl = config.relayUrl || '';
1108
- this.nullifierRegistry = config.nullifierRegistry;
1109
953
  }
1110
954
  // ============ Request Creation ============
1111
955
  /**
@@ -1866,115 +1710,42 @@ class ProofportSDK {
1866
1710
  return false;
1867
1711
  return /Android|iPhone|iPad|iPod|webOS|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
1868
1712
  }
1713
+ // ============ Relay Integration ============
1869
1714
  /**
1870
- * Authenticates with ZKProofport using client credentials via the relay server.
1871
- *
1872
- * Exchanges a client_id and api_key pair for a short-lived JWT token
1873
- * that can be used to authenticate relay requests.
1715
+ * Sets the wallet signer for challenge-signature authentication.
1716
+ * The signer will be used to sign challenges from the relay server.
1874
1717
  *
1875
- * @param credentials - Client ID and API key
1876
- * @param relayUrl - Relay server URL (e.g., 'https://relay.zkproofport.app')
1877
- * @returns Promise resolving to AuthToken with JWT token and metadata
1878
- * @throws Error if authentication fails
1718
+ * @param signer - Wallet signer (ethers v6 Signer or compatible object with signMessage/getAddress)
1879
1719
  *
1880
1720
  * @example
1881
1721
  * ```typescript
1882
- * const auth = await ProofportSDK.authenticate(
1883
- * { clientId: 'your-client-id', apiKey: 'your-api-key' },
1884
- * 'https://relay.zkproofport.app'
1885
- * );
1886
- * console.log('Token:', auth.token);
1887
- * console.log('Expires in:', auth.expiresIn, 'seconds');
1888
- * ```
1889
- */
1890
- static async authenticate(credentials, relayUrl) {
1891
- if (!credentials.clientId || !credentials.apiKey) {
1892
- throw new Error('clientId and apiKey are required');
1893
- }
1894
- if (!relayUrl) {
1895
- throw new Error('relayUrl is required');
1896
- }
1897
- const response = await fetch(`${relayUrl}/api/v1/auth/token`, {
1898
- method: 'POST',
1899
- headers: { 'Content-Type': 'application/json' },
1900
- body: JSON.stringify({
1901
- client_id: credentials.clientId,
1902
- api_key: credentials.apiKey,
1903
- }),
1904
- });
1905
- if (!response.ok) {
1906
- const error = await response.json().catch(() => ({ error: `HTTP ${response.status}` }));
1907
- throw new Error(error.error || `Authentication failed: HTTP ${response.status}`);
1908
- }
1909
- const data = await response.json();
1910
- return {
1911
- token: data.token,
1912
- clientId: data.client_id,
1913
- dappId: data.dapp_id,
1914
- tier: data.tier,
1915
- expiresIn: data.expires_in,
1916
- expiresAt: Date.now() + (data.expires_in * 1000),
1917
- };
1918
- }
1919
- /**
1920
- * Checks if an auth token is still valid (not expired).
1722
+ * import { BrowserProvider } from 'ethers';
1921
1723
  *
1922
- * @param auth - AuthToken to check
1923
- * @returns True if the token has not expired
1924
- *
1925
- * @example
1926
- * ```typescript
1927
- * if (!ProofportSDK.isTokenValid(auth)) {
1928
- * auth = await ProofportSDK.authenticate(credentials, relayUrl);
1929
- * }
1724
+ * const provider = new BrowserProvider(window.ethereum);
1725
+ * const signer = await provider.getSigner();
1726
+ * sdk.setSigner(signer);
1930
1727
  * ```
1931
1728
  */
1932
- static isTokenValid(auth) {
1933
- return Date.now() < auth.expiresAt - 30000; // 30s buffer
1729
+ setSigner(signer) {
1730
+ this.signer = signer;
1934
1731
  }
1935
- // ============ Relay Integration ============
1936
1732
  /**
1937
- * Authenticates with ZKProofport and stores the token for relay requests.
1938
- *
1939
- * Instance method that authenticates via the relay server and stores
1940
- * the JWT token internally, so subsequent relay requests are automatically authenticated.
1941
- *
1942
- * @param credentials - Client ID and API key
1943
- * @returns Promise resolving to AuthToken
1944
- * @throws Error if authentication fails or relayUrl is not configured
1945
- *
1946
- * @example
1947
- * ```typescript
1948
- * const sdk = ProofportSDK.create('production');
1733
+ * Fetches a random challenge from the relay server.
1734
+ * The challenge must be signed and included in proof requests.
1949
1735
  *
1950
- * await sdk.login({ clientId: 'your-id', apiKey: 'your-key' });
1951
- * // SDK is now authenticated for relay requests
1952
- * ```
1736
+ * @returns Promise resolving to ChallengeResponse with challenge hex and expiry
1737
+ * @throws Error if relayUrl is not configured
1953
1738
  */
1954
- async login(credentials) {
1739
+ async getChallenge() {
1955
1740
  if (!this.relayUrl) {
1956
- throw new Error('relayUrl is required for authentication. Use ProofportSDK.create(\'production\') or set relayUrl in config.');
1741
+ throw new Error('relayUrl is required. Set it in ProofportSDK config.');
1957
1742
  }
1958
- this.authToken = await ProofportSDK.authenticate(credentials, this.relayUrl);
1959
- return this.authToken;
1960
- }
1961
- /**
1962
- * Logs out by clearing the stored authentication token.
1963
- */
1964
- logout() {
1965
- this.authToken = null;
1966
- }
1967
- /**
1968
- * Returns whether the SDK instance is currently authenticated with a valid token.
1969
- */
1970
- isAuthenticated() {
1971
- return this.authToken !== null && ProofportSDK.isTokenValid(this.authToken);
1972
- }
1973
- /**
1974
- * Returns the current auth token, or null if not authenticated.
1975
- */
1976
- getAuthToken() {
1977
- return this.authToken;
1743
+ const response = await fetch(`${this.relayUrl}/api/v1/challenge`);
1744
+ if (!response.ok) {
1745
+ const error = await response.json().catch(() => ({ error: `HTTP ${response.status}` }));
1746
+ throw new Error(error.error || `Failed to get challenge: HTTP ${response.status}`);
1747
+ }
1748
+ return await response.json();
1978
1749
  }
1979
1750
  /**
1980
1751
  * Creates a proof request through the relay server.
@@ -1982,19 +1753,19 @@ class ProofportSDK {
1982
1753
  * This is the recommended way to create proof requests. The relay server:
1983
1754
  * - Issues a server-side requestId (validated by the mobile app)
1984
1755
  * - Tracks request status in Redis
1985
- * - Handles credit deduction and tier enforcement
1986
1756
  * - Builds the deep link with relay callback URL
1757
+ * - Stores inputs hash for deep link integrity verification
1987
1758
  *
1988
1759
  * @param circuit - Circuit type identifier
1989
1760
  * @param inputs - Circuit-specific inputs
1990
1761
  * @param options - Request options (message, dappName, dappIcon, nonce)
1991
1762
  * @returns Promise resolving to RelayProofRequest with requestId, deepLink, pollUrl
1992
- * @throws Error if not authenticated or relay request fails
1763
+ * @throws Error if signer not set or relay request fails
1993
1764
  *
1994
1765
  * @example
1995
1766
  * ```typescript
1996
1767
  * const sdk = ProofportSDK.create();
1997
- * await sdk.login({ clientId: 'id', apiKey: 'key' });
1768
+ * sdk.setSigner(signer);
1998
1769
  *
1999
1770
  * const relay = await sdk.createRelayRequest('coinbase_attestation', {
2000
1771
  * scope: 'myapp.com'
@@ -2008,15 +1779,20 @@ class ProofportSDK {
2008
1779
  * ```
2009
1780
  */
2010
1781
  async createRelayRequest(circuit, inputs, options = {}) {
2011
- if (!this.authToken || !ProofportSDK.isTokenValid(this.authToken)) {
2012
- throw new Error('Not authenticated. Call login() first.');
1782
+ if (!this.signer) {
1783
+ throw new Error('Signer not set. Call setSigner() first.');
2013
1784
  }
2014
1785
  if (!this.relayUrl) {
2015
1786
  throw new Error('relayUrl is required. Set it in ProofportSDK config.');
2016
1787
  }
1788
+ // Get challenge from relay and sign it
1789
+ const { challenge } = await this.getChallenge();
1790
+ const signature = await this.signer.signMessage(challenge);
2017
1791
  const body = {
2018
1792
  circuitId: circuit,
2019
1793
  inputs,
1794
+ challenge,
1795
+ signature,
2020
1796
  };
2021
1797
  if (options.message)
2022
1798
  body.message = options.message;
@@ -2030,7 +1806,6 @@ class ProofportSDK {
2030
1806
  method: 'POST',
2031
1807
  headers: {
2032
1808
  'Content-Type': 'application/json',
2033
- 'Authorization': `Bearer ${this.authToken.token}`,
2034
1809
  },
2035
1810
  body: JSON.stringify(body),
2036
1811
  });
@@ -2113,7 +1888,7 @@ class ProofportSDK {
2113
1888
  * @param callbacks.onResult - Called when proof is completed or failed
2114
1889
  * @param callbacks.onError - Called on errors
2115
1890
  * @returns Unsubscribe function to clean up the connection
2116
- * @throws Error if not authenticated, relayUrl not set, or socket.io-client not installed
1891
+ * @throws Error if relayUrl not set or socket.io-client not installed
2117
1892
  *
2118
1893
  * @example
2119
1894
  * ```typescript
@@ -2134,9 +1909,6 @@ class ProofportSDK {
2134
1909
  * ```
2135
1910
  */
2136
1911
  async subscribe(requestId, callbacks) {
2137
- if (!this.authToken || !ProofportSDK.isTokenValid(this.authToken)) {
2138
- throw new Error('Not authenticated. Call login() first.');
2139
- }
2140
1912
  if (!this.relayUrl) {
2141
1913
  throw new Error('relayUrl is required. Set it in ProofportSDK config.');
2142
1914
  }
@@ -2151,10 +1923,9 @@ class ProofportSDK {
2151
1923
  if (typeof ioConnect !== 'function') {
2152
1924
  throw new Error('Failed to load socket.io-client: io function not found');
2153
1925
  }
2154
- // Connect to relay /proof namespace
1926
+ // Connect to relay /proof namespace (no JWT — open connections)
2155
1927
  const socket = ioConnect(`${this.relayUrl}/proof`, {
2156
1928
  path: '/socket.io',
2157
- auth: { token: this.authToken.token },
2158
1929
  transports: ['websocket', 'polling'],
2159
1930
  });
2160
1931
  this.socket = socket;
@@ -2203,7 +1974,7 @@ class ProofportSDK {
2203
1974
  async waitForProof(requestId, options = {}) {
2204
1975
  const timeout = options.timeoutMs || 300000;
2205
1976
  // Try Socket.IO first
2206
- if (this.authToken && ProofportSDK.isTokenValid(this.authToken) && this.relayUrl) {
1977
+ if (this.relayUrl) {
2207
1978
  try {
2208
1979
  return await new Promise((resolve, reject) => {
2209
1980
  const timer = setTimeout(() => {
@@ -2251,30 +2022,7 @@ class ProofportSDK {
2251
2022
  this.socket = null;
2252
2023
  }
2253
2024
  }
2254
- // ============ Nullifier Utilities ============
2255
- /**
2256
- * Extracts the nullifier from proof public inputs.
2257
- *
2258
- * The nullifier is a bytes32 value derived from the user's address and scope,
2259
- * used to prevent duplicate proof submissions. Each user+scope combination
2260
- * produces a unique nullifier.
2261
- *
2262
- * @param publicInputs - Array of public input hex strings from proof response
2263
- * @param circuit - Circuit type to determine field positions
2264
- * @returns Nullifier as hex string (0x...), or null if inputs are insufficient
2265
- *
2266
- * @example
2267
- * ```typescript
2268
- * const result = await sdk.waitForProof(relay.requestId);
2269
- * if (result.status === 'completed') {
2270
- * const nullifier = sdk.extractNullifier(result.publicInputs, result.circuit);
2271
- * console.log('Nullifier:', nullifier);
2272
- * }
2273
- * ```
2274
- */
2275
- extractNullifier(publicInputs, circuit) {
2276
- return extractNullifierFromPublicInputs(publicInputs, circuit);
2277
- }
2025
+ // ============ Public Input Utilities ============
2278
2026
  /**
2279
2027
  * Extracts the scope from proof public inputs.
2280
2028
  *
@@ -2297,66 +2045,6 @@ class ProofportSDK {
2297
2045
  extractScope(publicInputs, circuit) {
2298
2046
  return extractScopeFromPublicInputs(publicInputs, circuit);
2299
2047
  }
2300
- /**
2301
- * Checks if a nullifier is already registered on-chain.
2302
- *
2303
- * Queries the ZKProofportNullifierRegistry contract to determine if the
2304
- * nullifier has been used before. Used to prevent duplicate proof submissions.
2305
- *
2306
- * Requires `nullifierRegistry` in SDK config.
2307
- *
2308
- * @param nullifier - Nullifier hex string from extractNullifier()
2309
- * @param provider - Optional ethers provider (defaults to public RPC for configured chain)
2310
- * @returns True if nullifier is already registered
2311
- * @throws Error if nullifierRegistry is not configured
2312
- *
2313
- * @example
2314
- * ```typescript
2315
- * const sdk = ProofportSDK.create({
2316
- * relayUrl: 'https://relay.zkproofport.app',
2317
- * nullifierRegistry: { address: '0x...', chainId: 8453 }
2318
- * });
2319
- *
2320
- * const nullifier = sdk.extractNullifier(publicInputs, circuit);
2321
- * const isDuplicate = await sdk.checkNullifier(nullifier);
2322
- * ```
2323
- */
2324
- async checkNullifier(nullifier, provider) {
2325
- if (!this.nullifierRegistry) {
2326
- throw new Error('nullifierRegistry is required. Set it in ProofportSDK config.');
2327
- }
2328
- const p = provider || getDefaultProvider(this.nullifierRegistry.chainId);
2329
- return isNullifierRegistered(nullifier, this.nullifierRegistry.address, p);
2330
- }
2331
- /**
2332
- * Gets detailed information about a registered nullifier from on-chain registry.
2333
- *
2334
- * Retrieves the registration timestamp, scope, and circuit ID for a nullifier.
2335
- * Returns null if the nullifier is not registered.
2336
- *
2337
- * Requires `nullifierRegistry` in SDK config.
2338
- *
2339
- * @param nullifier - Nullifier hex string from extractNullifier()
2340
- * @param provider - Optional ethers provider (defaults to public RPC for configured chain)
2341
- * @returns Nullifier info or null if not registered
2342
- * @throws Error if nullifierRegistry is not configured
2343
- *
2344
- * @example
2345
- * ```typescript
2346
- * const info = await sdk.getNullifierDetails(nullifier);
2347
- * if (info) {
2348
- * console.log('Registered at:', new Date(info.registeredAt * 1000));
2349
- * console.log('Circuit:', info.circuitId);
2350
- * }
2351
- * ```
2352
- */
2353
- async getNullifierDetails(nullifier, provider) {
2354
- if (!this.nullifierRegistry) {
2355
- throw new Error('nullifierRegistry is required. Set it in ProofportSDK config.');
2356
- }
2357
- const p = provider || getDefaultProvider(this.nullifierRegistry.chainId);
2358
- return getNullifierInfo(nullifier, this.nullifierRegistry.address, p);
2359
- }
2360
2048
  }
2361
2049
 
2362
2050
  exports.ProofportSDK = ProofportSDK;