@passly/passly-sdk 0.1.3 → 0.1.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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.js +474 -231
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@passly/passly-sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "Official SDK for Passly identity protocol - social identity verification for Web3",
6
- "main": "src/passly-sdk.js",
6
+ "main": "src/index.js",
7
7
  "dependencies": {
8
8
  "ethers": "^5.7.2"
9
9
  },
package/src/index.js CHANGED
@@ -1,29 +1,39 @@
1
- // passly-sdk.js
1
+ // index.js (or passly-sdk.js)
2
2
  import { ethers } from 'ethers';
3
3
 
4
4
  /**
5
- * Passly SDK - A simple interface for interacting with the Passly identity protocol
5
+ * Passly SDK - A comprehensive interface for interacting with the Passly identity protocol
6
6
  *
7
7
  * This SDK provides an easy way for developers to integrate with Passly,
8
8
  * a social identity layer that helps verify user identities and works as an anti-sybil tool.
9
+ *
10
+ * Features:
11
+ * - Identity verification and passport management
12
+ * - Points and rewards system integration
13
+ * - Historical verification data access
14
+ * - Platform configuration queries
15
+ * - Referral system integration
9
16
  */
10
17
  class PasslySDK {
11
18
  /**
12
19
  * Initialize the Passly SDK
13
20
  * @param {Object} config - Configuration options
14
- * @param {string} [config.contractAddress] - Optional override for the Passly contract address
21
+ * @param {string} [config.contractAddress] - Override for the Passly contract address
22
+ * @param {string} [config.platformsAddress] - Override for the Platforms contract address
23
+ * @param {string} [config.archivesAddress] - Override for the Archives contract address
24
+ * @param {string} [config.rewardsAddress] - Override for the Rewards contract address
15
25
  * @param {ethers.providers.Provider} [config.provider] - Optional ethers provider
16
26
  * @param {ethers.Signer} [config.signer] - Optional ethers signer for write operations
27
+ * @param {string} [config.network] - Network name for default addresses
17
28
  */
18
29
  constructor(config = {}) {
19
- // Default configuration will be set when connect() is called
20
30
  this.config = config;
21
- this.contract = null;
31
+ this.contracts = {};
22
32
  this.isConnected = false;
23
33
  }
24
34
 
25
35
  /**
26
- * Connect to the Passly contract
36
+ * Connect to the Passly contracts
27
37
  * @param {Object} options - Optional connection parameters to override constructor config
28
38
  * @returns {Promise<PasslySDK>} - Returns the SDK instance
29
39
  */
@@ -35,30 +45,75 @@ class PasslySDK {
35
45
  config.provider = new ethers.providers.JsonRpcProvider('https://testnet.skalenodes.com/v1/aware-fake-trim-testnet');
36
46
  }
37
47
 
38
- // If contract address isn't provided, use the default deployment
39
- config.contractAddress = config.contractAddress || '0x8Cf0eD0A6eBa23d7d94a071A5ce88DB40f90c105';
40
-
41
- // Load contract ABI
42
- const abi = [
43
- "function getPassportByAddress(address user) external view returns (uint256)",
44
- "function getPassportData(uint256 passportId) external view returns (address owner, uint256 createdAt, uint256 verificationCount, string memory category)",
45
- "function getVerifiedPlatforms(uint256 passportId) external view returns (string[] memory)",
46
- "function getVerification(uint256 passportId, string calldata platform) external view returns (string memory identifier, uint256 verifiedAt, bytes32 proofHash, bool active)",
47
- "function isIdentifierVerified(string calldata platform, string calldata identifier) external view returns (bool isVerified, uint256 passportId)",
48
- "function getSupportedPlatforms() external view returns (string[] memory)",
49
- "function getSupportedCategories() external view returns (string[] memory)",
50
- ];
51
-
52
- // Initialize the contract
53
- if (config.signer) {
54
- // Connect with signer for write operations
55
- this.contract = new ethers.Contract(config.contractAddress, abi, config.signer);
56
- } else {
57
- // Connect with provider for read-only operations
58
- this.contract = new ethers.Contract(config.contractAddress, abi, config.provider);
48
+ // Default contract addresses
49
+ const addresses = {
50
+ passly: config.contractAddress || '0x9a1b12c6E794dE70b1Bd73a74f81eF5A41Fb7Cb3',
51
+ platforms: config.platformsAddress || '0x0f1ff42F6f9C2d8D1C054aF7c03cf5e449f0Bc15',
52
+ archives: config.archivesAddress || '0xa26A0eAE99A6ccD8f82dC6Cfbd35ccCeebf3BcFf',
53
+ rewards: config.rewardsAddress || '0x993d28480D5f9bf457FAb67D58D696e3c5655031'
54
+ };
55
+
56
+ // Contract ABIs
57
+ const abis = {
58
+ passly: [
59
+ "function getPassportByAddress(address user) external view returns (uint256)",
60
+ "function getPassportData(uint256 passportId) external view returns (address owner, uint256 createdAt, uint256 verificationCount, string memory category, uint256 totalPoints, string memory referralCode, uint256 totalReferrals)",
61
+ "function getVerifiedPlatforms(uint256 passportId) external view returns (string[] memory)",
62
+ "function getVerification(uint256 passportId, string calldata platform) external view returns (string memory identifier, uint256 verifiedAt, bytes32 proofHash, bool active, bool pointsAwarded)",
63
+ "function isIdentifierVerified(string calldata platform, string calldata identifier) external view returns (bool isVerified, uint256 passportId)",
64
+ "function getSupportedCategories() external view returns (string[] memory)",
65
+ "function isCategorySupported(string calldata category) external view returns (bool)",
66
+ "function ownerOf(uint256 tokenId) external view returns (address)"
67
+ ],
68
+
69
+ platforms: [
70
+ "function getPlatformConfig(string calldata platform) external view returns (bool isSupported, string memory platformType, string[] memory requiredPlatforms, uint256 pointReward, bool enablePointPunishment, uint256 punishmentPeriodDays)",
71
+ "function getSupportedPlatforms() external view returns (string[] memory)",
72
+ "function getSupportedPlatformTypes() external view returns (string[] memory)",
73
+ "function isPlatformSupported(string calldata platform) external view returns (bool)",
74
+ "function isPlatformTypeSupported(string calldata platformType) external view returns (bool)",
75
+ "function validateDependencies(string[] calldata verifiedPlatforms, string calldata platform) external view returns (bool isValid, string memory missingDependency)",
76
+ "function getCascadeAffectedPlatforms(string[] calldata verifiedPlatforms, string calldata revokedPlatform) external view returns (string[] memory affectedPlatforms)"
77
+ ],
78
+
79
+ archives: [
80
+ "function getVerificationHistory(uint256 passportId, string calldata platform) external view returns (tuple(string identifier, uint256 verifiedAt, uint256 revokedAt, bytes32 proofHash, bool wasRevoked, string revokeReason)[] memory)",
81
+ "function getPlatformHistory(uint256 passportId, string calldata platform) external view returns (tuple(uint256 totalVerifications, uint256 totalRevocations, string[] historicalIdentifiers, uint256 firstVerificationAt, uint256 lastRevocationAt))",
82
+ "function getHistoricalIdentifiers(uint256 passportId, string calldata platform) external view returns (string[] memory)",
83
+ "function getIdentifierUsage(string calldata platform, string calldata identifier) external view returns (uint256[] memory)",
84
+ "function getMultiPlatformHistory(uint256 passportId, string[] calldata platforms) external view returns (uint256 totalVerifications, uint256 totalRevocations, tuple(uint256 totalVerifications, uint256 totalRevocations, string[] historicalIdentifiers, uint256 firstVerificationAt, uint256 lastRevocationAt)[] memory platformStats)"
85
+ ],
86
+
87
+ rewards: [
88
+ "function getPoints(uint256 passportId) external view returns (uint256)",
89
+ "function getPointBreakdown(uint256 passportId) external view returns (uint256 holding, uint256 platform, uint256 referral, uint256 total)",
90
+ "function getPlatformPoints(uint256 passportId, string calldata platform) external view returns (uint256)",
91
+ "function isPlatformRewarded(uint256 passportId, string calldata platform) external view returns (bool)",
92
+ "function getReferralInfo(uint256 passportId) external view returns (string memory referralCode, address referredBy, uint256 totalReferrals, uint256 referralEarnings)",
93
+ "function validateReferralCode(string calldata referralCode) external view returns (bool isValid, uint256 ownerPassportId)",
94
+ "function getUserReferrals(uint256 passportId) external view returns (string[] memory)",
95
+ "function getPointConfig() external view returns (uint256 dailyHolding, uint256 referral, uint256 referee)"
96
+ ]
97
+ };
98
+
99
+ // Initialize contracts
100
+ const contractProvider = config.signer || config.provider;
101
+
102
+ this.contracts.passly = new ethers.Contract(addresses.passly, abis.passly, contractProvider);
103
+
104
+ if (addresses.platforms) {
105
+ this.contracts.platforms = new ethers.Contract(addresses.platforms, abis.platforms, contractProvider);
106
+ }
107
+
108
+ if (addresses.archives) {
109
+ this.contracts.archives = new ethers.Contract(addresses.archives, abis.archives, contractProvider);
110
+ }
111
+
112
+ if (addresses.rewards) {
113
+ this.contracts.rewards = new ethers.Contract(addresses.rewards, abis.rewards, contractProvider);
59
114
  }
60
115
 
61
- this.config = config;
116
+ this.config = { ...config, addresses };
62
117
  this.isConnected = true;
63
118
  return this;
64
119
  }
@@ -73,6 +128,31 @@ class PasslySDK {
73
128
  }
74
129
  }
