@neus/sdk 1.0.1 → 1.0.3
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 +150 -140
- package/cjs/client.cjs +634 -223
- package/cjs/errors.cjs +1 -0
- package/cjs/gates.cjs +1 -0
- package/cjs/index.cjs +840 -236
- package/cjs/utils.cjs +408 -12
- package/client.js +502 -244
- package/index.js +75 -64
- package/neus-logo.svg +3 -0
- package/package.json +9 -5
- package/types.d.ts +379 -82
- package/utils.js +443 -14
- package/widgets/README.md +64 -53
- package/widgets/index.js +9 -9
- package/widgets/verify-gate/dist/ProofBadge.js +51 -38
- package/widgets/verify-gate/dist/VerifyGate.js +284 -59
- package/widgets/verify-gate/index.js +13 -13
package/cjs/client.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -128,6 +129,50 @@ var ConfigurationError = class extends SDKError {
|
|
|
128
129
|
};
|
|
129
130
|
|
|
130
131
|
// utils.js
|
|
132
|
+
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
133
|
+
function encodeBase58Bytes(input) {
|
|
134
|
+
let source;
|
|
135
|
+
if (input instanceof Uint8Array) {
|
|
136
|
+
source = input;
|
|
137
|
+
} else if (input instanceof ArrayBuffer) {
|
|
138
|
+
source = new Uint8Array(input);
|
|
139
|
+
} else if (ArrayBuffer.isView(input)) {
|
|
140
|
+
source = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
|
|
141
|
+
} else if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(input)) {
|
|
142
|
+
source = new Uint8Array(input);
|
|
143
|
+
} else {
|
|
144
|
+
throw new SDKError("Unsupported non-EVM signature byte format", "INVALID_SIGNATURE_FORMAT");
|
|
145
|
+
}
|
|
146
|
+
if (source.length === 0)
|
|
147
|
+
return "";
|
|
148
|
+
let zeroes = 0;
|
|
149
|
+
while (zeroes < source.length && source[zeroes] === 0) {
|
|
150
|
+
zeroes++;
|
|
151
|
+
}
|
|
152
|
+
const iFactor = Math.log(256) / Math.log(58);
|
|
153
|
+
const size = (source.length - zeroes) * iFactor + 1 >>> 0;
|
|
154
|
+
const b58 = new Uint8Array(size);
|
|
155
|
+
let length = 0;
|
|
156
|
+
for (let i = zeroes; i < source.length; i++) {
|
|
157
|
+
let carry = source[i];
|
|
158
|
+
let j = 0;
|
|
159
|
+
for (let k = size - 1; (carry !== 0 || j < length) && k >= 0; k--, j++) {
|
|
160
|
+
carry += 256 * b58[k];
|
|
161
|
+
b58[k] = carry % 58;
|
|
162
|
+
carry = carry / 58 | 0;
|
|
163
|
+
}
|
|
164
|
+
length = j;
|
|
165
|
+
}
|
|
166
|
+
let it = size - length;
|
|
167
|
+
while (it < size && b58[it] === 0) {
|
|
168
|
+
it++;
|
|
169
|
+
}
|
|
170
|
+
let out = BASE58_ALPHABET[0].repeat(zeroes);
|
|
171
|
+
for (; it < size; it++) {
|
|
172
|
+
out += BASE58_ALPHABET[b58[it]];
|
|
173
|
+
}
|
|
174
|
+
return out;
|
|
175
|
+
}
|
|
131
176
|
function deterministicStringify(obj) {
|
|
132
177
|
if (obj === null || obj === void 0) {
|
|
133
178
|
return JSON.stringify(obj);
|
|
@@ -159,7 +204,7 @@ function constructVerificationMessage({ walletAddress, signedTimestamp, data, ve
|
|
|
159
204
|
}
|
|
160
205
|
const chainContext = typeof chain === "string" && chain.length > 0 ? chain : chainId;
|
|
161
206
|
if (!chainContext) {
|
|
162
|
-
throw new SDKError("chainId is required (or provide chain for
|
|
207
|
+
throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
|
|
163
208
|
}
|
|
164
209
|
if (chainContext === chainId && typeof chainId !== "number") {
|
|
165
210
|
throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
|
|
@@ -186,6 +231,146 @@ function validateWalletAddress(address) {
|
|
|
186
231
|
}
|
|
187
232
|
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
188
233
|
}
|
|
234
|
+
function validateUniversalAddress(address, chain) {
|
|
235
|
+
if (!address || typeof address !== "string")
|
|
236
|
+
return false;
|
|
237
|
+
const value = address.trim();
|
|
238
|
+
if (!value)
|
|
239
|
+
return false;
|
|
240
|
+
const chainRef = typeof chain === "string" ? chain.trim().toLowerCase() : "";
|
|
241
|
+
const namespace = chainRef.includes(":") ? chainRef.split(":")[0] : "";
|
|
242
|
+
if (validateWalletAddress(value))
|
|
243
|
+
return true;
|
|
244
|
+
if (namespace === "eip155")
|
|
245
|
+
return false;
|
|
246
|
+
if (namespace === "solana") {
|
|
247
|
+
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(value);
|
|
248
|
+
}
|
|
249
|
+
if (namespace === "bip122") {
|
|
250
|
+
return /^(bc1|tb1|bcrt1)[a-z0-9]{11,87}$/.test(value.toLowerCase()) || /^[13mn2][a-km-zA-HJ-NP-Z1-9]{25,62}$/.test(value);
|
|
251
|
+
}
|
|
252
|
+
if (namespace === "near") {
|
|
253
|
+
return /^[a-z0-9._-]{2,64}$/.test(value);
|
|
254
|
+
}
|
|
255
|
+
return /^[A-Za-z0-9][A-Za-z0-9._:-]{1,127}$/.test(value);
|
|
256
|
+
}
|
|
257
|
+
function toHexUtf8(value) {
|
|
258
|
+
const input = typeof value === "string" ? value : String(value || "");
|
|
259
|
+
const bytes = new TextEncoder().encode(input);
|
|
260
|
+
return `0x${Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
261
|
+
}
|
|
262
|
+
async function signMessage({ provider, message, walletAddress, chain } = {}) {
|
|
263
|
+
const msg = typeof message === "string" ? message : String(message || "");
|
|
264
|
+
if (!msg) {
|
|
265
|
+
throw new SDKError("signMessage: message is required", "INVALID_ARGUMENT");
|
|
266
|
+
}
|
|
267
|
+
const resolvedProvider = provider || (typeof window !== "undefined" && window?.ethereum ? window.ethereum : null);
|
|
268
|
+
if (!resolvedProvider) {
|
|
269
|
+
throw new SDKError("signMessage: provider is required", "SIGNER_UNAVAILABLE");
|
|
270
|
+
}
|
|
271
|
+
const chainStr = typeof chain === "string" && chain.trim().length > 0 ? chain.trim() : "eip155";
|
|
272
|
+
const namespace = chainStr.includes(":") ? chainStr.split(":")[0] || "eip155" : "eip155";
|
|
273
|
+
const resolveAddress = async () => {
|
|
274
|
+
if (typeof walletAddress === "string" && walletAddress.trim().length > 0)
|
|
275
|
+
return walletAddress;
|
|
276
|
+
if (namespace === "solana") {
|
|
277
|
+
if (resolvedProvider?.publicKey && typeof resolvedProvider.publicKey.toBase58 === "function") {
|
|
278
|
+
const pk = resolvedProvider.publicKey.toBase58();
|
|
279
|
+
if (typeof pk === "string" && pk)
|
|
280
|
+
return pk;
|
|
281
|
+
}
|
|
282
|
+
if (typeof resolvedProvider.getAddress === "function") {
|
|
283
|
+
const addr = await resolvedProvider.getAddress().catch(() => null);
|
|
284
|
+
if (typeof addr === "string" && addr)
|
|
285
|
+
return addr;
|
|
286
|
+
}
|
|
287
|
+
if (typeof resolvedProvider.address === "string" && resolvedProvider.address)
|
|
288
|
+
return resolvedProvider.address;
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
if (typeof resolvedProvider.address === "string" && resolvedProvider.address)
|
|
292
|
+
return resolvedProvider.address;
|
|
293
|
+
if (typeof resolvedProvider.getAddress === "function")
|
|
294
|
+
return await resolvedProvider.getAddress();
|
|
295
|
+
if (typeof resolvedProvider.request === "function") {
|
|
296
|
+
let accounts = await resolvedProvider.request({ method: "eth_accounts" }).catch(() => []);
|
|
297
|
+
if (!Array.isArray(accounts) || accounts.length === 0) {
|
|
298
|
+
accounts = await resolvedProvider.request({ method: "eth_requestAccounts" }).catch(() => []);
|
|
299
|
+
}
|
|
300
|
+
if (Array.isArray(accounts) && accounts[0])
|
|
301
|
+
return accounts[0];
|
|
302
|
+
}
|
|
303
|
+
return null;
|
|
304
|
+
};
|
|
305
|
+
if (namespace !== "eip155") {
|
|
306
|
+
if (typeof resolvedProvider.signMessage === "function") {
|
|
307
|
+
const encoded = typeof msg === "string" ? new TextEncoder().encode(msg) : msg;
|
|
308
|
+
const result = await resolvedProvider.signMessage(encoded);
|
|
309
|
+
if (typeof result === "string" && result)
|
|
310
|
+
return result;
|
|
311
|
+
if (result instanceof Uint8Array)
|
|
312
|
+
return encodeBase58Bytes(result);
|
|
313
|
+
if (result instanceof ArrayBuffer)
|
|
314
|
+
return encodeBase58Bytes(new Uint8Array(result));
|
|
315
|
+
if (ArrayBuffer.isView(result))
|
|
316
|
+
return encodeBase58Bytes(result);
|
|
317
|
+
if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(result))
|
|
318
|
+
return encodeBase58Bytes(result);
|
|
319
|
+
}
|
|
320
|
+
throw new SDKError("Non-EVM signing requires provider.signMessage", "SIGNER_UNAVAILABLE");
|
|
321
|
+
}
|
|
322
|
+
const address = await resolveAddress();
|
|
323
|
+
if (typeof resolvedProvider.request === "function" && address) {
|
|
324
|
+
let firstPersonalSignError = null;
|
|
325
|
+
try {
|
|
326
|
+
const sig = await resolvedProvider.request({ method: "personal_sign", params: [msg, address] });
|
|
327
|
+
if (typeof sig === "string" && sig)
|
|
328
|
+
return sig;
|
|
329
|
+
} catch (error) {
|
|
330
|
+
firstPersonalSignError = error;
|
|
331
|
+
}
|
|
332
|
+
let secondPersonalSignError = null;
|
|
333
|
+
try {
|
|
334
|
+
const sig = await resolvedProvider.request({ method: "personal_sign", params: [address, msg] });
|
|
335
|
+
if (typeof sig === "string" && sig)
|
|
336
|
+
return sig;
|
|
337
|
+
} catch (error) {
|
|
338
|
+
secondPersonalSignError = error;
|
|
339
|
+
const signatureErrorMessage = String(
|
|
340
|
+
error?.message || error?.reason || firstPersonalSignError?.message || firstPersonalSignError?.reason || ""
|
|
341
|
+
).toLowerCase();
|
|
342
|
+
const needsHex = /byte|bytes|invalid byte sequence|encoding|non-hex/i.test(signatureErrorMessage);
|
|
343
|
+
if (needsHex) {
|
|
344
|
+
try {
|
|
345
|
+
const hexMsg = toHexUtf8(msg);
|
|
346
|
+
const sig = await resolvedProvider.request({ method: "personal_sign", params: [hexMsg, address] });
|
|
347
|
+
if (typeof sig === "string" && sig)
|
|
348
|
+
return sig;
|
|
349
|
+
} catch {
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
const sig = await resolvedProvider.request({ method: "eth_sign", params: [address, msg] });
|
|
355
|
+
if (typeof sig === "string" && sig)
|
|
356
|
+
return sig;
|
|
357
|
+
} catch {
|
|
358
|
+
}
|
|
359
|
+
if (secondPersonalSignError || firstPersonalSignError) {
|
|
360
|
+
const lastError = secondPersonalSignError || firstPersonalSignError;
|
|
361
|
+
const isUserRejection = [4001, "ACTION_REJECTED"].includes(lastError?.code);
|
|
362
|
+
if (isUserRejection) {
|
|
363
|
+
throw lastError;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (typeof resolvedProvider.signMessage === "function") {
|
|
368
|
+
const result = await resolvedProvider.signMessage(msg);
|
|
369
|
+
if (typeof result === "string" && result)
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
throw new SDKError("Unable to sign message with provided wallet/provider", "SIGNER_UNAVAILABLE");
|
|
373
|
+
}
|
|
189
374
|
var NEUS_CONSTANTS = {
|
|
190
375
|
// Hub chain (where all verifications occur)
|
|
191
376
|
HUB_CHAIN_ID: 84532,
|
|
@@ -217,18 +402,97 @@ var NEUS_CONSTANTS = {
|
|
|
217
402
|
};
|
|
218
403
|
|
|
219
404
|
// client.js
|
|
405
|
+
var FALLBACK_PUBLIC_VERIFIERS = [
|
|
406
|
+
"ownership-basic",
|
|
407
|
+
"ownership-pseudonym",
|
|
408
|
+
"ownership-dns-txt",
|
|
409
|
+
"ownership-social",
|
|
410
|
+
"ownership-org-oauth",
|
|
411
|
+
"contract-ownership",
|
|
412
|
+
"nft-ownership",
|
|
413
|
+
"token-holding",
|
|
414
|
+
"wallet-link",
|
|
415
|
+
"wallet-risk",
|
|
416
|
+
"proof-of-human",
|
|
417
|
+
"agent-identity",
|
|
418
|
+
"agent-delegation",
|
|
419
|
+
"ai-content-moderation"
|
|
420
|
+
];
|
|
421
|
+
var INTERACTIVE_VERIFIERS = /* @__PURE__ */ new Set([
|
|
422
|
+
"ownership-social",
|
|
423
|
+
"ownership-org-oauth",
|
|
424
|
+
"proof-of-human"
|
|
425
|
+
]);
|
|
426
|
+
var EVM_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
|
|
220
427
|
var validateVerifierData = (verifierId, data) => {
|
|
221
428
|
if (!data || typeof data !== "object") {
|
|
222
429
|
return { valid: false, error: "Data object is required" };
|
|
223
430
|
}
|
|
224
|
-
const ownerField = verifierId === "nft-ownership" || verifierId === "token-holding" ? "ownerAddress" : "owner";
|
|
225
|
-
if (data[ownerField] && !validateWalletAddress(data[ownerField])) {
|
|
226
|
-
return { valid: false, error: `Invalid ${ownerField} address` };
|
|
227
|
-
}
|
|
228
431
|
switch (verifierId) {
|
|
229
432
|
case "ownership-basic":
|
|
230
|
-
if (!data.owner || !
|
|
231
|
-
return { valid: false, error: "owner (wallet address) is required" };
|
|
433
|
+
if (!data.owner || !validateUniversalAddress(data.owner, typeof data.chain === "string" ? data.chain : void 0)) {
|
|
434
|
+
return { valid: false, error: "owner (universal wallet address) is required" };
|
|
435
|
+
}
|
|
436
|
+
if (data.content !== void 0 && data.content !== null) {
|
|
437
|
+
if (typeof data.content !== "string") {
|
|
438
|
+
return { valid: false, error: "content must be a string when provided" };
|
|
439
|
+
}
|
|
440
|
+
if (data.content.length > 5e4) {
|
|
441
|
+
return { valid: false, error: "content exceeds 50KB inline limit" };
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (data.contentHash !== void 0 && data.contentHash !== null) {
|
|
445
|
+
if (typeof data.contentHash !== "string" || !/^0x[a-fA-F0-9]{64}$/.test(data.contentHash)) {
|
|
446
|
+
return { valid: false, error: "contentHash must be a 32-byte hex string (0x + 64 hex chars) when provided" };
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (data.contentType !== void 0 && data.contentType !== null) {
|
|
450
|
+
if (typeof data.contentType !== "string" || data.contentType.length > 100) {
|
|
451
|
+
return { valid: false, error: "contentType must be a string (max 100 chars) when provided" };
|
|
452
|
+
}
|
|
453
|
+
const base = String(data.contentType).split(";")[0].trim().toLowerCase();
|
|
454
|
+
if (!base || base.includes(" ") || !base.includes("/")) {
|
|
455
|
+
return { valid: false, error: "contentType must be a valid MIME type when provided" };
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (data.provenance !== void 0 && data.provenance !== null) {
|
|
459
|
+
if (!data.provenance || typeof data.provenance !== "object" || Array.isArray(data.provenance)) {
|
|
460
|
+
return { valid: false, error: "provenance must be an object when provided" };
|
|
461
|
+
}
|
|
462
|
+
const dk = data.provenance.declaredKind;
|
|
463
|
+
if (dk !== void 0 && dk !== null) {
|
|
464
|
+
const allowed = ["human", "ai", "mixed", "unknown"];
|
|
465
|
+
if (typeof dk !== "string" || !allowed.includes(dk)) {
|
|
466
|
+
return { valid: false, error: `provenance.declaredKind must be one of: ${allowed.join(", ")}` };
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const ai = data.provenance.aiContext;
|
|
470
|
+
if (ai !== void 0 && ai !== null) {
|
|
471
|
+
if (typeof ai !== "object" || Array.isArray(ai)) {
|
|
472
|
+
return { valid: false, error: "provenance.aiContext must be an object when provided" };
|
|
473
|
+
}
|
|
474
|
+
if (ai.generatorType !== void 0 && ai.generatorType !== null) {
|
|
475
|
+
const allowed = ["local", "saas", "agent"];
|
|
476
|
+
if (typeof ai.generatorType !== "string" || !allowed.includes(ai.generatorType)) {
|
|
477
|
+
return { valid: false, error: `provenance.aiContext.generatorType must be one of: ${allowed.join(", ")}` };
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (ai.provider !== void 0 && ai.provider !== null) {
|
|
481
|
+
if (typeof ai.provider !== "string" || ai.provider.length > 64) {
|
|
482
|
+
return { valid: false, error: "provenance.aiContext.provider must be a string (max 64 chars) when provided" };
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (ai.model !== void 0 && ai.model !== null) {
|
|
486
|
+
if (typeof ai.model !== "string" || ai.model.length > 128) {
|
|
487
|
+
return { valid: false, error: "provenance.aiContext.model must be a string (max 128 chars) when provided" };
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (ai.runId !== void 0 && ai.runId !== null) {
|
|
491
|
+
if (typeof ai.runId !== "string" || ai.runId.length > 128) {
|
|
492
|
+
return { valid: false, error: "provenance.aiContext.runId must be a string (max 128 chars) when provided" };
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
232
496
|
}
|
|
233
497
|
if (data.reference !== void 0) {
|
|
234
498
|
if (!data.reference || typeof data.reference !== "object") {
|
|
@@ -293,17 +557,20 @@ var validateVerifierData = (verifierId, data) => {
|
|
|
293
557
|
}
|
|
294
558
|
break;
|
|
295
559
|
case "wallet-link":
|
|
296
|
-
if (!data.primaryWalletAddress || !
|
|
560
|
+
if (!data.primaryWalletAddress || !validateUniversalAddress(data.primaryWalletAddress, data.chain)) {
|
|
297
561
|
return { valid: false, error: "primaryWalletAddress is required" };
|
|
298
562
|
}
|
|
299
|
-
if (!data.secondaryWalletAddress || !
|
|
563
|
+
if (!data.secondaryWalletAddress || !validateUniversalAddress(data.secondaryWalletAddress, data.chain)) {
|
|
300
564
|
return { valid: false, error: "secondaryWalletAddress is required" };
|
|
301
565
|
}
|
|
302
566
|
if (!data.signature || typeof data.signature !== "string") {
|
|
303
567
|
return { valid: false, error: "signature is required (signed by secondary wallet)" };
|
|
304
568
|
}
|
|
305
|
-
if (typeof data.
|
|
306
|
-
return { valid: false, error: "
|
|
569
|
+
if (typeof data.chain !== "string" || !/^[a-z0-9]+:[^\s]+$/.test(data.chain)) {
|
|
570
|
+
return { valid: false, error: "chain is required (namespace:reference)" };
|
|
571
|
+
}
|
|
572
|
+
if (typeof data.signatureMethod !== "string" || !data.signatureMethod.trim()) {
|
|
573
|
+
return { valid: false, error: "signatureMethod is required" };
|
|
307
574
|
}
|
|
308
575
|
if (typeof data.signedTimestamp !== "number") {
|
|
309
576
|
return { valid: false, error: "signedTimestamp is required" };
|
|
@@ -368,6 +635,17 @@ var validateVerifierData = (verifierId, data) => {
|
|
|
368
635
|
if (!validTypes.includes(contentType)) {
|
|
369
636
|
return { valid: false, error: `contentType must be one of: ${validTypes.join(", ")}` };
|
|
370
637
|
}
|
|
638
|
+
const isTextual = contentType.startsWith("text/") || contentType.includes("markdown");
|
|
639
|
+
if (isTextual) {
|
|
640
|
+
try {
|
|
641
|
+
const maxBytes = 50 * 1024;
|
|
642
|
+
const bytes = typeof TextEncoder !== "undefined" ? new TextEncoder().encode(data.content).length : String(data.content).length;
|
|
643
|
+
if (bytes > maxBytes) {
|
|
644
|
+
return { valid: false, error: `content exceeds ${maxBytes} bytes limit for ai-content-moderation verifier (text)` };
|
|
645
|
+
}
|
|
646
|
+
} catch {
|
|
647
|
+
}
|
|
648
|
+
}
|
|
371
649
|
}
|
|
372
650
|
if (data.content.length > 13653334) {
|
|
373
651
|
return { valid: false, error: "content exceeds 10MB limit" };
|
|
@@ -387,7 +665,7 @@ var validateVerifierData = (verifierId, data) => {
|
|
|
387
665
|
}
|
|
388
666
|
break;
|
|
389
667
|
case "wallet-risk":
|
|
390
|
-
if (data.walletAddress && !
|
|
668
|
+
if (data.walletAddress && !validateUniversalAddress(data.walletAddress, data.chain)) {
|
|
391
669
|
return { valid: false, error: "Invalid walletAddress" };
|
|
392
670
|
}
|
|
393
671
|
break;
|
|
@@ -419,6 +697,26 @@ var NeusClient = class {
|
|
|
419
697
|
if (typeof this.config.apiKey === "string" && this.config.apiKey.trim().length > 0) {
|
|
420
698
|
this.defaultHeaders["Authorization"] = `Bearer ${this.config.apiKey.trim()}`;
|
|
421
699
|
}
|
|
700
|
+
if (typeof this.config.appId === "string" && this.config.appId.trim().length > 0) {
|
|
701
|
+
this.defaultHeaders["X-Neus-App"] = this.config.appId.trim();
|
|
702
|
+
}
|
|
703
|
+
if (typeof this.config.sponsorGrant === "string" && this.config.sponsorGrant.trim().length > 0) {
|
|
704
|
+
this.defaultHeaders["X-Sponsor-Grant"] = this.config.sponsorGrant.trim();
|
|
705
|
+
}
|
|
706
|
+
if (typeof this.config.paymentSignature === "string" && this.config.paymentSignature.trim().length > 0) {
|
|
707
|
+
this.defaultHeaders["PAYMENT-SIGNATURE"] = this.config.paymentSignature.trim();
|
|
708
|
+
}
|
|
709
|
+
if (this.config.extraHeaders && typeof this.config.extraHeaders === "object") {
|
|
710
|
+
for (const [k, v] of Object.entries(this.config.extraHeaders)) {
|
|
711
|
+
if (!k || v === void 0 || v === null)
|
|
712
|
+
continue;
|
|
713
|
+
const key = String(k).trim();
|
|
714
|
+
const value = String(v).trim();
|
|
715
|
+
if (!key || !value)
|
|
716
|
+
continue;
|
|
717
|
+
this.defaultHeaders[key] = value;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
422
720
|
try {
|
|
423
721
|
if (typeof window !== "undefined" && window.location && window.location.origin) {
|
|
424
722
|
this.defaultHeaders["X-Client-Origin"] = window.location.origin;
|
|
@@ -426,6 +724,122 @@ var NeusClient = class {
|
|
|
426
724
|
} catch {
|
|
427
725
|
}
|
|
428
726
|
}
|
|
727
|
+
_getHubChainId() {
|
|
728
|
+
const configured = Number(this.config?.hubChainId);
|
|
729
|
+
if (Number.isFinite(configured) && configured > 0)
|
|
730
|
+
return Math.floor(configured);
|
|
731
|
+
return NEUS_CONSTANTS.HUB_CHAIN_ID;
|
|
732
|
+
}
|
|
733
|
+
_normalizeIdentity(value) {
|
|
734
|
+
let raw = String(value || "").trim();
|
|
735
|
+
if (!raw)
|
|
736
|
+
return "";
|
|
737
|
+
const didMatch = raw.match(/^did:pkh:([^:]+):([^:]+):(.+)$/i);
|
|
738
|
+
if (didMatch && didMatch[3]) {
|
|
739
|
+
raw = String(didMatch[3]).trim();
|
|
740
|
+
}
|
|
741
|
+
return EVM_ADDRESS_RE.test(raw) ? raw.toLowerCase() : raw;
|
|
742
|
+
}
|
|
743
|
+
_inferChainForAddress(address, explicitChain) {
|
|
744
|
+
if (typeof explicitChain === "string" && explicitChain.includes(":"))
|
|
745
|
+
return explicitChain.trim();
|
|
746
|
+
const raw = String(address || "").trim();
|
|
747
|
+
const didMatch = raw.match(/^did:pkh:([^:]+):([^:]+):(.+)$/i);
|
|
748
|
+
if (didMatch && didMatch[1] && didMatch[2]) {
|
|
749
|
+
return `${didMatch[1]}:${didMatch[2]}`;
|
|
750
|
+
}
|
|
751
|
+
if (EVM_ADDRESS_RE.test(raw)) {
|
|
752
|
+
return `eip155:${this._getHubChainId()}`;
|
|
753
|
+
}
|
|
754
|
+
return "solana:mainnet";
|
|
755
|
+
}
|
|
756
|
+
async _resolveWalletSigner(wallet) {
|
|
757
|
+
if (!wallet) {
|
|
758
|
+
throw new ConfigurationError("No wallet provider available");
|
|
759
|
+
}
|
|
760
|
+
if (wallet.address) {
|
|
761
|
+
return { signerWalletAddress: wallet.address, provider: wallet };
|
|
762
|
+
}
|
|
763
|
+
if (wallet.publicKey && typeof wallet.publicKey.toBase58 === "function") {
|
|
764
|
+
return { signerWalletAddress: wallet.publicKey.toBase58(), provider: wallet };
|
|
765
|
+
}
|
|
766
|
+
if (typeof wallet.getAddress === "function") {
|
|
767
|
+
const signerWalletAddress = await wallet.getAddress().catch(() => null);
|
|
768
|
+
return { signerWalletAddress, provider: wallet };
|
|
769
|
+
}
|
|
770
|
+
if (wallet.selectedAddress || wallet.request) {
|
|
771
|
+
const provider = wallet;
|
|
772
|
+
if (wallet.selectedAddress) {
|
|
773
|
+
return { signerWalletAddress: wallet.selectedAddress, provider };
|
|
774
|
+
}
|
|
775
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
776
|
+
if (!accounts || accounts.length === 0) {
|
|
777
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
778
|
+
}
|
|
779
|
+
return { signerWalletAddress: accounts[0], provider };
|
|
780
|
+
}
|
|
781
|
+
throw new ConfigurationError("Invalid wallet provider");
|
|
782
|
+
}
|
|
783
|
+
_getDefaultBrowserWallet() {
|
|
784
|
+
if (typeof window === "undefined")
|
|
785
|
+
return null;
|
|
786
|
+
return window.ethereum || window.solana || window.phantom && window.phantom.solana || null;
|
|
787
|
+
}
|
|
788
|
+
async _buildPrivateGateAuth({ address, wallet, chain, signatureMethod } = {}) {
|
|
789
|
+
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
790
|
+
const { signerWalletAddress, provider } = await this._resolveWalletSigner(providerWallet);
|
|
791
|
+
if (!signerWalletAddress || typeof signerWalletAddress !== "string") {
|
|
792
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
793
|
+
}
|
|
794
|
+
const normalizedSigner = this._normalizeIdentity(signerWalletAddress);
|
|
795
|
+
const normalizedAddress = this._normalizeIdentity(address);
|
|
796
|
+
if (!normalizedSigner || normalizedSigner !== normalizedAddress) {
|
|
797
|
+
throw new ValidationError("wallet must match address when includePrivate=true");
|
|
798
|
+
}
|
|
799
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(normalizedSigner);
|
|
800
|
+
const resolvedChain = this._inferChainForAddress(normalizedSigner, chain);
|
|
801
|
+
const resolvedSignatureMethod = typeof signatureMethod === "string" && signatureMethod.trim() ? signatureMethod.trim() : signerIsEvm ? "eip191" : "ed25519";
|
|
802
|
+
const signedTimestamp = Date.now();
|
|
803
|
+
const message = constructVerificationMessage({
|
|
804
|
+
walletAddress: signerWalletAddress,
|
|
805
|
+
signedTimestamp,
|
|
806
|
+
data: { action: "gate_check_private_proofs", walletAddress: normalizedAddress },
|
|
807
|
+
verifierIds: ["ownership-basic"],
|
|
808
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain: resolvedChain }
|
|
809
|
+
});
|
|
810
|
+
let signature;
|
|
811
|
+
try {
|
|
812
|
+
signature = await signMessage({
|
|
813
|
+
provider,
|
|
814
|
+
message,
|
|
815
|
+
walletAddress: signerWalletAddress,
|
|
816
|
+
...signerIsEvm ? {} : { chain: resolvedChain }
|
|
817
|
+
});
|
|
818
|
+
} catch (error) {
|
|
819
|
+
if (error.code === 4001) {
|
|
820
|
+
throw new ValidationError("User rejected signature request");
|
|
821
|
+
}
|
|
822
|
+
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
823
|
+
}
|
|
824
|
+
return {
|
|
825
|
+
walletAddress: signerWalletAddress,
|
|
826
|
+
signature,
|
|
827
|
+
signedTimestamp,
|
|
828
|
+
...signerIsEvm ? {} : { chain: resolvedChain, signatureMethod: resolvedSignatureMethod }
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
async createGatePrivateAuth(params = {}) {
|
|
832
|
+
const address = (params.address || "").toString();
|
|
833
|
+
if (!validateUniversalAddress(address, params.chain)) {
|
|
834
|
+
throw new ValidationError("Valid address is required");
|
|
835
|
+
}
|
|
836
|
+
return this._buildPrivateGateAuth({
|
|
837
|
+
address,
|
|
838
|
+
wallet: params.wallet,
|
|
839
|
+
chain: params.chain,
|
|
840
|
+
signatureMethod: params.signatureMethod
|
|
841
|
+
});
|
|
842
|
+
}
|
|
429
843
|
// ============================================================================
|
|
430
844
|
// CORE VERIFICATION METHODS
|
|
431
845
|
// ============================================================================
|
|
@@ -447,7 +861,7 @@ var NeusClient = class {
|
|
|
447
861
|
* @param {string} [params.verifier] - Verifier ID (auto path)
|
|
448
862
|
* @param {string} [params.content] - Content/description (auto path)
|
|
449
863
|
* @param {Object} [params.wallet] - Optional injected wallet/provider (auto path)
|
|
450
|
-
* @returns {Promise<Object>} Verification result with qHash
|
|
864
|
+
* @returns {Promise<Object>} Verification result with proofId (qHash is a deprecated alias)
|
|
451
865
|
*
|
|
452
866
|
* @example
|
|
453
867
|
* const proof = await client.verify({
|
|
@@ -455,7 +869,7 @@ var NeusClient = class {
|
|
|
455
869
|
* data: {
|
|
456
870
|
* content: "My content",
|
|
457
871
|
* owner: walletAddress, // or ownerAddress for nft-ownership/token-holding
|
|
458
|
-
* reference: { type: '
|
|
872
|
+
* reference: { type: 'other', id: 'my-unique-identifier' }
|
|
459
873
|
* },
|
|
460
874
|
* walletAddress: '0x...',
|
|
461
875
|
* signature: '0x...',
|
|
@@ -472,7 +886,7 @@ var NeusClient = class {
|
|
|
472
886
|
* @param {Object} [params.data] - Structured verification data
|
|
473
887
|
* @param {Object} [params.wallet] - Wallet provider
|
|
474
888
|
* @param {Object} [params.options] - Additional options
|
|
475
|
-
* @returns {Promise<Object>} Verification result with qHash
|
|
889
|
+
* @returns {Promise<Object>} Verification result with proofId (qHash is a deprecated alias)
|
|
476
890
|
*
|
|
477
891
|
* @example
|
|
478
892
|
* // Simple ownership proof
|
|
@@ -488,25 +902,23 @@ var NeusClient = class {
|
|
|
488
902
|
if (verifier === "ownership-basic" && !data2 && (!content || typeof content !== "string")) {
|
|
489
903
|
throw new ValidationError("content is required and must be a string (or use data param with owner + reference)");
|
|
490
904
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
"contract-ownership",
|
|
500
|
-
"wallet-risk",
|
|
501
|
-
// Wallet risk assessment (public)
|
|
502
|
-
// AI & Agent verifiers (ERC-8004 aligned)
|
|
503
|
-
"agent-identity",
|
|
504
|
-
"agent-delegation",
|
|
505
|
-
"ai-content-moderation"
|
|
506
|
-
];
|
|
905
|
+
let validVerifiers = FALLBACK_PUBLIC_VERIFIERS;
|
|
906
|
+
try {
|
|
907
|
+
const discovered = await this.getVerifiers();
|
|
908
|
+
if (Array.isArray(discovered) && discovered.length > 0) {
|
|
909
|
+
validVerifiers = discovered;
|
|
910
|
+
}
|
|
911
|
+
} catch {
|
|
912
|
+
}
|
|
507
913
|
if (!validVerifiers.includes(verifier)) {
|
|
508
914
|
throw new ValidationError(`Invalid verifier '${verifier}'. Must be one of: ${validVerifiers.join(", ")}.`);
|
|
509
915
|
}
|
|
916
|
+
if (INTERACTIVE_VERIFIERS.has(verifier)) {
|
|
917
|
+
const hostedCheckoutUrl = options2?.hostedCheckoutUrl || "https://neus.network/verify";
|
|
918
|
+
throw new ValidationError(
|
|
919
|
+
`${verifier} requires hosted interactive checkout. Use VerifyGate or redirect to ${hostedCheckoutUrl}.`
|
|
920
|
+
);
|
|
921
|
+
}
|
|
510
922
|
const requiresDataParam = [
|
|
511
923
|
"ownership-dns-txt",
|
|
512
924
|
"wallet-link",
|
|
@@ -524,8 +936,12 @@ var NeusClient = class {
|
|
|
524
936
|
}
|
|
525
937
|
let walletAddress2, provider;
|
|
526
938
|
if (wallet) {
|
|
527
|
-
walletAddress2 = wallet.address || wallet.selectedAddress;
|
|
939
|
+
walletAddress2 = wallet.address || wallet.selectedAddress || wallet.walletAddress || (typeof wallet.getAddress === "function" ? await wallet.getAddress() : null);
|
|
528
940
|
provider = wallet.provider || wallet;
|
|
941
|
+
if (!walletAddress2 && provider && typeof provider.request === "function") {
|
|
942
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
943
|
+
walletAddress2 = Array.isArray(accounts) ? accounts[0] : null;
|
|
944
|
+
}
|
|
529
945
|
} else {
|
|
530
946
|
if (typeof window === "undefined" || !window.ethereum) {
|
|
531
947
|
throw new ConfigurationError("No Web3 wallet detected. Please install MetaMask or provide wallet parameter.");
|
|
@@ -543,6 +959,7 @@ var NeusClient = class {
|
|
|
543
959
|
reference: data2.reference,
|
|
544
960
|
...data2.content && { content: data2.content },
|
|
545
961
|
...data2.contentHash && { contentHash: data2.contentHash },
|
|
962
|
+
...data2.contentType && { contentType: data2.contentType },
|
|
546
963
|
...data2.provenance && { provenance: data2.provenance }
|
|
547
964
|
};
|
|
548
965
|
} else {
|
|
@@ -600,14 +1017,18 @@ var NeusClient = class {
|
|
|
600
1017
|
if (!data2?.signature) {
|
|
601
1018
|
throw new ValidationError("wallet-link requires signature in data parameter (signed by secondary wallet)");
|
|
602
1019
|
}
|
|
603
|
-
if (typeof data2?.
|
|
604
|
-
throw new ValidationError("wallet-link requires
|
|
1020
|
+
if (typeof data2?.chain !== "string" || !/^[a-z0-9]+:[^\s]+$/.test(data2.chain)) {
|
|
1021
|
+
throw new ValidationError("wallet-link requires chain (namespace:reference) in data parameter");
|
|
1022
|
+
}
|
|
1023
|
+
if (typeof data2?.signatureMethod !== "string" || !data2.signatureMethod.trim()) {
|
|
1024
|
+
throw new ValidationError("wallet-link requires signatureMethod in data parameter");
|
|
605
1025
|
}
|
|
606
1026
|
verificationData = {
|
|
607
1027
|
primaryWalletAddress: walletAddress2,
|
|
608
1028
|
secondaryWalletAddress: data2.secondaryWalletAddress,
|
|
609
1029
|
signature: data2.signature,
|
|
610
|
-
|
|
1030
|
+
chain: data2.chain,
|
|
1031
|
+
signatureMethod: data2.signatureMethod,
|
|
611
1032
|
signedTimestamp: data2?.signedTimestamp || Date.now()
|
|
612
1033
|
};
|
|
613
1034
|
} else if (verifier === "contract-ownership") {
|
|
@@ -696,12 +1117,12 @@ var NeusClient = class {
|
|
|
696
1117
|
signedTimestamp: signedTimestamp2,
|
|
697
1118
|
data: verificationData,
|
|
698
1119
|
verifierIds: verifierIds2,
|
|
699
|
-
chainId:
|
|
1120
|
+
chainId: this._getHubChainId()
|
|
700
1121
|
// Protocol-managed chain
|
|
701
1122
|
});
|
|
702
1123
|
let signature2;
|
|
703
1124
|
try {
|
|
704
|
-
const
|
|
1125
|
+
const toHexUtf82 = (s) => {
|
|
705
1126
|
try {
|
|
706
1127
|
const enc = new TextEncoder();
|
|
707
1128
|
const bytes = enc.encode(s);
|
|
@@ -737,7 +1158,7 @@ var NeusClient = class {
|
|
|
737
1158
|
})();
|
|
738
1159
|
if (isFarcasterWallet) {
|
|
739
1160
|
try {
|
|
740
|
-
const hexMsg =
|
|
1161
|
+
const hexMsg = toHexUtf82(message);
|
|
741
1162
|
signature2 = await provider.request({ method: "personal_sign", params: [hexMsg, walletAddress2] });
|
|
742
1163
|
} catch (e) {
|
|
743
1164
|
}
|
|
@@ -786,7 +1207,7 @@ ${bytes.length}`;
|
|
|
786
1207
|
}
|
|
787
1208
|
} else if (needsHex) {
|
|
788
1209
|
this._log("Retrying personal_sign with hex-encoded message");
|
|
789
|
-
const hexMsg =
|
|
1210
|
+
const hexMsg = toHexUtf82(message);
|
|
790
1211
|
signature2 = await provider.request({ method: "personal_sign", params: [hexMsg, walletAddress2] });
|
|
791
1212
|
} else {
|
|
792
1213
|
throw e;
|
|
@@ -884,18 +1305,18 @@ ${bytes.length}`;
|
|
|
884
1305
|
/**
|
|
885
1306
|
* Get verification status
|
|
886
1307
|
*
|
|
887
|
-
* @param {string}
|
|
1308
|
+
* @param {string} proofId - Proof ID (standard). `qHash` is a deprecated alias (same value).
|
|
888
1309
|
* @returns {Promise<Object>} Verification status and data
|
|
889
1310
|
*
|
|
890
1311
|
* @example
|
|
891
1312
|
* const result = await client.getStatus('0x...');
|
|
892
1313
|
* console.log('Status:', result.status);
|
|
893
1314
|
*/
|
|
894
|
-
async getStatus(
|
|
895
|
-
if (!
|
|
896
|
-
throw new ValidationError("
|
|
1315
|
+
async getStatus(proofId) {
|
|
1316
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1317
|
+
throw new ValidationError("proofId is required");
|
|
897
1318
|
}
|
|
898
|
-
const response = await this._makeRequest("GET", `/api/v1/verification/status/${
|
|
1319
|
+
const response = await this._makeRequest("GET", `/api/v1/verification/status/${proofId}`);
|
|
899
1320
|
if (!response.success) {
|
|
900
1321
|
throw new ApiError(`Failed to get status: ${response.error?.message || "Unknown error"}`, response.error);
|
|
901
1322
|
}
|
|
@@ -904,70 +1325,72 @@ ${bytes.length}`;
|
|
|
904
1325
|
/**
|
|
905
1326
|
* Get private proof status with wallet signature
|
|
906
1327
|
*
|
|
907
|
-
* @param {string}
|
|
1328
|
+
* @param {string} proofId - Proof ID (standard). `qHash` is a deprecated alias (same value).
|
|
908
1329
|
* @param {Object} wallet - Wallet provider (window.ethereum or ethers Wallet)
|
|
909
1330
|
* @returns {Promise<Object>} Private verification status and data
|
|
910
1331
|
*
|
|
911
1332
|
* @example
|
|
912
1333
|
* // Access private proof
|
|
913
|
-
* const privateData = await client.getPrivateStatus(
|
|
1334
|
+
* const privateData = await client.getPrivateStatus(proofId, window.ethereum);
|
|
914
1335
|
*/
|
|
915
|
-
async getPrivateStatus(
|
|
916
|
-
if (!
|
|
917
|
-
throw new ValidationError("
|
|
1336
|
+
async getPrivateStatus(proofId, wallet = null) {
|
|
1337
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1338
|
+
throw new ValidationError("proofId is required");
|
|
918
1339
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1340
|
+
const isPreSignedAuth = wallet && typeof wallet === "object" && typeof wallet.walletAddress === "string" && typeof wallet.signature === "string" && typeof wallet.signedTimestamp === "number";
|
|
1341
|
+
if (isPreSignedAuth) {
|
|
1342
|
+
const auth = wallet;
|
|
1343
|
+
const headers = {
|
|
1344
|
+
"x-wallet-address": String(auth.walletAddress),
|
|
1345
|
+
"x-signature": String(auth.signature),
|
|
1346
|
+
"x-signed-timestamp": String(auth.signedTimestamp),
|
|
1347
|
+
...typeof auth.chain === "string" && auth.chain.trim() ? { "x-chain": auth.chain.trim() } : {},
|
|
1348
|
+
...typeof auth.signatureMethod === "string" && auth.signatureMethod.trim() ? { "x-signature-method": auth.signatureMethod.trim() } : {}
|
|
1349
|
+
};
|
|
1350
|
+
const response2 = await this._makeRequest("GET", `/api/v1/verification/status/${proofId}`, null, headers);
|
|
1351
|
+
if (!response2.success) {
|
|
1352
|
+
throw new ApiError(
|
|
1353
|
+
`Failed to access private proof: ${response2.error?.message || "Unauthorized"}`,
|
|
1354
|
+
response2.error
|
|
1355
|
+
);
|
|
922
1356
|
}
|
|
923
|
-
|
|
1357
|
+
return this._formatResponse(response2);
|
|
924
1358
|
}
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
} else if (wallet.selectedAddress || wallet.request) {
|
|
930
|
-
provider = wallet;
|
|
931
|
-
if (wallet.selectedAddress) {
|
|
932
|
-
walletAddress = wallet.selectedAddress;
|
|
933
|
-
} else {
|
|
934
|
-
const accounts = await provider.request({ method: "eth_accounts" });
|
|
935
|
-
if (!accounts || accounts.length === 0) {
|
|
936
|
-
throw new ConfigurationError("No wallet accounts available");
|
|
937
|
-
}
|
|
938
|
-
walletAddress = accounts[0];
|
|
939
|
-
}
|
|
940
|
-
} else {
|
|
941
|
-
throw new ConfigurationError("Invalid wallet provider");
|
|
1359
|
+
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
1360
|
+
const { signerWalletAddress: walletAddress, provider } = await this._resolveWalletSigner(providerWallet);
|
|
1361
|
+
if (!walletAddress || typeof walletAddress !== "string") {
|
|
1362
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
942
1363
|
}
|
|
1364
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(this._normalizeIdentity(walletAddress));
|
|
1365
|
+
const chain = this._inferChainForAddress(walletAddress);
|
|
1366
|
+
const signatureMethod = signerIsEvm ? "eip191" : "ed25519";
|
|
943
1367
|
const signedTimestamp = Date.now();
|
|
944
1368
|
const message = constructVerificationMessage({
|
|
945
1369
|
walletAddress,
|
|
946
1370
|
signedTimestamp,
|
|
947
|
-
data: { action: "access_private_proof", qHash },
|
|
1371
|
+
data: { action: "access_private_proof", qHash: proofId },
|
|
948
1372
|
verifierIds: ["ownership-basic"],
|
|
949
|
-
chainId:
|
|
1373
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
950
1374
|
});
|
|
951
1375
|
let signature;
|
|
952
1376
|
try {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
});
|
|
960
|
-
}
|
|
1377
|
+
signature = await signMessage({
|
|
1378
|
+
provider,
|
|
1379
|
+
message,
|
|
1380
|
+
walletAddress,
|
|
1381
|
+
...signerIsEvm ? {} : { chain }
|
|
1382
|
+
});
|
|
961
1383
|
} catch (error) {
|
|
962
1384
|
if (error.code === 4001) {
|
|
963
1385
|
throw new ValidationError("User rejected signature request");
|
|
964
1386
|
}
|
|
965
1387
|
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
966
1388
|
}
|
|
967
|
-
const response = await this._makeRequest("GET", `/api/v1/verification/status/${
|
|
1389
|
+
const response = await this._makeRequest("GET", `/api/v1/verification/status/${proofId}`, null, {
|
|
968
1390
|
"x-wallet-address": walletAddress,
|
|
969
1391
|
"x-signature": signature,
|
|
970
|
-
"x-signed-timestamp": signedTimestamp.toString()
|
|
1392
|
+
"x-signed-timestamp": signedTimestamp.toString(),
|
|
1393
|
+
...signerIsEvm ? {} : { "x-chain": chain, "x-signature-method": signatureMethod }
|
|
971
1394
|
});
|
|
972
1395
|
if (!response.success) {
|
|
973
1396
|
throw new ApiError(
|
|
@@ -1008,7 +1431,7 @@ ${bytes.length}`;
|
|
|
1008
1431
|
* Polls the verification status until it reaches a terminal state (completed or failed).
|
|
1009
1432
|
* Useful for providing real-time feedback to users during verification.
|
|
1010
1433
|
*
|
|
1011
|
-
* @param {string}
|
|
1434
|
+
* @param {string} proofId - Proof ID to poll (standard). `qHash` is a deprecated alias (same value).
|
|
1012
1435
|
* @param {Object} [options] - Polling options
|
|
1013
1436
|
* @param {number} [options.interval=5000] - Polling interval in ms
|
|
1014
1437
|
* @param {number} [options.timeout=120000] - Total timeout in ms
|
|
@@ -1016,7 +1439,7 @@ ${bytes.length}`;
|
|
|
1016
1439
|
* @returns {Promise<Object>} Final verification status
|
|
1017
1440
|
*
|
|
1018
1441
|
* @example
|
|
1019
|
-
* const finalStatus = await client.pollProofStatus(
|
|
1442
|
+
* const finalStatus = await client.pollProofStatus(proofId, {
|
|
1020
1443
|
* interval: 3000,
|
|
1021
1444
|
* timeout: 60000,
|
|
1022
1445
|
* onProgress: (status) => {
|
|
@@ -1027,19 +1450,21 @@ ${bytes.length}`;
|
|
|
1027
1450
|
* }
|
|
1028
1451
|
* });
|
|
1029
1452
|
*/
|
|
1030
|
-
async pollProofStatus(
|
|
1453
|
+
async pollProofStatus(proofId, options = {}) {
|
|
1031
1454
|
const {
|
|
1032
1455
|
interval = 5e3,
|
|
1033
1456
|
timeout = 12e4,
|
|
1034
1457
|
onProgress
|
|
1035
1458
|
} = options;
|
|
1036
|
-
if (!
|
|
1037
|
-
throw new ValidationError("
|
|
1459
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1460
|
+
throw new ValidationError("proofId is required");
|
|
1038
1461
|
}
|
|
1039
1462
|
const startTime = Date.now();
|
|
1463
|
+
let consecutiveRateLimits = 0;
|
|
1040
1464
|
while (Date.now() - startTime < timeout) {
|
|
1041
1465
|
try {
|
|
1042
|
-
const status = await this.getStatus(
|
|
1466
|
+
const status = await this.getStatus(proofId);
|
|
1467
|
+
consecutiveRateLimits = 0;
|
|
1043
1468
|
if (onProgress && typeof onProgress === "function") {
|
|
1044
1469
|
onProgress(status.data || status);
|
|
1045
1470
|
}
|
|
@@ -1054,7 +1479,17 @@ ${bytes.length}`;
|
|
|
1054
1479
|
if (error instanceof ValidationError) {
|
|
1055
1480
|
throw error;
|
|
1056
1481
|
}
|
|
1057
|
-
|
|
1482
|
+
let nextDelay = interval;
|
|
1483
|
+
if (error instanceof ApiError && Number(error.statusCode) === 429) {
|
|
1484
|
+
consecutiveRateLimits += 1;
|
|
1485
|
+
const exp = Math.min(6, consecutiveRateLimits);
|
|
1486
|
+
const base = Math.max(500, Number(interval) || 0);
|
|
1487
|
+
const max = 3e4;
|
|
1488
|
+
const backoff = Math.min(max, base * Math.pow(2, exp));
|
|
1489
|
+
const jitter = Math.floor(backoff * (0.5 + Math.random() * 0.5));
|
|
1490
|
+
nextDelay = jitter;
|
|
1491
|
+
}
|
|
1492
|
+
await new Promise((resolve) => setTimeout(resolve, nextDelay));
|
|
1058
1493
|
}
|
|
1059
1494
|
}
|
|
1060
1495
|
throw new NetworkError(`Polling timeout after ${timeout}ms`, "POLLING_TIMEOUT");
|
|
@@ -1076,70 +1511,51 @@ ${bytes.length}`;
|
|
|
1076
1511
|
}
|
|
1077
1512
|
}
|
|
1078
1513
|
/** Revoke your own proof (owner-signed) */
|
|
1079
|
-
async revokeOwnProof(
|
|
1080
|
-
if (!
|
|
1081
|
-
throw new ValidationError("
|
|
1514
|
+
async revokeOwnProof(proofId, wallet) {
|
|
1515
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1516
|
+
throw new ValidationError("proofId is required");
|
|
1082
1517
|
}
|
|
1083
|
-
const
|
|
1518
|
+
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
1519
|
+
const { signerWalletAddress: address, provider } = await this._resolveWalletSigner(providerWallet);
|
|
1520
|
+
if (!address || typeof address !== "string") {
|
|
1521
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
1522
|
+
}
|
|
1523
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(this._normalizeIdentity(address));
|
|
1524
|
+
const chain = this._inferChainForAddress(address);
|
|
1525
|
+
const signatureMethod = signerIsEvm ? "eip191" : "ed25519";
|
|
1084
1526
|
const signedTimestamp = Date.now();
|
|
1085
|
-
const hubChainId = NEUS_CONSTANTS.HUB_CHAIN_ID;
|
|
1086
1527
|
const message = constructVerificationMessage({
|
|
1087
1528
|
walletAddress: address,
|
|
1088
1529
|
signedTimestamp,
|
|
1089
|
-
|
|
1530
|
+
// Keep wire payload key `qHash` for backwards compatibility.
|
|
1531
|
+
data: { action: "revoke_proof", qHash: proofId },
|
|
1090
1532
|
verifierIds: ["ownership-basic"],
|
|
1091
|
-
chainId:
|
|
1533
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
1092
1534
|
});
|
|
1093
1535
|
let signature;
|
|
1094
1536
|
try {
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
return hex;
|
|
1102
|
-
};
|
|
1103
|
-
const isFarcasterWallet = (() => {
|
|
1104
|
-
if (typeof window === "undefined")
|
|
1105
|
-
return false;
|
|
1106
|
-
try {
|
|
1107
|
-
const w = window;
|
|
1108
|
-
const fc = w.farcaster;
|
|
1109
|
-
if (!fc || !fc.context)
|
|
1110
|
-
return false;
|
|
1111
|
-
const fcProvider = fc.provider || fc.walletProvider || fc.context && fc.context.walletProvider;
|
|
1112
|
-
if (fcProvider === w.ethereum)
|
|
1113
|
-
return true;
|
|
1114
|
-
if (w.mini && w.mini.wallet === w.ethereum && fc && fc.context)
|
|
1115
|
-
return true;
|
|
1116
|
-
if (w.ethereum && fc && fc.context)
|
|
1117
|
-
return true;
|
|
1118
|
-
} catch {
|
|
1119
|
-
}
|
|
1120
|
-
return false;
|
|
1121
|
-
})();
|
|
1122
|
-
if (isFarcasterWallet) {
|
|
1123
|
-
try {
|
|
1124
|
-
const hexMsg = toHexUtf8(message);
|
|
1125
|
-
signature = await window.ethereum.request({ method: "personal_sign", params: [hexMsg, address] });
|
|
1126
|
-
} catch {
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
if (!signature) {
|
|
1130
|
-
signature = await window.ethereum.request({ method: "personal_sign", params: [message, address] });
|
|
1131
|
-
}
|
|
1537
|
+
signature = await signMessage({
|
|
1538
|
+
provider,
|
|
1539
|
+
message,
|
|
1540
|
+
walletAddress: address,
|
|
1541
|
+
...signerIsEvm ? {} : { chain }
|
|
1542
|
+
});
|
|
1132
1543
|
} catch (error) {
|
|
1133
1544
|
if (error.code === 4001) {
|
|
1134
1545
|
throw new ValidationError("User rejected revocation signature");
|
|
1135
1546
|
}
|
|
1136
1547
|
throw new ValidationError(`Failed to sign revocation: ${error.message}`);
|
|
1137
1548
|
}
|
|
1138
|
-
const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/${
|
|
1549
|
+
const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/${proofId}/revoke-self`, {
|
|
1139
1550
|
method: "POST",
|
|
1140
1551
|
// SECURITY: Do not put proof signatures into Authorization headers.
|
|
1141
1552
|
headers: { "Content-Type": "application/json" },
|
|
1142
|
-
body: JSON.stringify({
|
|
1553
|
+
body: JSON.stringify({
|
|
1554
|
+
walletAddress: address,
|
|
1555
|
+
signature,
|
|
1556
|
+
signedTimestamp,
|
|
1557
|
+
...signerIsEvm ? {} : { chain, signatureMethod }
|
|
1558
|
+
})
|
|
1143
1559
|
});
|
|
1144
1560
|
const json = await res.json();
|
|
1145
1561
|
if (!json.success) {
|
|
@@ -1148,12 +1564,12 @@ ${bytes.length}`;
|
|
|
1148
1564
|
return true;
|
|
1149
1565
|
}
|
|
1150
1566
|
// ============================================================================
|
|
1151
|
-
//
|
|
1567
|
+
// PROOFS & GATING METHODS
|
|
1152
1568
|
// ============================================================================
|
|
1153
1569
|
/**
|
|
1154
1570
|
* GET PROOFS BY WALLET - Fetch proofs for a wallet address
|
|
1155
1571
|
*
|
|
1156
|
-
* @param {string} walletAddress - Wallet
|
|
1572
|
+
* @param {string} walletAddress - Wallet identity (EVM/Solana/DID)
|
|
1157
1573
|
* @param {Object} [options] - Filter options
|
|
1158
1574
|
* @param {number} [options.limit] - Max results (default: 50; higher limits require owner access)
|
|
1159
1575
|
* @param {number} [options.offset] - Pagination offset (default: 0)
|
|
@@ -1198,7 +1614,7 @@ ${bytes.length}`;
|
|
|
1198
1614
|
*
|
|
1199
1615
|
* Signs an owner-access intent and requests private proofs via signature headers.
|
|
1200
1616
|
*
|
|
1201
|
-
* @param {string} walletAddress - Wallet
|
|
1617
|
+
* @param {string} walletAddress - Wallet identity (EVM/Solana/DID)
|
|
1202
1618
|
* @param {Object} [options]
|
|
1203
1619
|
* @param {number} [options.limit] - Max results (server enforces caps)
|
|
1204
1620
|
* @param {number} [options.offset] - Pagination offset
|
|
@@ -1210,48 +1626,41 @@ ${bytes.length}`;
|
|
|
1210
1626
|
}
|
|
1211
1627
|
const id = walletAddress.trim();
|
|
1212
1628
|
const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
|
|
1629
|
+
const requestedIdentity = this._normalizeIdentity(id);
|
|
1213
1630
|
if (!wallet) {
|
|
1214
|
-
|
|
1631
|
+
const defaultWallet = this._getDefaultBrowserWallet();
|
|
1632
|
+
if (!defaultWallet) {
|
|
1215
1633
|
throw new ConfigurationError("No wallet provider available");
|
|
1216
1634
|
}
|
|
1217
|
-
wallet =
|
|
1635
|
+
wallet = defaultWallet;
|
|
1218
1636
|
}
|
|
1219
|
-
|
|
1220
|
-
if (
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
signerWalletAddress = wallet.selectedAddress;
|
|
1227
|
-
} else {
|
|
1228
|
-
const accounts = await provider.request({ method: "eth_accounts" });
|
|
1229
|
-
if (!accounts || accounts.length === 0) {
|
|
1230
|
-
throw new ConfigurationError("No wallet accounts available");
|
|
1231
|
-
}
|
|
1232
|
-
signerWalletAddress = accounts[0];
|
|
1233
|
-
}
|
|
1234
|
-
} else {
|
|
1235
|
-
throw new ConfigurationError("Invalid wallet provider");
|
|
1637
|
+
const { signerWalletAddress, provider } = await this._resolveWalletSigner(wallet);
|
|
1638
|
+
if (!signerWalletAddress || typeof signerWalletAddress !== "string") {
|
|
1639
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
1640
|
+
}
|
|
1641
|
+
const normalizedSigner = this._normalizeIdentity(signerWalletAddress);
|
|
1642
|
+
if (!normalizedSigner || normalizedSigner !== requestedIdentity) {
|
|
1643
|
+
throw new ValidationError("wallet must match walletAddress for private proof access");
|
|
1236
1644
|
}
|
|
1645
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(normalizedSigner);
|
|
1646
|
+
const chain = this._inferChainForAddress(normalizedSigner, options?.chain);
|
|
1647
|
+
const signatureMethod = typeof options?.signatureMethod === "string" && options.signatureMethod.trim() ? options.signatureMethod.trim() : signerIsEvm ? "eip191" : "ed25519";
|
|
1237
1648
|
const signedTimestamp = Date.now();
|
|
1238
1649
|
const message = constructVerificationMessage({
|
|
1239
1650
|
walletAddress: signerWalletAddress,
|
|
1240
1651
|
signedTimestamp,
|
|
1241
|
-
data: { action: "access_private_proofs_by_wallet", walletAddress:
|
|
1652
|
+
data: { action: "access_private_proofs_by_wallet", walletAddress: normalizedSigner },
|
|
1242
1653
|
verifierIds: ["ownership-basic"],
|
|
1243
|
-
chainId:
|
|
1654
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
1244
1655
|
});
|
|
1245
1656
|
let signature;
|
|
1246
1657
|
try {
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
});
|
|
1254
|
-
}
|
|
1658
|
+
signature = await signMessage({
|
|
1659
|
+
provider,
|
|
1660
|
+
message,
|
|
1661
|
+
walletAddress: signerWalletAddress,
|
|
1662
|
+
...signerIsEvm ? {} : { chain }
|
|
1663
|
+
});
|
|
1255
1664
|
} catch (error) {
|
|
1256
1665
|
if (error.code === 4001) {
|
|
1257
1666
|
throw new ValidationError("User rejected signature request");
|
|
@@ -1267,7 +1676,8 @@ ${bytes.length}`;
|
|
|
1267
1676
|
const response = await this._makeRequest("GET", `/api/v1/proofs/byWallet/${encodeURIComponent(pathId)}${query}`, null, {
|
|
1268
1677
|
"x-wallet-address": signerWalletAddress,
|
|
1269
1678
|
"x-signature": signature,
|
|
1270
|
-
"x-signed-timestamp": signedTimestamp.toString()
|
|
1679
|
+
"x-signed-timestamp": signedTimestamp.toString(),
|
|
1680
|
+
...signerIsEvm ? {} : { "x-chain": chain, "x-signature-method": signatureMethod }
|
|
1271
1681
|
});
|
|
1272
1682
|
if (!response.success) {
|
|
1273
1683
|
throw new ApiError(`Failed to get proofs: ${response.error?.message || "Unauthorized"}`, response.error);
|
|
@@ -1281,68 +1691,34 @@ ${bytes.length}`;
|
|
|
1281
1691
|
nextOffset: response.data?.nextOffset ?? null
|
|
1282
1692
|
};
|
|
1283
1693
|
}
|
|
1284
|
-
/**
|
|
1285
|
-
* LOOKUP MODE (API) - Non-persistent server-to-server checks
|
|
1286
|
-
*
|
|
1287
|
-
* Runs `external_lookup` verifiers without minting/storing a proof.
|
|
1288
|
-
* Requires an enterprise API key (server-side only).
|
|
1289
|
-
*
|
|
1290
|
-
* @param {Object} params
|
|
1291
|
-
* @param {string} params.apiKey - Enterprise API key (sk_live_... or sk_test_...)
|
|
1292
|
-
* @param {Array<string>} params.verifierIds - Verifiers to run (external_lookup only)
|
|
1293
|
-
* @param {string} params.targetWalletAddress - Wallet to evaluate
|
|
1294
|
-
* @param {Object} [params.data] - Verifier input data (e.g., contractAddress/tokenId/chainId)
|
|
1295
|
-
* @returns {Promise<Object>} API response ({ success, data })
|
|
1296
|
-
*/
|
|
1297
|
-
async lookup(params = {}) {
|
|
1298
|
-
const apiKey = (params.apiKey || "").toString().trim();
|
|
1299
|
-
if (!apiKey || !(apiKey.startsWith("sk_live_") || apiKey.startsWith("sk_test_"))) {
|
|
1300
|
-
throw new ValidationError("lookup requires apiKey (sk_live_* or sk_test_*)");
|
|
1301
|
-
}
|
|
1302
|
-
const verifierIds = Array.isArray(params.verifierIds) ? params.verifierIds.map((v) => String(v).trim()).filter(Boolean) : [];
|
|
1303
|
-
if (verifierIds.length === 0) {
|
|
1304
|
-
throw new ValidationError("lookup requires verifierIds (non-empty array)");
|
|
1305
|
-
}
|
|
1306
|
-
const targetWalletAddress = (params.targetWalletAddress || "").toString().trim();
|
|
1307
|
-
if (!targetWalletAddress || !/^0x[a-fA-F0-9]{40}$/i.test(targetWalletAddress)) {
|
|
1308
|
-
throw new ValidationError("lookup requires a valid targetWalletAddress (0x...)");
|
|
1309
|
-
}
|
|
1310
|
-
const body = {
|
|
1311
|
-
verifierIds,
|
|
1312
|
-
targetWalletAddress,
|
|
1313
|
-
data: params.data && typeof params.data === "object" ? params.data : {}
|
|
1314
|
-
};
|
|
1315
|
-
const response = await this._makeRequest("POST", "/api/v1/verification/lookup", body, {
|
|
1316
|
-
Authorization: `Bearer ${apiKey}`
|
|
1317
|
-
});
|
|
1318
|
-
if (!response.success) {
|
|
1319
|
-
throw new ApiError(`Lookup failed: ${response.error?.message || "Unknown error"}`, response.error);
|
|
1320
|
-
}
|
|
1321
|
-
return response;
|
|
1322
|
-
}
|
|
1323
1694
|
/**
|
|
1324
1695
|
* GATE CHECK (API) - Minimal eligibility check
|
|
1325
1696
|
*
|
|
1326
|
-
* Calls the
|
|
1327
|
-
*
|
|
1697
|
+
* Calls the gate endpoint and returns a **minimal** yes/no response.
|
|
1698
|
+
* By default this checks **public + discoverable** proofs only.
|
|
1699
|
+
*
|
|
1700
|
+
* When `includePrivate=true`, this can perform owner-signed private checks
|
|
1701
|
+
* (no full proof payloads returned) by providing a wallet/provider.
|
|
1328
1702
|
*
|
|
1329
|
-
* Prefer this over `checkGate()` for
|
|
1703
|
+
* Prefer this over `checkGate()` for integrations that want the
|
|
1330
1704
|
* smallest, most stable surface area (and do NOT need full proof payloads).
|
|
1331
1705
|
*
|
|
1332
1706
|
* @param {Object} params - Gate check query params
|
|
1333
|
-
* @param {string} params.address - Wallet
|
|
1707
|
+
* @param {string} params.address - Wallet identity to check (EVM/Solana/DID)
|
|
1334
1708
|
* @param {Array<string>|string} [params.verifierIds] - Verifier IDs to match (array or comma-separated)
|
|
1335
1709
|
* @param {boolean} [params.requireAll] - Require all verifierIds on a single proof
|
|
1336
1710
|
* @param {number} [params.minCount] - Minimum number of matching proofs
|
|
1337
1711
|
* @param {number} [params.sinceDays] - Optional time window in days
|
|
1338
1712
|
* @param {number} [params.since] - Optional unix timestamp in ms (lower bound)
|
|
1339
1713
|
* @param {number} [params.limit] - Max rows to scan (server may clamp)
|
|
1340
|
-
* @param {
|
|
1714
|
+
* @param {boolean} [params.includePrivate] - Include private proofs for owner-authenticated requests
|
|
1715
|
+
* @param {boolean} [params.includeQHashes] - Include matched qHashes in response (minimal IDs only)
|
|
1716
|
+
* @param {Object} [params.wallet] - Optional wallet/provider used to sign includePrivate owner checks
|
|
1341
1717
|
* @returns {Promise<Object>} API response ({ success, data })
|
|
1342
1718
|
*/
|
|
1343
1719
|
async gateCheck(params = {}) {
|
|
1344
1720
|
const address = (params.address || "").toString();
|
|
1345
|
-
if (!address
|
|
1721
|
+
if (!validateUniversalAddress(address, params.chain)) {
|
|
1346
1722
|
throw new ValidationError("Valid address is required");
|
|
1347
1723
|
}
|
|
1348
1724
|
const qs = new URLSearchParams();
|
|
@@ -1377,7 +1753,8 @@ ${bytes.length}`;
|
|
|
1377
1753
|
setIfPresent("sinceDays", params.sinceDays);
|
|
1378
1754
|
setIfPresent("since", params.since);
|
|
1379
1755
|
setIfPresent("limit", params.limit);
|
|
1380
|
-
|
|
1756
|
+
setBoolIfPresent("includePrivate", params.includePrivate);
|
|
1757
|
+
setBoolIfPresent("includeQHashes", params.includeQHashes);
|
|
1381
1758
|
setIfPresent("referenceType", params.referenceType);
|
|
1382
1759
|
setIfPresent("referenceId", params.referenceId);
|
|
1383
1760
|
setIfPresent("tag", params.tag);
|
|
@@ -1391,7 +1768,6 @@ ${bytes.length}`;
|
|
|
1391
1768
|
setIfPresent("domain", params.domain);
|
|
1392
1769
|
setIfPresent("minBalance", params.minBalance);
|
|
1393
1770
|
setIfPresent("provider", params.provider);
|
|
1394
|
-
setIfPresent("handle", params.handle);
|
|
1395
1771
|
setIfPresent("ownerAddress", params.ownerAddress);
|
|
1396
1772
|
setIfPresent("riskLevel", params.riskLevel);
|
|
1397
1773
|
setBoolIfPresent("sanctioned", params.sanctioned);
|
|
@@ -1399,9 +1775,40 @@ ${bytes.length}`;
|
|
|
1399
1775
|
setIfPresent("primaryWalletAddress", params.primaryWalletAddress);
|
|
1400
1776
|
setIfPresent("secondaryWalletAddress", params.secondaryWalletAddress);
|
|
1401
1777
|
setIfPresent("verificationMethod", params.verificationMethod);
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1778
|
+
let headersOverride = null;
|
|
1779
|
+
if (params.includePrivate === true) {
|
|
1780
|
+
const provided = params.privateAuth && typeof params.privateAuth === "object" ? params.privateAuth : null;
|
|
1781
|
+
let auth = provided;
|
|
1782
|
+
if (!auth) {
|
|
1783
|
+
const walletCandidate = params.wallet || this._getDefaultBrowserWallet();
|
|
1784
|
+
if (walletCandidate) {
|
|
1785
|
+
auth = await this._buildPrivateGateAuth({
|
|
1786
|
+
address,
|
|
1787
|
+
wallet: walletCandidate,
|
|
1788
|
+
chain: params.chain,
|
|
1789
|
+
signatureMethod: params.signatureMethod
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
if (!auth) {
|
|
1794
|
+
} else {
|
|
1795
|
+
const normalizedAuthWallet = this._normalizeIdentity(auth.walletAddress);
|
|
1796
|
+
const normalizedAddress = this._normalizeIdentity(address);
|
|
1797
|
+
if (!normalizedAuthWallet || normalizedAuthWallet !== normalizedAddress) {
|
|
1798
|
+
throw new ValidationError("privateAuth.walletAddress must match address when includePrivate=true");
|
|
1799
|
+
}
|
|
1800
|
+
const authChain = typeof auth.chain === "string" && auth.chain.includes(":") ? auth.chain.trim() : null;
|
|
1801
|
+
const authSignatureMethod = typeof auth.signatureMethod === "string" && auth.signatureMethod.trim() ? auth.signatureMethod.trim() : null;
|
|
1802
|
+
headersOverride = {
|
|
1803
|
+
"x-wallet-address": String(auth.walletAddress),
|
|
1804
|
+
"x-signature": String(auth.signature),
|
|
1805
|
+
"x-signed-timestamp": String(auth.signedTimestamp),
|
|
1806
|
+
...authChain ? { "x-chain": authChain } : {},
|
|
1807
|
+
...authSignatureMethod ? { "x-signature-method": authSignatureMethod } : {}
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
const response = await this._makeRequest("GET", `/api/v1/proofs/check?${qs.toString()}`, null, headersOverride);
|
|
1405
1812
|
if (!response.success) {
|
|
1406
1813
|
throw new ApiError(`Gate check failed: ${response.error?.message || "Unknown error"}`, response.error);
|
|
1407
1814
|
}
|
|
@@ -1425,7 +1832,7 @@ ${bytes.length}`;
|
|
|
1425
1832
|
* Supports verifier-specific:
|
|
1426
1833
|
* - NFT/Token: 'contractAddress', 'tokenId', 'chainId', 'ownerAddress', 'minBalance'
|
|
1427
1834
|
* - DNS: 'domain', 'walletAddress'
|
|
1428
|
-
* - Wallet-link: 'primaryWalletAddress', 'secondaryWalletAddress', '
|
|
1835
|
+
* - Wallet-link: 'primaryWalletAddress', 'secondaryWalletAddress', 'chain', 'signatureMethod'
|
|
1429
1836
|
* - Contract-ownership: 'contractAddress', 'chainId', 'owner', 'verificationMethod'
|
|
1430
1837
|
* Note: contentHash matching uses approximation in SDK; for exact SHA-256 matching, use backend API
|
|
1431
1838
|
* @param {Array} [params.proofs] - Pre-fetched proofs (skip API call)
|
|
@@ -1442,7 +1849,7 @@ ${bytes.length}`;
|
|
|
1442
1849
|
*/
|
|
1443
1850
|
async checkGate(params) {
|
|
1444
1851
|
const { walletAddress, requirements, proofs: preloadedProofs } = params;
|
|
1445
|
-
if (!
|
|
1852
|
+
if (!validateUniversalAddress(walletAddress)) {
|
|
1446
1853
|
throw new ValidationError("Valid walletAddress is required");
|
|
1447
1854
|
}
|
|
1448
1855
|
if (!Array.isArray(requirements) || requirements.length === 0) {
|
|
@@ -1636,16 +2043,20 @@ ${bytes.length}`;
|
|
|
1636
2043
|
* @private
|
|
1637
2044
|
*/
|
|
1638
2045
|
_formatResponse(response) {
|
|
1639
|
-
const
|
|
2046
|
+
const proofId = response?.data?.proofId || response?.proofId || response?.data?.resource?.proofId || response?.data?.qHash || response?.qHash || response?.data?.resource?.qHash || response?.data?.id;
|
|
2047
|
+
const qHash = response?.data?.qHash || response?.qHash || response?.data?.resource?.qHash || proofId || response?.data?.id;
|
|
2048
|
+
const finalProofId = proofId || qHash || null;
|
|
2049
|
+
const finalQHash = qHash || proofId || finalProofId;
|
|
1640
2050
|
const status = response?.data?.status || response?.status || response?.data?.resource?.status || (response?.success ? "completed" : "unknown");
|
|
1641
2051
|
return {
|
|
1642
2052
|
success: response.success,
|
|
1643
|
-
|
|
2053
|
+
proofId: finalProofId,
|
|
2054
|
+
qHash: finalQHash,
|
|
1644
2055
|
status,
|
|
1645
2056
|
data: response.data,
|
|
1646
2057
|
message: response.message,
|
|
1647
2058
|
timestamp: Date.now(),
|
|
1648
|
-
statusUrl:
|
|
2059
|
+
statusUrl: finalProofId ? `${this.baseUrl}/api/v1/verification/status/${finalProofId}` : null
|
|
1649
2060
|
};
|
|
1650
2061
|
}
|
|
1651
2062
|
/**
|