@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.
- package/package.json +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
|
+
"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/
|
|
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
|
|
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] -
|
|
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.
|
|
31
|
+
this.contracts = {};
|
|
22
32
|
this.isConnected = false;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
/**
|
|
26
|
-
* Connect to the Passly
|
|
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
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
|
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}
|
|
243
|
+
* @param {string|number} addressOrPassportId - Wallet address or passport ID
|
|
156
244
|
* @returns {Promise<Object>} - Object containing verification details
|
|
157
245
|
*/
|
|
158
|
-
async getVerifications(
|
|
246
|
+
async getVerifications(addressOrPassportId) {
|
|
159
247
|
this._ensureConnected();
|
|
160
248
|
|
|
161
|
-
const
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
*
|
|
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
|
|
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
|
-
* @
|
|
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
|
|
596
|
+
async getUserProfile(address) {
|
|
268
597
|
const passport = await this.getPassport(address);
|
|
269
|
-
if (!passport
|
|
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
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
*
|
|
613
|
+
* Calculate verification strength score for a user (0-100)
|
|
301
614
|
* @param {string} address - The wallet address
|
|
302
|
-
* @returns {Promise<Object|null>} -
|
|
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:
|
|
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 *
|
|
634
|
+
breakdown.platformCount = Math.min(activePlatforms.length * 15, 75);
|
|
364
635
|
score += breakdown.platformCount;
|
|
365
636
|
|
|
366
|
-
// Age bonus: up to
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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:
|
|
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
|
|
380
|
-
|
|
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 (
|
|
383
|
-
breakdown.diversityBonus =
|
|
384
|
-
score +=
|
|
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:
|
|
675
|
+
accountAge: ageInDays
|
|
398
676
|
};
|
|
399
|
-
}
|
|
677
|
+
}
|
|
400
678
|
|
|
401
679
|
/**
|
|
402
|
-
* Get
|
|
403
|
-
*
|
|
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
|
|
683
|
+
async getSystemConfig() {
|
|
411
684
|
this._ensureConnected();
|
|
412
685
|
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
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
|
-
|
|
691
|
+
let pointConfig = null;
|
|
692
|
+
if (this.contracts.rewards) {
|
|
421
693
|
try {
|
|
422
|
-
const [
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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
|
-
//
|
|
701
|
+
// Ignore if not available
|
|
441
702
|
}
|
|
442
|
-
|
|
443
|
-
currentId++;
|
|
444
|
-
attempts++;
|
|
445
703
|
}
|
|
446
704
|
|
|
447
|
-
return
|
|
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
|
|
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;
|