75
130
 
131
+ /**
132
+ * Helper to convert address or passport ID to passport ID
133
+ * @private
134
+ */
135
+ async _resolvePassportId(addressOrPassportId) {
136
+ if (typeof addressOrPassportId === 'number' ||
137
+ (typeof addressOrPassportId === 'string' && /^\d+$/.test(addressOrPassportId))) {
138
+ return parseInt(addressOrPassportId);
139
+ }
140
+
141
+ if (typeof addressOrPassportId === 'string' && ethers.utils.isAddress(addressOrPassportId)) {
142
+ const passportId = await this.getPassportId(addressOrPassportId);
143
+ if (!passportId) {
144
+ throw new Error('No passport found for address');
145
+ }
146
+ return passportId;
147
+ }
148
+
149
+ throw new Error('Invalid address or passport ID');
150
+ }
151
+
152
+ // =============================================================================
153
+ // PASSPORT & IDENTITY FUNCTIONS
154
+ // =============================================================================
155
+
76
156
  /**
77
157
  * Get a user's passport ID from their wallet address
78
158
  * @param {string} address - The wallet address to check
@@ -82,10 +162,9 @@ class PasslySDK {
82
162
  this._ensureConnected();
83
163
 
84
164
  try {
85
- const passportId = await this.contract.getPassportByAddress(address);
165
+ const passportId = await this.contracts.passly.getPassportByAddress(address);
86
166
  return passportId.toNumber();
87
167
  } catch (error) {
88
- // If the error is "User has no passport", return null
89
168
  if (error.message.includes('User has no passport')) {
90
169
  return null;
91
170
  }
@@ -114,37 +193,46 @@ class PasslySDK {
114
193
  let passportId;
115
194
  try {
116
195
  passportId = await this.getPassportId(address);
196
+ if (!passportId) return null;
117
197
  } catch (error) {
118
198
  return null;
119
199
  }
120
200
 
121
- if (!passportId) return null;
201
+ // Get passport data - now correctly handling all 7 return values
202
+ const [owner, createdAt, verificationCount, category, totalPoints, referralCode, totalReferrals] =
203
+ await this.contracts.passly.getPassportData(passportId);
122
204
 
123
- const [owner, createdAt, verificationCount, category] = await this.contract.getPassportData(passportId);
124
- const platforms = await this.contract.getVerifiedPlatforms(passportId);
205
+ const platforms = await this.contracts.passly.getVerifiedPlatforms(passportId);
125
206
 
126
207
  // Gather all verifications
127
208
  const verifications = {};
128
209
  for (const platform of platforms) {
129
- const [identifier, verifiedAt, proofHash, active] = await this.contract.getVerification(
130
- passportId,
131
- platform
132
- );
133
-
134
- verifications[platform] = {
135
- identifier,
136
- verifiedAt: new Date(verifiedAt.toNumber() * 1000),
137
- proofHash: proofHash,
138
- active
139
- };
210
+ try {
211
+ const [identifier, verifiedAt, proofHash, active, pointsAwarded] =
212
+ await this.contracts.passly.getVerification(passportId, platform);
213
+
214
+ verifications[platform] = {
215
+ identifier,
216
+ verifiedAt: new Date(verifiedAt.toNumber() * 1000),
217
+ proofHash,
218
+ active,
219
+ pointsAwarded
220
+ };
221
+ } catch (error) {
222
+ // Skip platforms that fail to load
223
+ console.warn(`Failed to load verification for platform ${platform}:`, error.message);
224
+ }
140
225
  }
141
226
 
142
227
  return {
143
228
  id: passportId,
144
- owner: owner,
229
+ owner,
145
230
  createdAt: new Date(createdAt.toNumber() * 1000),
146
231
  verificationCount: verificationCount.toNumber(),
147
232
  category,
233
+ totalPoints: totalPoints.toNumber(),
234
+ referralCode,
235
+ totalReferrals: totalReferrals.toNumber(),
148
236
  platforms,
149
237
  verifications
150
238
  };
@@ -152,27 +240,31 @@ class PasslySDK {
152
240
 
153
241
  /**
154
242
  * Get all verification data for a passport
155
- * @param {number} passportId - The passport ID
243
+ * @param {string|number} addressOrPassportId - Wallet address or passport ID
156
244
  * @returns {Promise<Object>} - Object containing verification details
157
245
  */
