@passly/passly-sdk 0.1.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/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Passly SDK
2
+
3
+ Official JavaScript SDK for the Passly identity protocol - a social identity layer that helps verify user identities and works as an anti-sybil tool.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @passly/passly-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```javascript
14
+ import PasslySDK from '@passly/passly-sdk';
15
+
16
+ // Initialize the SDK
17
+ const passly = new PasslySDK();
18
+
19
+ // Connect to the contract
20
+ await passly.connect();
21
+
22
+ // Check if a user has a passport
23
+ const hasPassport = await passly.hasPassport('0x1234...');
24
+
25
+ // Get complete passport data
26
+ const passport = await passly.getPassport('0x1234...');
27
+ console.log(passport);
28
+ ```
29
+
30
+ ## Core Features
31
+
32
+ - ✅ **Identity Verification**: Check if users have verified social accounts
33
+ - ✅ **Anti-Sybil Protection**: Verify unique identity across platforms
34
+ - ✅ **Multiple Platforms**: Twitter, Discord, GitHub, Telegram support
35
+ - ✅ **Verification Strength**: Calculate identity confidence scores
36
+ - ✅ **Account Age**: Track how long identities have been verified
37
+
38
+ ## Links
39
+
40
+ - [Documentation](https://passly.xyz/docs)
41
+ - [Website](https://passly.xyz)
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@passly/passly-sdk",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Official SDK for Passly identity protocol - social identity verification for Web3",
6
+ "main": "src/passly-sdk.js",
7
+ "dependencies": {
8
+ "ethers": "^5.7.2"
9
+ },
10
+ "keywords": [
11
+ "web3",
12
+ "identity",
13
+ "verification",
14
+ "did",
15
+ "social",
16
+ "anti-sybil",
17
+ "blockchain",
18
+ "ethereum",
19
+ "skale",
20
+ "oauth",
21
+ "passport"
22
+ ],
23
+ "author": {
24
+ "name": "0xRetroDev",
25
+ "email": "hellO@0xRetro.dev",
26
+ "url": "https://github.com/0xRetroDev"
27
+ },
28
+ "homepage": "https://passly.xyz",
29
+ "license": "MIT",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ }
33
+ }
@@ -0,0 +1,495 @@
1
+ // passly-sdk.js
2
+ import { ethers } from 'ethers';
3
+
4
+ /**
5
+ * Passly SDK - A simple interface for interacting with the Passly identity protocol
6
+ *
7
+ * This SDK provides an easy way for developers to integrate with Passly,
8
+ * a social identity layer that helps verify user identities and works as an anti-sybil tool.
9
+ */
10
+ class PasslySDK {
11
+ /**
12
+ * Initialize the Passly SDK
13
+ * @param {Object} config - Configuration options
14
+ * @param {string} [config.contractAddress] - Optional override for the Passly contract address
15
+ * @param {ethers.providers.Provider} [config.provider] - Optional ethers provider
16
+ * @param {ethers.Signer} [config.signer] - Optional ethers signer for write operations
17
+ */
18
+ constructor(config = {}) {
19
+ // Default configuration will be set when connect() is called
20
+ this.config = config;
21
+ this.contract = null;
22
+ this.isConnected = false;
23
+ }
24
+
25
+ /**
26
+ * Connect to the Passly contract
27
+ * @param {Object} options - Optional connection parameters to override constructor config
28
+ * @returns {Promise<PasslySDK>} - Returns the SDK instance
29
+ */
30
+ async connect(options = {}) {
31
+ const config = { ...this.config, ...options };
32
+
33
+ // Use default provider if none provided
34
+ if (!config.provider) {
35
+ config.provider = new ethers.providers.JsonRpcProvider('https://testnet.skalenodes.com/v1/aware-fake-trim-testnet');
36
+ }
37
+
38
+ // If contract address isn't provided, use the default deployment
39
+ // This would typically be set to your production deployment
40
+ config.contractAddress = config.contractAddress || '0xB9eaC2E3f9c1171fB9d05eFC8D7af311684B9113';
41
+
42
+ // Load contract ABI
43
+ const abi = [
44
+ "function getPassportByAddress(address user) external view returns (uint256)",
45
+ "function getPassportData(uint256 passportId) external view returns (address owner, uint256 createdAt, uint256 verificationCount, string memory category)",
46
+ "function getVerifiedPlatforms(uint256 passportId) external view returns (string[] memory)",
47
+ "function getVerification(uint256 passportId, string calldata platform) external view returns (string memory identifier, uint256 verifiedAt, bytes32 proofHash, bool active)",
48
+ "function isIdentifierVerified(string calldata platform, string calldata identifier) external view returns (bool isVerified, uint256 passportId)",
49
+ "function getSupportedPlatforms() external view returns (string[] memory)",
50
+ "function getSupportedCategories() external view returns (string[] memory)",
51
+ ];
52
+
53
+ // Initialize the contract
54
+ if (config.signer) {
55
+ // Connect with signer for write operations
56
+ this.contract = new ethers.Contract(config.contractAddress, abi, config.signer);
57
+ } else {
58
+ // Connect with provider for read-only operations
59
+ this.contract = new ethers.Contract(config.contractAddress, abi, config.provider);
60
+ }
61
+
62
+ this.config = config;
63
+ this.isConnected = true;
64
+ return this;
65
+ }
66
+
67
+ /**
68
+ * Ensure the SDK is connected before performing operations
69
+ * @private
70
+ */
71
+ _ensureConnected() {
72
+ if (!this.isConnected) {
73
+ throw new Error('Passly SDK not connected. Call connect() first.');
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Get a user's passport ID from their wallet address
79
+ * @param {string} address - The wallet address to check
80
+ * @returns {Promise<number|null>} - The passport ID or null if none exists
81
+ */
82
+ async getPassportId(address) {
83
+ this._ensureConnected();
84
+
85
+ try {
86
+ const passportId = await this.contract.getPassportByAddress(address);
87
+ return passportId.toNumber();
88
+ } catch (error) {
89
+ // If the error is "User has no passport", return null
90
+ if (error.message.includes('User has no passport')) {
91
+ return null;
92
+ }
93
+ throw error;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Check if a user has a passport
99
+ * @param {string} address - The wallet address to check
100
+ * @returns {Promise<boolean>} - Whether the user has a passport
101
+ */
102
+ async hasPassport(address) {
103
+ const passportId = await this.getPassportId(address);
104
+ return passportId !== null;
105
+ }
106
+
107
+ /**
108
+ * Get complete passport data for a user
109
+ * @param {string} address - The wallet address
110
+ * @returns {Promise<Object|null>} - The passport data or null if no passport
111
+ */
112
+ async getPassport(address) {
113
+ this._ensureConnected();
114
+
115
+ let passportId;
116
+ try {
117
+ passportId = await this.getPassportId(address);
118
+ } catch (error) {
119
+ return null;
120
+ }
121
+
122
+ if (!passportId) return null;
123
+
124
+ const [owner, createdAt, verificationCount, category] = await this.contract.getPassportData(passportId);
125
+ const platforms = await this.contract.getVerifiedPlatforms(passportId);
126
+
127
+ // Gather all verifications
128
+ const verifications = {};
129
+ for (const platform of platforms) {
130
+ const [identifier, verifiedAt, proofHash, active] = await this.contract.getVerification(
131
+ passportId,
132
+ platform
133
+ );
134
+
135
+ verifications[platform] = {
136
+ identifier,
137
+ verifiedAt: new Date(verifiedAt.toNumber() * 1000),
138
+ proofHash: proofHash,
139
+ active
140
+ };
141
+ }
142
+
143
+ return {
144
+ id: passportId,
145
+ owner: owner,
146
+ createdAt: new Date(createdAt.toNumber() * 1000),
147
+ verificationCount: verificationCount.toNumber(),
148
+ category,
149
+ platforms,
150
+ verifications
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Get all verification data for a passport
156
+ * @param {number} passportId - The passport ID
157
+ * @returns {Promise<Object>} - Object containing verification details
158
+ */
159
+ async getVerifications(passportId) {
160
+ this._ensureConnected();
161
+
162
+ const platforms = await this.contract.getVerifiedPlatforms(passportId);
163
+ const verifications = {};
164
+
165
+ for (const platform of platforms) {
166
+ const [identifier, verifiedAt, proofHash, active] = await this.contract.getVerification(
167
+ passportId,
168
+ platform
169
+ );
170
+
171
+ verifications[platform] = {
172
+ identifier,
173
+ verifiedAt: new Date(verifiedAt.toNumber() * 1000),
174
+ proofHash: proofHash,
175
+ active
176
+ };
177
+ }
178
+
179
+ return verifications;
180
+ }
181
+
182
+ /**
183
+ * Check if a social media account identifier is verified
184
+ * @param {string} platform - The platform (e.g., "twitter")
185
+ * @param {string} identifier - The account identifier (e.g., username)
186
+ * @returns {Promise<{isVerified: boolean, passportId: number|null}>} - Verification status and passport ID if verified
187
+ */
188
+ async isAccountVerified(platform, identifier) {
189
+ this._ensureConnected();
190
+
191
+ const [isVerified, passportId] = await this.contract.isIdentifierVerified(platform, identifier);
192
+
193
+ return {
194
+ isVerified,
195
+ passportId: isVerified ? passportId.toNumber() : null
196
+ };
197
+ }
198
+
199
+ /**
200
+ * Get supported platforms
201
+ * @returns {Promise<string[]>} - List of supported platforms
202
+ */
203
+ async getSupportedPlatforms() {
204
+ this._ensureConnected();
205
+ return await this.contract.getSupportedPlatforms();
206
+ }
207
+
208
+ /**
209
+ * Get supported categories
210
+ * @returns {Promise<string[]>} - List of supported categories
211
+ */
212
+ async getSupportedCategories() {
213
+ this._ensureConnected();
214
+ return await this.contract.getSupportedCategories();
215
+ }
216
+
217
+ /**
218
+ * Helper method to get a user's active verifications by wallet address
219
+ * @param {string} address - The wallet address
220
+ * @returns {Promise<Object|null>} - Object of platforms and identifiers, or null if no passport
221
+ */
222
+ async getUserVerifications(address) {
223
+ const passport = await this.getPassport(address);
224
+ if (!passport) return null;
225
+
226
+ const result = {};
227
+ for (const platform in passport.verifications) {
228
+ const verification = passport.verifications[platform];
229
+ if (verification.active) {
230
+ result[platform] = verification.identifier;
231
+ }
232
+ }
233
+
234
+ return result;
235
+ }
236
+
237
+ /**
238
+ * Check if a user has verified a specific platform
239
+ * @param {string} address - The wallet address
240
+ * @param {string} platform - The platform to check
241
+ * @returns {Promise<boolean>} - Whether the user has verified this platform
242
+ */
243
+ async hasVerifiedPlatform(address, platform) {
244
+ const verifications = await this.getUserVerifications(address);
245
+ return verifications !== null && verifications[platform.toLowerCase()] !== undefined;
246
+ }
247
+
248
+ /**
249
+ * Get a user's identifier on a specific platform
250
+ * @param {string} address - The wallet address
251
+ * @param {string} platform - The platform to check
252
+ * @returns {Promise<string|null>} - The identifier or null if not verified
253
+ */
254
+ async getPlatformIdentifier(address, platform) {
255
+ const verifications = await this.getUserVerifications(address);
256
+ if (!verifications) return null;
257
+ return verifications[platform.toLowerCase()] || null;
258
+ }
259
+
260
+ // CONVENIENCE FUNCTIONS FOR ENHANCED IDENTITY VERIFICATION
261
+
262
+ /**
263
+ * Get how long a user has been verified on a specific platform
264
+ * @param {string} address - The wallet address
265
+ * @param {string} platform - The platform to check
266
+ * @returns {Promise<Object|null>} - Object with verification age data or null if not verified
267
+ */
268
+ async getVerificationAge(address, platform) {
269
+ const passport = await this.getPassport(address);
270
+ if (!passport || !passport.verifications[platform.toLowerCase()]) {
271
+ return null;
272
+ }
273
+
274
+ const verification = passport.verifications[platform.toLowerCase()];
275
+ if (!verification.active) return null;
276
+
277
+ const now = new Date();
278
+ const verifiedAt = verification.verifiedAt;
279
+ const ageInMs = now - verifiedAt;
280
+ const ageInDays = Math.floor(ageInMs / (1000 * 60 * 60 * 24));
281
+ const ageInHours = Math.floor(ageInMs / (1000 * 60 * 60));
282
+ const ageInMinutes = Math.floor(ageInMs / (1000 * 60));
283
+
284
+ return {
285
+ platform: platform.toLowerCase(),
286
+ identifier: verification.identifier,
287
+ verifiedAt: verifiedAt,
288
+ ageInMs,
289
+ ageInMinutes,
290
+ ageInHours,
291
+ ageInDays,
292
+ humanReadable: ageInDays > 0
293
+ ? `${ageInDays} day${ageInDays !== 1 ? 's' : ''}`
294
+ : ageInHours > 0
295
+ ? `${ageInHours} hour${ageInHours !== 1 ? 's' : ''}`
296
+ : `${ageInMinutes} minute${ageInMinutes !== 1 ? 's' : ''}`
297
+ };
298
+ }
299
+
300
+ /**
301
+ * Get the earliest verification for a user (their "account age" in the Passly ecosystem)
302
+ * @param {string} address - The wallet address
303
+ * @returns {Promise<Object|null>} - Object with earliest verification data or null if no verifications
304
+ */
305
+ async getEarliestVerification(address) {
306
+ const passport = await this.getPassport(address);
307
+ if (!passport || passport.platforms.length === 0) {
308
+ return null;
309
+ }
310
+
311
+ let earliest = null;
312
+ let earliestDate = null;
313
+
314
+ for (const platform of passport.platforms) {
315
+ const verification = passport.verifications[platform];
316
+ if (verification.active && (!earliestDate || verification.verifiedAt < earliestDate)) {
317
+ earliestDate = verification.verifiedAt;
318
+ earliest = {
319
+ platform,
320
+ identifier: verification.identifier,
321
+ verifiedAt: verification.verifiedAt,
322
+ proofHash: verification.proofHash
323
+ };
324
+ }
325
+ }
326
+
327
+ if (earliest) {
328
+ const now = new Date();
329
+ const ageInMs = now - earliest.verifiedAt;
330
+ const ageInDays = Math.floor(ageInMs / (1000 * 60 * 60 * 24));
331
+
332
+ return {
333
+ ...earliest,
334
+ ageInDays,
335
+ humanReadable: `${ageInDays} day${ageInDays !== 1 ? 's' : ''} ago`
336
+ };
337
+ }
338
+
339
+ return null;
340
+ }
341
+
342
+ /**
343
+ * Calculate a verification strength score for a user (0-100)
344
+ * @param {string} address - The wallet address
345
+ * @returns {Promise<Object|null>} - Object with verification strength data or null if no passport
346
+ */
347
+ async getVerificationStrength(address) {
348
+ const passport = await this.getPassport(address);
349
+ if (!passport) return null;
350
+
351
+ const now = new Date();
352
+ let score = 0;
353
+ let breakdown = {
354
+ platformCount: 0,
355
+ ageBonus: 0,
356
+ diversityBonus: 0,
357
+ totalScore: 0
358
+ };
359
+
360
+ // Base score: 20 points per verified platform (max 80 points for 4+ platforms)
361
+ const activePlatforms = passport.platforms.filter(platform =>
362
+ passport.verifications[platform].active
363
+ );
364
+ breakdown.platformCount = Math.min(activePlatforms.length * 20, 80);
365
+ score += breakdown.platformCount;
366
+
367
+ // Age bonus: up to 15 points based on earliest verification age
368
+ const earliest = await this.getEarliestVerification(address);
369
+ if (earliest) {
370
+ const ageInDays = earliest.ageInDays;
371
+ // Give more points for older verifications (max 15 points at 365+ days)
372
+ breakdown.ageBonus = Math.min(Math.floor(ageInDays / 24.33), 15); // ~15 points at 1 year
373
+ score += breakdown.ageBonus;
374
+ }
375
+
376
+ // Diversity bonus: 5 points if they have both social and development platforms
377
+ const socialPlatforms = ['twitter', 'discord', 'telegram', 'instagram'];
378
+ const devPlatforms = ['github', 'gitlab'];
379
+
380
+ const hasSocial = activePlatforms.some(platform => socialPlatforms.includes(platform));
381
+ const hasDev = activePlatforms.some(platform => devPlatforms.includes(platform));
382
+
383
+ if (hasSocial && hasDev) {
384
+ breakdown.diversityBonus = 5;
385
+ score += 5;
386
+ }
387
+
388
+ breakdown.totalScore = Math.min(score, 100);
389
+
390
+ return {
391
+ score: breakdown.totalScore,
392
+ grade: breakdown.totalScore >= 80 ? 'A' :
393
+ breakdown.totalScore >= 60 ? 'B' :
394
+ breakdown.totalScore >= 40 ? 'C' :
395
+ breakdown.totalScore >= 20 ? 'D' : 'F',
396
+ breakdown,
397
+ activePlatforms: activePlatforms.length,
398
+ accountAge: earliest ? earliest.ageInDays : 0
399
+ };
400
+ }
401
+
402
+ /**
403
+ * Get users by category (requires querying multiple passport IDs)
404
+ * Note: This is a simplified version that checks known passport IDs
405
+ * In a real implementation, you might want to use The Graph or similar indexing
406
+ * @param {string} category - The category to search for
407
+ * @param {number} limit - Maximum number of results
408
+ * @param {number} startId - Starting passport ID to search from
409
+ * @returns {Promise<Array>} - Array of passport data matching the category
410
+ */
411
+ async getUsersByCategory(category, limit = 10, startId = 1) {
412
+ this._ensureConnected();
413
+
414
+ const results = [];
415
+ const normalizedCategory = category.toLowerCase();
416
+ let currentId = startId;
417
+ let found = 0;
418
+ let attempts = 0;
419
+ const maxAttempts = limit * 10; // Prevent infinite loops
420
+
421
+ while (found < limit && attempts < maxAttempts) {
422
+ try {
423
+ const [owner, createdAt, verificationCount, passportCategory] =
424
+ await this.contract.getPassportData(currentId);
425
+
426
+ if (passportCategory.toLowerCase() === normalizedCategory) {
427
+ const platforms = await this.contract.getVerifiedPlatforms(currentId);
428
+
429
+ results.push({
430
+ id: currentId,
431
+ owner,
432
+ createdAt: new Date(createdAt.toNumber() * 1000),
433
+ verificationCount: verificationCount.toNumber(),
434
+ category: passportCategory,
435
+ platforms
436
+ });
437
+
438
+ found++;
439
+ }
440
+ } catch (error) {
441
+ // Passport doesn't exist, continue to next ID
442
+ }
443
+
444
+ currentId++;
445
+ attempts++;
446
+ }
447
+
448
+ return results;
449
+ }
450
+
451
+ // PROOF HASH UTILITIES
452
+
453
+ /**
454
+ * Get the proof hash for a specific platform verification
455
+ * @param {string} address - The wallet address
456
+ * @param {string} platform - The platform to get proof hash for
457
+ * @returns {Promise<string|null>} - The proof hash or null if not verified
458
+ */
459
+ async getProofHash(address, platform) {
460
+ const passport = await this.getPassport(address);
461
+ if (!passport || !passport.verifications[platform.toLowerCase()]) {
462
+ return null;
463
+ }
464
+
465
+ const verification = passport.verifications[platform.toLowerCase()];
466
+ if (!verification.active) return null;
467
+
468
+ return verification.proofHash;
469
+ }
470
+
471
+ /**
472
+ * Get all proof hashes for all verified platforms
473
+ * @param {string} address - The wallet address
474
+ * @returns {Promise<Object|null>} - Object mapping platforms to proof hashes or null if no passport
475
+ */
476
+ async getAllProofHashes(address) {
477
+ const passport = await this.getPassport(address);
478
+ if (!passport) return null;
479
+
480
+ const proofHashes = {};
481
+
482
+ for (const platform of passport.platforms) {
483
+ const verification = passport.verifications[platform];
484
+ if (verification.active) {
485
+ proofHashes[platform] = verification.proofHash;
486
+ }
487
+ }
488
+
489
+ return proofHashes;
490
+ }
491
+
492
+
493
+ }
494
+
495
+ export default PasslySDK;