noah-clarity 0.3.3 → 0.3.5

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/config.d.ts CHANGED
@@ -32,6 +32,7 @@ export declare function createSDKConfig(addresses: ContractAddresses, options?:
32
32
  }): {
33
33
  kycRegistryAddress: string;
34
34
  attesterRegistryAddress: string;
35
+ revocationRegistryAddress: string;
35
36
  network: "testnet" | "mainnet" | "devnet";
36
37
  proverServiceUrl: string;
37
38
  attesterServiceUrl: string;
package/dist/config.js CHANGED
@@ -8,9 +8,9 @@ export const TESTNET_CONTRACTS = {
8
8
  network: 'testnet',
9
9
  deployer: 'STVAH96MR73TP2FZG2W4X220MEB4NEMJHPMVYQNS',
10
10
  contracts: {
11
- 'attester-registry': 'STVAH96MR73TP2FZG2W4X220MEB4NEMJHPMVYQNS.attester-registry',
11
+ 'attester-registry': 'STVAH96MR73TP2FZG2W4X220MEB4NEMJHPMVYQNS.Attester-registry',
12
12
  'attester-registry-trait': 'STVAH96MR73TP2FZG2W4X220MEB4NEMJHPMVYQNS.attester-registry-trait',
13
- 'kyc-registry': 'STVAH96MR73TP2FZG2W4X220MEB4NEMJHPMVYQNS.kycs-registry',
13
+ 'kyc-registry': 'STVAH96MR73TP2FZG2W4X220MEB4NEMJHPMVYQNS.KYc-registry',
14
14
  'revocation': 'STVAH96MR73TP2FZG2W4X220MEB4NEMJHPMVYQNS.revocation',
15
15
  },
16
16
  deployment_date: '2025-01-17',
@@ -40,6 +40,7 @@ export function createSDKConfig(addresses, options) {
40
40
  return {
41
41
  kycRegistryAddress: addresses.contracts['kyc-registry'],
42
42
  attesterRegistryAddress: addresses.contracts['attester-registry'],
43
+ revocationRegistryAddress: addresses.contracts['revocation'],
43
44
  network: addresses.network,
44
45
  proverServiceUrl: options?.proverServiceUrl || 'http://localhost:8080',
45
46
  attesterServiceUrl: options?.attesterServiceUrl || 'http://localhost:8081',
@@ -20,11 +20,23 @@ export declare class KYCContract {
20
20
  * @returns KYC status
21
21
  */
22
22
  hasKYC(userPrincipal: string): Promise<KYCStatus>;
23
+ /**
24
+ * Get revocation root from the revocation registry contract
25
+ * @returns Revocation root (32-byte hex string) or null if contract not configured
26
+ */
27
+ getRevocationRoot(): Promise<string | null>;
28
+ /**
29
+ * Check if a commitment is revoked by checking the revocation root
30
+ * Note: This is a simplified check. For full verification, non-membership proofs are needed.
31
+ * @param commitment Commitment to check (hex string)
32
+ * @returns true if revoked, false if not revoked or if revocation checking is unavailable
33
+ */
34
+ isCommitmentRevoked(commitment: string): Promise<boolean>;
23
35
  /**
24
36
  * Check if KYC is valid
25
- * Since KYC records don't expire, this is equivalent to hasKYC
37
+ * Now includes revocation checking
26
38
  * @param userPrincipal User's Stacks principal
27
- * @returns true if KYC is valid
39
+ * @returns true if KYC is valid (exists and not revoked)
28
40
  */
29
41
  isKYCValid(userPrincipal: string): Promise<boolean>;
30
42
  /**
package/dist/contract.js CHANGED
@@ -239,6 +239,9 @@ export class KYCContract {
239
239
  */
240
240
  async hasKYC(userPrincipal) {
241
241
  const { address, name } = this.parseContractAddress(this.config.kycRegistryAddress);
242
+ // #region agent log
243
+ fetch('http://127.0.0.1:7249/ingest/b239a7fb-669e-478f-b888-bd46beaadedf', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'contract.ts:269', 'message': 'hasKYC called', 'data': { userPrincipal, contractAddress: this.config.kycRegistryAddress, parsedAddress: address, parsedName: name }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'A' }) }).catch(() => { });
244
+ // #endregion agent log
242
245
  try {
243
246
  const result = await callReadOnlyFunction({
244
247
  contractAddress: address,
@@ -248,30 +251,117 @@ export class KYCContract {
248
251
  network: this.network,
249
252
  senderAddress: address, // Use contract address as sender for read-only calls
250
253
  });
254
+ // #region agent log
255
+ console.log('hasKYC callReadOnlyFunction result (before cvToJSON):', result);
256
+ console.log('hasKYC result type:', typeof result);
257
+ console.log('hasKYC result constructor:', result?.constructor?.name);
258
+ fetch('http://127.0.0.1:7249/ingest/b239a7fb-669e-478f-b888-bd46beaadedf', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'contract.ts:277', 'message': 'hasKYC callReadOnlyFunction result', 'data': { userPrincipal, resultType: typeof result, resultConstructor: result?.constructor?.name, resultString: String(result) }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run2', hypothesisId: 'A' }) }).catch(() => { });
259
+ // #endregion agent log
251
260
  const jsonResult = cvToJSON(result);
252
- // Result is (ok bool), so check if it's ok and the value is true
253
- if (jsonResult.type === 'responseOk') {
254
- const hasKYC = jsonResult.value.value === true;
261
+ // #region agent log
262
+ console.log('hasKYC raw result (after cvToJSON):', JSON.stringify(jsonResult, null, 2));
263
+ console.log('hasKYC jsonResult.type:', jsonResult.type);
264
+ console.log('hasKYC jsonResult.value:', jsonResult.value);
265
+ console.log('hasKYC jsonResult.value type:', typeof jsonResult.value);
266
+ console.log('hasKYC jsonResult.success:', jsonResult.success);
267
+ fetch('http://127.0.0.1:7249/ingest/b239a7fb-669e-478f-b888-bd46beaadedf', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'contract.ts:290', 'message': 'hasKYC result after cvToJSON', 'data': { userPrincipal, resultType: jsonResult.type, resultValue: jsonResult.value, resultValueType: typeof jsonResult.value, resultSuccess: jsonResult.success, fullResult: JSON.stringify(jsonResult) }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run2', hypothesisId: 'B' }) }).catch(() => { });
268
+ // #endregion agent log
269
+ // Result is (ok bool), cvToJSON returns:
270
+ // { type: '(response bool UnknownType)', value: { type: 'bool', value: true }, success: true }
271
+ // Check success field or response type, then extract boolean from value.value
272
+ if (jsonResult.success === true || (jsonResult.type && jsonResult.type.includes('response'))) {
273
+ // Extract the boolean value from the nested structure
274
+ const boolValue = jsonResult.value?.value;
275
+ const hasKYC = boolValue === true;
276
+ console.log('hasKYC final result:', hasKYC, 'jsonResult.value.value:', boolValue, 'type:', typeof boolValue);
255
277
  return { hasKYC };
256
278
  }
257
279
  else {
280
+ console.log('hasKYC: response not ok, type:', jsonResult.type, 'success:', jsonResult.success, 'full result:', JSON.stringify(jsonResult));
258
281
  return { hasKYC: false };
259
282
  }
260
283
  }
261
284
  catch (error) {
285
+ // #region agent log
286
+ console.error('hasKYC exception:', error);
287
+ fetch('http://127.0.0.1:7249/ingest/b239a7fb-669e-478f-b888-bd46beaadedf', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'contract.ts:294', 'message': 'hasKYC error', 'data': { userPrincipal, error: error instanceof Error ? error.message : String(error), errorStack: error instanceof Error ? error.stack : undefined }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'A' }) }).catch(() => { });
288
+ // #endregion agent log
262
289
  console.error('Error checking KYC status:', error);
263
290
  return { hasKYC: false };
264
291
  }
265
292
  }
293
+ /**
294
+ * Get revocation root from the revocation registry contract
295
+ * @returns Revocation root (32-byte hex string) or null if contract not configured
296
+ */
297
+ async getRevocationRoot() {
298
+ if (!this.config.revocationRegistryAddress) {
299
+ return null;
300
+ }
301
+ const { address, name } = this.parseContractAddress(this.config.revocationRegistryAddress);
302
+ try {
303
+ const result = await callReadOnlyFunction({
304
+ contractAddress: address,
305
+ contractName: name,
306
+ functionName: 'get-revocation-root',
307
+ functionArgs: [],
308
+ network: this.network,
309
+ senderAddress: address,
310
+ });
311
+ const jsonResult = cvToJSON(result);
312
+ // Result is (ok (buff 32))
313
+ if (jsonResult.success === true || (jsonResult.type && jsonResult.type.includes('response'))) {
314
+ const rootValue = jsonResult.value?.value;
315
+ if (rootValue) {
316
+ // Convert buffer to hex string
317
+ return rootValue.startsWith('0x') ? rootValue : `0x${rootValue}`;
318
+ }
319
+ }
320
+ return null;
321
+ }
322
+ catch (error) {
323
+ console.error('Error fetching revocation root:', error);
324
+ return null;
325
+ }
326
+ }
327
+ /**
328
+ * Check if a commitment is revoked by checking the revocation root
329
+ * Note: This is a simplified check. For full verification, non-membership proofs are needed.
330
+ * @param commitment Commitment to check (hex string)
331
+ * @returns true if revoked, false if not revoked or if revocation checking is unavailable
332
+ */
333
+ async isCommitmentRevoked(commitment) {
334
+ const root = await this.getRevocationRoot();
335
+ // If no revocation registry configured or root is zero (empty tree), nothing is revoked
336
+ if (!root || root === '0x0000000000000000000000000000000000000000000000000000000000000000') {
337
+ return false;
338
+ }
339
+ // TODO: Full revocation checking requires non-membership proof verification
340
+ // For now, we return false (not revoked) when root exists but we can't verify without proof
341
+ // In production, you should:
342
+ // 1. Request a non-membership proof from the attester service
343
+ // 2. Verify the proof using Merkle tree verification
344
+ // 3. Return true if proof verification fails or if commitment is in revocation tree
345
+ return false;
346
+ }
266
347
  /**
267
348
  * Check if KYC is valid
268
- * Since KYC records don't expire, this is equivalent to hasKYC
349
+ * Now includes revocation checking
269
350
  * @param userPrincipal User's Stacks principal
270
- * @returns true if KYC is valid
351
+ * @returns true if KYC is valid (exists and not revoked)
271
352
  */
272
353
  async isKYCValid(userPrincipal) {
273
- const status = await this.hasKYC(userPrincipal);
274
- return status.hasKYC;
354
+ // First check if user has KYC record
355
+ const kycDetails = await this.getKYC(userPrincipal);
356
+ if (!kycDetails || !kycDetails.hasKYC || !kycDetails.commitment) {
357
+ return false;
358
+ }
359
+ // Check revocation status
360
+ const isRevoked = await this.isCommitmentRevoked(kycDetails.commitment);
361
+ if (isRevoked) {
362
+ return false;
363
+ }
364
+ return true;
275
365
  }
276
366
  /**
277
367
  * Get KYC details for a user
@@ -293,12 +383,20 @@ export class KYCContract {
293
383
  // Result is (ok (some kyc-record)) or (ok none)
294
384
  if (jsonResult.type === 'responseOk' && jsonResult.value.type === 'optionalSome') {
295
385
  const record = jsonResult.value.value.value;
296
- return {
386
+ const result = {
297
387
  hasKYC: true,
298
388
  commitment: record.commitment?.value,
299
389
  attesterId: record['attester-id']?.value,
300
390
  registeredAt: record['registered-at']?.value,
301
391
  };
392
+ // Add history fields if present
393
+ if (record['previous-commitment']?.value) {
394
+ result.previousCommitment = record['previous-commitment'].value;
395
+ }
396
+ if (record['previous-registered-at']?.value !== undefined) {
397
+ result.previousRegisteredAt = record['previous-registered-at'].value;
398
+ }
399
+ return result;
302
400
  }
303
401
  else {
304
402
  return null;
package/dist/types.d.ts CHANGED
@@ -6,6 +6,8 @@ export interface KYCStatus {
6
6
  commitment?: string;
7
7
  attesterId?: number;
8
8
  registeredAt?: number;
9
+ previousCommitment?: string;
10
+ previousRegisteredAt?: number;
9
11
  }
10
12
  export interface RegisterKYCParams {
11
13
  commitment: string;
@@ -46,6 +48,7 @@ export interface AttestationResponse {
46
48
  export interface SDKConfig {
47
49
  kycRegistryAddress: string;
48
50
  attesterRegistryAddress: string;
51
+ revocationRegistryAddress?: string;
49
52
  proverServiceUrl?: string;
50
53
  attesterServiceUrl?: string;
51
54
  network?: 'mainnet' | 'testnet' | 'devnet';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noah-clarity",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "TypeScript SDK for Noah-v2 KYC system on Stacks",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",