158
- async getVerifications(passportId) {
246
+ async getVerifications(addressOrPassportId) {
159
247
  this._ensureConnected();
160
248
 
161
- const platforms = await this.contract.getVerifiedPlatforms(passportId);
249
+ const passportId = await this._resolvePassportId(addressOrPassportId);
250
+ const platforms = await this.contracts.passly.getVerifiedPlatforms(passportId);
162
251
  const verifications = {};
163
252
 
164
253
  for (const platform of platforms) {
165
- const [identifier, verifiedAt, proofHash, active] = await this.contract.getVerification(
166
- passportId,
167
- platform
168
- );
169
-
170
- verifications[platform] = {
171
- identifier,
172
- verifiedAt: new Date(verifiedAt.toNumber() * 1000),
173
- proofHash: proofHash,
174
- active
175
- };
254
+ try {
255
+ const [identifier, verifiedAt, proofHash, active, pointsAwarded] =
256
+ await this.contracts.passly.getVerification(passportId, platform);
257
+
258
+ verifications[platform] = {
259
+ identifier,
260
+ verifiedAt: new Date(verifiedAt.toNumber() * 1000),
261
+ proofHash,
262
+ active,
263
+ pointsAwarded
264
+ };
265
+ } catch (error) {
266
+ console.warn(`Failed to load verification for platform ${platform}:`, error.message);
267
+ }
176
268
  }
177
269
 
178
270
  return verifications;
@@ -187,7 +279,7 @@ class PasslySDK {
187
279
  async isAccountVerified(platform, identifier) {
188
280
  this._ensureConnected();
189
281
 
190
- const [isVerified, passportId] = await this.contract.isIdentifierVerified(platform, identifier);
282
+ const [isVerified, passportId] = await this.contracts.passly.isIdentifierVerified(platform, identifier);
191
283
 
192
284
  return {
193
285
  isVerified,
@@ -195,13 +287,246 @@ class PasslySDK {
195
287
  };
196
288
  }
197
289
 
290
+ // =============================================================================
291
+ // REWARDS & POINTS FUNCTIONS
292
+ // =============================================================================
293
+
294
+ /**
295
+ * Get total points for a passport
296
+ * @param {string|number} addressOrPassportId - Wallet address or passport ID
297
+ * @returns {Promise<number|null>} - Total points or null if no passport/rewards contract
298
+ */
299
+ async getPoints(addressOrPassportId) {
300
+ this._ensureConnected();
301
+
302
+ if (!this.contracts.rewards) {
303
+ // Fallback to passport data
304
+ const passport = await this.getPassport(addressOrPassportId);
305
+ return passport ? passport.totalPoints : null;
306
+ }
307
+
308
+ try {
309
+ const passportId = await this._resolvePassportId(addressOrPassportId);
310
+ const points = await this.contracts.rewards.getPoints(passportId);
311
+ return points.toNumber();
312
+ } catch (error) {
313
+ return null;
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Get detailed point breakdown for a passport
319
+ * @param {string|number} addressOrPassportId - Wallet address or passport ID
320
+ * @returns {Promise<Object|null>} - Point breakdown or null if no passport/rewards contract
321
+ */
322
+ async getPointBreakdown(addressOrPassportId) {
323
+ this._ensureConnected();
324
+
325
+ if (!this.contracts.rewards) return null;
326
+
327
+ try {
328
+ const passportId = await this._resolvePassportId(addressOrPassportId);
329
+ const [holding, platform, referral, total] = await this.contracts.rewards.getPointBreakdown(passportId);
330
+
331
+ return {
332
+ holding: holding.toNumber(),
333
+ platform: platform.toNumber(),
334
+ referral: referral.toNumber(),
335
+ total: total.toNumber()
336
+ };
337
+ } catch (error) {
338
+ return null;
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Get points earned from a specific platform
344
+ * @param {string|number} addressOrPassportId - Wallet address or passport ID
345
+ * @param {string} platform - The platform name
346
+ * @returns {Promise<number|null>} - Platform points or null if no passport/rewards contract
347
+ */
348
+ async getPlatformPoints(addressOrPassportId, platform) {
349
+ this._ensureConnected();
350
+
351
+ if (!this.contracts.rewards) return null;
352
+
353
+ try {
354
+ const passportId = await this._resolvePassportId(addressOrPassportId);
355
+ const points = await this.contracts.rewards.getPlatformPoints(passportId, platform);
356
+ return points.toNumber();
357
+ } catch (error) {
358
+ return null;
359
+ }
360
+ }
361
+
362
+ // =============================================================================
363
+ // REFERRAL FUNCTIONS
364
+ // =============================================================================
365
+
366
+ /**
367
+ * Get referral information for a passport
368
+ * @param {string|number} addressOrPassportId - Wallet address or passport ID
369
+ * @returns {Promise<Object|null>} - Referral info or null if no passport/rewards contract
370
+ */
371
+ async getReferralInfo(addressOrPassportId) {
372
+ this._ensureConnected();
373
+
374
+ if (!this.contracts.rewards) {
375
+ // Fallback to passport data
376
+ const passport = await this.getPassport(addressOrPassportId);
377
+ if (!passport) return null;
378
+
379
+ return {
380
+ referralCode: passport.referralCode,
381
+ referredBy: '0x0000000000000000000000000000000000000000', // Not available in passport data
382
+ totalReferrals: passport.totalReferrals,
383
+ referralEarnings: 0 // Not available in passport data
384
+ };
385
+ }
386
+
387
+ try {
388
+ const passportId = await this._resolvePassportId(addressOrPassportId);
389
+ const [referralCode, referredBy, totalReferrals, referralEarnings] =
390
+ await this.contracts.rewards.getReferralInfo(passportId);
391
+
392
+ return {
393
+ referralCode,
394
+ referredBy,
395
+ totalReferrals: totalReferrals.toNumber(),
396
+ referralEarnings: referralEarnings.toNumber()
397
+ };
398
+ } catch (error) {
399
+ return null;
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Validate a referral code
405
+ * @param {string} referralCode - The referral code to validate
406
+ * @returns {Promise<Object|null>} - Validation result or null if no rewards contract
407
+ */
408
+ async validateReferralCode(referralCode) {
409
+ this._ensureConnected();
410
+
411
+ if (!this.contracts.rewards) return null;
412
+
413
+ try {
414
+ const [isValid, ownerPassportId] = await this.contracts.rewards.validateReferralCode(referralCode);
415
+
416
+ return {
417
+ isValid,
418
+ ownerPassportId: isValid ? ownerPassportId.toNumber() : null
419
+ };
420
+ } catch (error) {
421
+ return { isValid: false, ownerPassportId: null };
422
+ }
423
+ }
424
+
425
+ // =============================================================================
426
+ // HISTORICAL DATA FUNCTIONS
427
+ // =============================================================================
428
+
429
+ /**
430
+ * Get verification history for a platform
431
+ * @param {string|number} addressOrPassportId - Wallet address or passport ID
432
+ * @param {string} platform - The platform name
433
+ * @returns {Promise<Array|null>} - Verification history or null if no passport/archives contract
434
+ */
435
+ async getVerificationHistory(addressOrPassportId, platform) {
436
+ this._ensureConnected();
437
+
438
+ if (!this.contracts.archives) return null;
439
+
440
+ try {
441
+ const passportId = await this._resolvePassportId(addressOrPassportId);
442
+ const history = await this.contracts.archives.getVerificationHistory(passportId, platform);
443
+
444
+ return history.map(entry => ({
445
+ identifier: entry.identifier,
446
+ verifiedAt: new Date(entry.verifiedAt.toNumber() * 1000),
447
+ revokedAt: entry.revokedAt.toNumber() > 0 ? new Date(entry.revokedAt.toNumber() * 1000) : null,
448
+ proofHash: entry.proofHash,
449
+ wasRevoked: entry.wasRevoked,
450
+ revokeReason: entry.revokeReason
451
+ }));
452
+ } catch (error) {
453
+ return null;
454
+ }
455
+ }
456
+
457
+ /**
458
+ * Get platform usage statistics
459
+ * @param {string|number} addressOrPassportId - Wallet address or passport ID
460
+ * @param {string} platform - The platform name
461
+ * @returns {Promise<Object|null>} - Platform history or null if no passport/archives contract
462
+ */
463
+ async getPlatformHistory(addressOrPassportId, platform) {
464
+ this._ensureConnected();
465
+
466
+ if (!this.contracts.archives) return null;
467
+
468
+ try {
469
+ const passportId = await this._resolvePassportId(addressOrPassportId);
470
+ const history = await this.contracts.archives.getPlatformHistory(passportId, platform);
471
+
472
+ return {
473
+ totalVerifications: history.totalVerifications.toNumber(),
474
+ totalRevocations: history.totalRevocations.toNumber(),
475
+ historicalIdentifiers: history.historicalIdentifiers,
476
+ firstVerificationAt: history.firstVerificationAt.toNumber() > 0 ?
477
+ new Date(history.firstVerificationAt.toNumber() * 1000) : null,
478
+ lastRevocationAt: history.lastRevocationAt.toNumber() > 0 ?
479
+ new Date(history.lastRevocationAt.toNumber() * 1000) : null
480
+ };
481
+ } catch (error) {
482
+ return null;
483
+ }
484
+ }
485
+
486
+ // =============================================================================
487
+ // PLATFORM CONFIGURATION FUNCTIONS
488
+ // =============================================================================
489
+
490
+ /**
491
+ * Get platform configuration
492
+ * @param {string} platform - The platform name
493
+ * @returns {Promise<Object|null>} - Platform config or null if no platforms contract
494
+ */
495
+ async getPlatformConfig(platform) {
496
+ this._ensureConnected();
497
+
498
+ if (!this.contracts.platforms) return null;
499
+
500
+ try {
501
+ const [isSupported, platformType, requiredPlatforms, pointReward, enablePointPunishment, punishmentPeriodDays] =
502
+ await this.contracts.platforms.getPlatformConfig(platform);
503
+
504
+ return {
505
+ isSupported,
506
+ platformType,
507
+ requiredPlatforms,
508
+ pointReward: pointReward.toNumber(),
509
+ enablePointPunishment,
510
+ punishmentPeriodDays: punishmentPeriodDays.toNumber()
511
+ };
512
+ } catch (error) {
513
+ return null;
514
+ }
515
+ }
516
+
198
517
  /**
199
518
  * Get supported platforms
200
519
  * @returns {Promise<string[]>} - List of supported platforms
201
520
  */
202
521
  async getSupportedPlatforms() {
203
522
  this._ensureConnected();
204
- return await this.contract.getSupportedPlatforms();
523
+
524
+ if (this.contracts.platforms) {
525
+ return await this.contracts.platforms.getSupportedPlatforms();
526
+ }
527
+
528
+ // If platforms contract not available, return empty array
529
+ return [];
205
530
  }
206
531
 
207
532
  /**
@@ -210,11 +535,30 @@ class PasslySDK {
210
535
  */
211
536
  async getSupportedCategories() {
212
537
  this._ensureConnected();
213
- return await this.contract.getSupportedCategories();
538
+ return await this.contracts.passly.getSupportedCategories();
539
+ }
540
+
541
+ /**
542
+ * Check if a platform is supported
543
+ * @param {string} platform - The platform name
544
+ * @returns {Promise<boolean>} - Whether the platform is supported
545
+ */
546
+ async isPlatformSupported(platform) {
547
+ this._ensureConnected();
548
+
549
+ if (this.contracts.platforms) {
550
+ return await this.contracts.platforms.isPlatformSupported(platform);
551
+ }
552
+
553
+ return false;
214
554
  }
215
555
 
556
+ // =============================================================================
557
+ // CONVENIENCE & UTILITY FUNCTIONS
558
+ // =============================================================================
559
+
216
560
  /**
217
- * Helper method to get a user's active verifications by wallet address
561
+ * Get user's active verifications by wallet address
218
562
  * @param {string} address - The wallet address
219
563
  * @returns {Promise<Object|null>} - Object of platforms and identifiers, or null if no passport
220
564
  */
@@ -245,143 +589,77 @@ class PasslySDK {
245
589
  }
246
590
 
247
591
  /**
248
- * Get a user's identifier on a specific platform
249
- * @param {string} address - The wallet address
250
- * @param {string} platform - The platform to check
251
- * @returns {Promise<string|null>} - The identifier or null if not verified
252
- */
253
- async getPlatformIdentifier(address, platform) {
254
- const verifications = await this.getUserVerifications(address);
255
- if (!verifications) return null;
256
- return verifications[platform.toLowerCase()] || null;
257
- }
258
-
259
- // CONVENIENCE FUNCTIONS FOR ENHANCED IDENTITY VERIFICATION
260
-
261
- /**
262
- * Get how long a user has been verified on a specific platform
592
+ * Get comprehensive user profile
263
593
  * @param {string} address - The wallet address
264
- * @param {string} platform - The platform to check
265
- * @returns {Promise<Object|null>} - Object with verification age data or null if not verified
594
+ * @returns {Promise<Object|null>} - Complete user profile or null if no passport
266
595
  */
267
- async getVerificationAge(address, platform) {
596
+ async getUserProfile(address) {
268
597
  const passport = await this.getPassport(address);
269
- if (!passport || !passport.verifications[platform.toLowerCase()]) {
270
- return null;
271
- }
272
-
273
- const verification = passport.verifications[platform.toLowerCase()];
274
- if (!verification.active) return null;
598
+ if (!passport) return null;
275
599
 
276
- const now = new Date();
277
- const verifiedAt = verification.verifiedAt;
278
- const ageInMs = now - verifiedAt;
279
- const ageInDays = Math.floor(ageInMs / (1000 * 60 * 60 * 24));
280
- const ageInHours = Math.floor(ageInMs / (1000 * 60 * 60));
281
- const ageInMinutes = Math.floor(ageInMs / (1000 * 60));
600
+ const [pointBreakdown, referralInfo] = await Promise.all([
601
+ this.getPointBreakdown(address).catch(() => null),
602
+ this.getReferralInfo(address).catch(() => null)
603
+ ]);
282
604
 
283
605
  return {
284
- platform: platform.toLowerCase(),
285
- identifier: verification.identifier,
286
- verifiedAt: verifiedAt,
287
- ageInMs,
288
- ageInMinutes,
289
- ageInHours,
290
- ageInDays,
291
- humanReadable: ageInDays > 0
292
- ? `${ageInDays} day${ageInDays !== 1 ? 's' : ''}`
293
- : ageInHours > 0
294
- ? `${ageInHours} hour${ageInHours !== 1 ? 's' : ''}`
295
- : `${ageInMinutes} minute${ageInMinutes !== 1 ? 's' : ''}`
606
+ ...passport,
607
+ points: pointBreakdown,
608
+ referrals: referralInfo
296
609
  };
297
610
  }
298
611
 
299
612
  /**
300
- * Get the earliest verification for a user (their "account age" in the Passly ecosystem)
613
+ * Calculate verification strength score for a user (0-100)
301
614
  * @param {string} address - The wallet address
302
- * @returns {Promise<Object|null>} - Object with earliest verification data or null if no verifications
303
- */
304
- async getEarliestVerification(address) {
305
- const passport = await this.getPassport(address);
306
- if (!passport || passport.platforms.length === 0) {
307
- return null;
308
- }
309
-
310
- let earliest = null;
311
- let earliestDate = null;
312
-
313
- for (const platform of passport.platforms) {
314
- const verification = passport.verifications[platform];
315
- if (verification.active && (!earliestDate || verification.verifiedAt < earliestDate)) {
316
- earliestDate = verification.verifiedAt;
317
- earliest = {
318
- platform,
319
- identifier: verification.identifier,
320
- verifiedAt: verification.verifiedAt,
321
- proofHash: verification.proofHash
322
- };
323
- }
324
- }
325
-
326
- if (earliest) {
327
- const now = new Date();
328
- const ageInMs = now - earliest.verifiedAt;
329
- const ageInDays = Math.floor(ageInMs / (1000 * 60 * 60 * 24));
330
-
331
- return {
332
- ...earliest,
333
- ageInDays,
334
- humanReadable: `${ageInDays} day${ageInDays !== 1 ? 's' : ''} ago`
335
- };
336
- }
337
-
338
- return null;
339
- }
340
-
341
- /**
342
- * Calculate a verification strength score for a user (0-100)
343
- * @param {string} address - The wallet address
344
- * @returns {Promise<Object|null>} - Object with verification strength data or null if no passport
615
+ * @returns {Promise<Object|null>} - Verification strength data or null if no passport
345
616
  */
346
617
  async getVerificationStrength(address) {
347
618
  const passport = await this.getPassport(address);
348
619
  if (!passport) return null;
349
620
 
350
- const now = new Date();
351
621
  let score = 0;
352
622
  let breakdown = {
353
623
  platformCount: 0,
354
624
  ageBonus: 0,
355
625
  diversityBonus: 0,
626
+ pointsBonus: 0,
356
627
  totalScore: 0
357
628
  };
358
629
 
359
- // Base score: 20 points per verified platform (max 80 points for 4+ platforms)
630
+ // Base score: 15 points per verified platform (max 75 points for 5+ platforms)
360
631
  const activePlatforms = passport.platforms.filter(platform =>
361
632
  passport.verifications[platform].active
362
633
  );
363
- breakdown.platformCount = Math.min(activePlatforms.length * 20, 80);
634
+ breakdown.platformCount = Math.min(activePlatforms.length * 15, 75);
364
635
  score += breakdown.platformCount;
365
636
 
366
- // Age bonus: up to 15 points based on earliest verification age
367
- const earliest = await this.getEarliestVerification(address);
368
- if (earliest) {
369
- const ageInDays = earliest.ageInDays;
370
- // Give more points for older verifications (max 15 points at 365+ days)
371
- breakdown.ageBonus = Math.min(Math.floor(ageInDays / 24.33), 15); // ~15 points at 1 year
372
- score += breakdown.ageBonus;
373
- }
637
+ // Age bonus: up to 10 points based on passport age
638
+ const now = new Date();
639
+ const ageInDays = Math.floor((now - passport.createdAt) / (1000 * 60 * 60 * 24));
640
+ breakdown.ageBonus = Math.min(Math.floor(ageInDays / 30), 10);
641
+ score += breakdown.ageBonus;
374
642
 
375
- // Diversity bonus: 5 points if they have both social and development platforms
643
+ // Diversity bonus: 10 points if they have multiple platform types
376
644
  const socialPlatforms = ['twitter', 'discord', 'telegram', 'instagram'];
377
645
  const devPlatforms = ['github', 'gitlab'];
646
+ const chainPlatforms = ['solana', 'ethereum'];
378
647
 
379
- const hasSocial = activePlatforms.some(platform => socialPlatforms.includes(platform));
380
- const hasDev = activePlatforms.some(platform => devPlatforms.includes(platform));
648
+ const types = [
649
+ activePlatforms.some(p => socialPlatforms.includes(p)),
650
+ activePlatforms.some(p => devPlatforms.includes(p)),
651
+ activePlatforms.some(p => chainPlatforms.includes(p))
652
+ ].filter(Boolean);
381
653
 
382
- if (hasSocial && hasDev) {
383
- breakdown.diversityBonus = 5;
384
- score += 5;
654
+ if (types.length >= 2) {
655
+ breakdown.diversityBonus = 10;
656
+ score += 10;
657
+ }
658
+
659
+ // Points bonus: up to 5 points based on total points
660
+ if (passport.totalPoints > 0) {
661
+ breakdown.pointsBonus = Math.min(Math.floor(passport.totalPoints / 100), 5);
662
+ score += breakdown.pointsBonus;
385
663
  }
386
664
 
387
665
  breakdown.totalScore = Math.min(score, 100);
@@ -394,63 +672,51 @@ class PasslySDK {
394
672
  breakdown.totalScore >= 20 ? 'D' : 'F',
395
673
  breakdown,
396
674
  activePlatforms: activePlatforms.length,
397
- accountAge: earliest ? earliest.ageInDays : 0
675
+ accountAge: ageInDays
398
676
  };
399
- }
677
+ }
400
678
 
401
679
  /**
402
- * Get users by category (requires querying multiple passport IDs)
403
- * Note: This is a simplified version that checks known passport IDs
404
- * In a real implementation, you might want to use The Graph or similar indexing
405
- * @param {string} category - The category to search for
406
- * @param {number} limit - Maximum number of results
407
- * @param {number} startId - Starting passport ID to search from
408
- * @returns {Promise<Array>} - Array of passport data matching the category
680
+ * Get system configuration
681
+ * @returns {Promise<Object>} - System configuration
409
682
  */
410
- async getUsersByCategory(category, limit = 10, startId = 1) {
683
+ async getSystemConfig() {
411
684
  this._ensureConnected();
412
685
 
413
- const results = [];
414
- const normalizedCategory = category.toLowerCase();
415
- let currentId = startId;
416
- let found = 0;
417
- let attempts = 0;
418
- const maxAttempts = limit * 10; // Prevent infinite loops
686
+ const [supportedPlatforms, supportedCategories] = await Promise.all([
687
+ this.getSupportedPlatforms().catch(() => []),
688
+ this.getSupportedCategories().catch(() => [])
689
+ ]);
419
690
 
420
- while (found < limit && attempts < maxAttempts) {
691
+ let pointConfig = null;
692
+ if (this.contracts.rewards) {
421
693
  try {
422
- const [owner, createdAt, verificationCount, passportCategory] =
423
- await this.contract.getPassportData(currentId);
424
-
425
- if (passportCategory.toLowerCase() === normalizedCategory) {
426
- const platforms = await this.contract.getVerifiedPlatforms(currentId);
427
-
428
- results.push({
429
- id: currentId,
430
- owner,
431
- createdAt: new Date(createdAt.toNumber() * 1000),
432
- verificationCount: verificationCount.toNumber(),
433
- category: passportCategory,
434
- platforms
435
- });
436
-
437
- found++;
438
- }
694
+ const [dailyHolding, referral, referee] = await this.contracts.rewards.getPointConfig();
695
+ pointConfig = {
696
+ dailyHolding: dailyHolding.toNumber(),
697
+ referral: referral.toNumber(),
698
+ referee: referee.toNumber()
699
+ };
439
700
  } catch (error) {
440
- // Passport doesn't exist, continue to next ID
701
+ // Ignore if not available
441
702
  }
442
-
443
- currentId++;
444
- attempts++;
445
703
  }
446
704
 
447
- return results;
705
+ return {
706
+ supportedPlatforms,
707
+ supportedCategories,
708
+ pointConfig,
709
+ contracts: {
710
+ passly: this.config.addresses.passly,
711
+ platforms: this.config.addresses.platforms || null,
712
+ archives: this.config.addresses.archives || null,
713
+ rewards: this.config.addresses.rewards || null
714
+ }
715
+ };
448
716
  }
449
717
 
450
- // PROOF HASH UTILITIES
451
-
452
718
  /**
453
- * Get the proof hash for a specific platform verification
719
+ * Get proof hash for a specific platform verification
454
720
  * @param {string} address - The wallet address
455
721
  * @param {string} platform - The platform to get proof hash for
456
722
  * @returns {Promise<string|null>} - The proof hash or null if not verified
@@ -466,29 +732,6 @@ class PasslySDK {
466
732
 
467
733
  return verification.proofHash;
468
734
  }
469
-
470
- /**
471
- * Get all proof hashes for all verified platforms
472
- * @param {string} address - The wallet address
473
- * @returns {Promise<Object|null>} - Object mapping platforms to proof hashes or null if no passport
474
- */
475
- async getAllProofHashes(address) {
476
- const passport = await this.getPassport(address);
477
- if (!passport) return null;
478
-
479
- const proofHashes = {};
480
-
481
- for (const platform of passport.platforms) {
482
- const verification = passport.verifications[platform];
483
- if (verification.active) {
484
- proofHashes[platform] = verification.proofHash;
485
- }
486
- }
487
-
488
- return proofHashes;
489
- }
490
-
491
-
492
735
  }
493
736
 
494
737
  export default PasslySDK;