@neus/sdk 1.0.2 → 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 -112
- package/cjs/client.cjs +545 -175
- package/cjs/errors.cjs +1 -0
- package/cjs/gates.cjs +1 -0
- package/cjs/index.cjs +725 -180
- package/cjs/utils.cjs +338 -3
- package/client.js +1951 -1729
- package/index.js +75 -64
- package/neus-logo.svg +3 -0
- package/package.json +9 -5
- package/types.d.ts +215 -30
- package/utils.js +407 -4
- 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 +283 -58
- 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);
|
|
@@ -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,36 @@ 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" };
|
|
232
435
|
}
|
|
233
436
|
if (data.content !== void 0 && data.content !== null) {
|
|
234
437
|
if (typeof data.content !== "string") {
|
|
@@ -354,17 +557,20 @@ var validateVerifierData = (verifierId, data) => {
|
|
|
354
557
|
}
|
|
355
558
|
break;
|
|
356
559
|
case "wallet-link":
|
|
357
|
-
if (!data.primaryWalletAddress || !
|
|
560
|
+
if (!data.primaryWalletAddress || !validateUniversalAddress(data.primaryWalletAddress, data.chain)) {
|
|
358
561
|
return { valid: false, error: "primaryWalletAddress is required" };
|
|
359
562
|
}
|
|
360
|
-
if (!data.secondaryWalletAddress || !
|
|
563
|
+
if (!data.secondaryWalletAddress || !validateUniversalAddress(data.secondaryWalletAddress, data.chain)) {
|
|
361
564
|
return { valid: false, error: "secondaryWalletAddress is required" };
|
|
362
565
|
}
|
|
363
566
|
if (!data.signature || typeof data.signature !== "string") {
|
|
364
567
|
return { valid: false, error: "signature is required (signed by secondary wallet)" };
|
|
365
568
|
}
|
|
366
|
-
if (typeof data.
|
|
367
|
-
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" };
|
|
368
574
|
}
|
|
369
575
|
if (typeof data.signedTimestamp !== "number") {
|
|
370
576
|
return { valid: false, error: "signedTimestamp is required" };
|
|
@@ -459,7 +665,7 @@ var validateVerifierData = (verifierId, data) => {
|
|
|
459
665
|
}
|
|
460
666
|
break;
|
|
461
667
|
case "wallet-risk":
|
|
462
|
-
if (data.walletAddress && !
|
|
668
|
+
if (data.walletAddress && !validateUniversalAddress(data.walletAddress, data.chain)) {
|
|
463
669
|
return { valid: false, error: "Invalid walletAddress" };
|
|
464
670
|
}
|
|
465
671
|
break;
|
|
@@ -491,6 +697,26 @@ var NeusClient = class {
|
|
|
491
697
|
if (typeof this.config.apiKey === "string" && this.config.apiKey.trim().length > 0) {
|
|
492
698
|
this.defaultHeaders["Authorization"] = `Bearer ${this.config.apiKey.trim()}`;
|
|
493
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
|
+
}
|
|
494
720
|
try {
|
|
495
721
|
if (typeof window !== "undefined" && window.location && window.location.origin) {
|
|
496
722
|
this.defaultHeaders["X-Client-Origin"] = window.location.origin;
|
|
@@ -498,6 +724,122 @@ var NeusClient = class {
|
|
|
498
724
|
} catch {
|
|
499
725
|
}
|
|
500
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
|
+
}
|
|
501
843
|
// ============================================================================
|
|
502
844
|
// CORE VERIFICATION METHODS
|
|
503
845
|
// ============================================================================
|
|
@@ -519,7 +861,7 @@ var NeusClient = class {
|
|
|
519
861
|
* @param {string} [params.verifier] - Verifier ID (auto path)
|
|
520
862
|
* @param {string} [params.content] - Content/description (auto path)
|
|
521
863
|
* @param {Object} [params.wallet] - Optional injected wallet/provider (auto path)
|
|
522
|
-
* @returns {Promise<Object>} Verification result with qHash
|
|
864
|
+
* @returns {Promise<Object>} Verification result with proofId (qHash is a deprecated alias)
|
|
523
865
|
*
|
|
524
866
|
* @example
|
|
525
867
|
* const proof = await client.verify({
|
|
@@ -544,7 +886,7 @@ var NeusClient = class {
|
|
|
544
886
|
* @param {Object} [params.data] - Structured verification data
|
|
545
887
|
* @param {Object} [params.wallet] - Wallet provider
|
|
546
888
|
* @param {Object} [params.options] - Additional options
|
|
547
|
-
* @returns {Promise<Object>} Verification result with qHash
|
|
889
|
+
* @returns {Promise<Object>} Verification result with proofId (qHash is a deprecated alias)
|
|
548
890
|
*
|
|
549
891
|
* @example
|
|
550
892
|
* // Simple ownership proof
|
|
@@ -560,25 +902,23 @@ var NeusClient = class {
|
|
|
560
902
|
if (verifier === "ownership-basic" && !data2 && (!content || typeof content !== "string")) {
|
|
561
903
|
throw new ValidationError("content is required and must be a string (or use data param with owner + reference)");
|
|
562
904
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
"contract-ownership",
|
|
572
|
-
"wallet-risk",
|
|
573
|
-
// Wallet risk assessment (public)
|
|
574
|
-
// AI & Agent verifiers (ERC-8004 aligned)
|
|
575
|
-
"agent-identity",
|
|
576
|
-
"agent-delegation",
|
|
577
|
-
"ai-content-moderation"
|
|
578
|
-
];
|
|
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
|
+
}
|
|
579
913
|
if (!validVerifiers.includes(verifier)) {
|
|
580
914
|
throw new ValidationError(`Invalid verifier '${verifier}'. Must be one of: ${validVerifiers.join(", ")}.`);
|
|
581
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
|
+
}
|
|
582
922
|
const requiresDataParam = [
|
|
583
923
|
"ownership-dns-txt",
|
|
584
924
|
"wallet-link",
|
|
@@ -596,8 +936,12 @@ var NeusClient = class {
|
|
|
596
936
|
}
|
|
597
937
|
let walletAddress2, provider;
|
|
598
938
|
if (wallet) {
|
|
599
|
-
walletAddress2 = wallet.address || wallet.selectedAddress;
|
|
939
|
+
walletAddress2 = wallet.address || wallet.selectedAddress || wallet.walletAddress || (typeof wallet.getAddress === "function" ? await wallet.getAddress() : null);
|
|
600
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
|
+
}
|
|
601
945
|
} else {
|
|
602
946
|
if (typeof window === "undefined" || !window.ethereum) {
|
|
603
947
|
throw new ConfigurationError("No Web3 wallet detected. Please install MetaMask or provide wallet parameter.");
|
|
@@ -673,14 +1017,18 @@ var NeusClient = class {
|
|
|
673
1017
|
if (!data2?.signature) {
|
|
674
1018
|
throw new ValidationError("wallet-link requires signature in data parameter (signed by secondary wallet)");
|
|
675
1019
|
}
|
|
676
|
-
if (typeof data2?.
|
|
677
|
-
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");
|
|
678
1025
|
}
|
|
679
1026
|
verificationData = {
|
|
680
1027
|
primaryWalletAddress: walletAddress2,
|
|
681
1028
|
secondaryWalletAddress: data2.secondaryWalletAddress,
|
|
682
1029
|
signature: data2.signature,
|
|
683
|
-
|
|
1030
|
+
chain: data2.chain,
|
|
1031
|
+
signatureMethod: data2.signatureMethod,
|
|
684
1032
|
signedTimestamp: data2?.signedTimestamp || Date.now()
|
|
685
1033
|
};
|
|
686
1034
|
} else if (verifier === "contract-ownership") {
|
|
@@ -769,12 +1117,12 @@ var NeusClient = class {
|
|
|
769
1117
|
signedTimestamp: signedTimestamp2,
|
|
770
1118
|
data: verificationData,
|
|
771
1119
|
verifierIds: verifierIds2,
|
|
772
|
-
chainId:
|
|
1120
|
+
chainId: this._getHubChainId()
|
|
773
1121
|
// Protocol-managed chain
|
|
774
1122
|
});
|
|
775
1123
|
let signature2;
|
|
776
1124
|
try {
|
|
777
|
-
const
|
|
1125
|
+
const toHexUtf82 = (s) => {
|
|
778
1126
|
try {
|
|
779
1127
|
const enc = new TextEncoder();
|
|
780
1128
|
const bytes = enc.encode(s);
|
|
@@ -810,7 +1158,7 @@ var NeusClient = class {
|
|
|
810
1158
|
})();
|
|
811
1159
|
if (isFarcasterWallet) {
|
|
812
1160
|
try {
|
|
813
|
-
const hexMsg =
|
|
1161
|
+
const hexMsg = toHexUtf82(message);
|
|
814
1162
|
signature2 = await provider.request({ method: "personal_sign", params: [hexMsg, walletAddress2] });
|
|
815
1163
|
} catch (e) {
|
|
816
1164
|
}
|
|
@@ -859,7 +1207,7 @@ ${bytes.length}`;
|
|
|
859
1207
|
}
|
|
860
1208
|
} else if (needsHex) {
|
|
861
1209
|
this._log("Retrying personal_sign with hex-encoded message");
|
|
862
|
-
const hexMsg =
|
|
1210
|
+
const hexMsg = toHexUtf82(message);
|
|
863
1211
|
signature2 = await provider.request({ method: "personal_sign", params: [hexMsg, walletAddress2] });
|
|
864
1212
|
} else {
|
|
865
1213
|
throw e;
|
|
@@ -957,18 +1305,18 @@ ${bytes.length}`;
|
|
|
957
1305
|
/**
|
|
958
1306
|
* Get verification status
|
|
959
1307
|
*
|
|
960
|
-
* @param {string}
|
|
1308
|
+
* @param {string} proofId - Proof ID (standard). `qHash` is a deprecated alias (same value).
|
|
961
1309
|
* @returns {Promise<Object>} Verification status and data
|
|
962
1310
|
*
|
|
963
1311
|
* @example
|
|
964
1312
|
* const result = await client.getStatus('0x...');
|
|
965
1313
|
* console.log('Status:', result.status);
|
|
966
1314
|
*/
|
|
967
|
-
async getStatus(
|
|
968
|
-
if (!
|
|
969
|
-
throw new ValidationError("
|
|
1315
|
+
async getStatus(proofId) {
|
|
1316
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1317
|
+
throw new ValidationError("proofId is required");
|
|
970
1318
|
}
|
|
971
|
-
const response = await this._makeRequest("GET", `/api/v1/verification/status/${
|
|
1319
|
+
const response = await this._makeRequest("GET", `/api/v1/verification/status/${proofId}`);
|
|
972
1320
|
if (!response.success) {
|
|
973
1321
|
throw new ApiError(`Failed to get status: ${response.error?.message || "Unknown error"}`, response.error);
|
|
974
1322
|
}
|
|
@@ -977,70 +1325,72 @@ ${bytes.length}`;
|
|
|
977
1325
|
/**
|
|
978
1326
|
* Get private proof status with wallet signature
|
|
979
1327
|
*
|
|
980
|
-
* @param {string}
|
|
1328
|
+
* @param {string} proofId - Proof ID (standard). `qHash` is a deprecated alias (same value).
|
|
981
1329
|
* @param {Object} wallet - Wallet provider (window.ethereum or ethers Wallet)
|
|
982
1330
|
* @returns {Promise<Object>} Private verification status and data
|
|
983
1331
|
*
|
|
984
1332
|
* @example
|
|
985
1333
|
* // Access private proof
|
|
986
|
-
* const privateData = await client.getPrivateStatus(
|
|
1334
|
+
* const privateData = await client.getPrivateStatus(proofId, window.ethereum);
|
|
987
1335
|
*/
|
|
988
|
-
async getPrivateStatus(
|
|
989
|
-
if (!
|
|
990
|
-
throw new ValidationError("
|
|
1336
|
+
async getPrivateStatus(proofId, wallet = null) {
|
|
1337
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1338
|
+
throw new ValidationError("proofId is required");
|
|
991
1339
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
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
|
+
);
|
|
995
1356
|
}
|
|
996
|
-
|
|
1357
|
+
return this._formatResponse(response2);
|
|
997
1358
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
} else if (wallet.selectedAddress || wallet.request) {
|
|
1003
|
-
provider = wallet;
|
|
1004
|
-
if (wallet.selectedAddress) {
|
|
1005
|
-
walletAddress = wallet.selectedAddress;
|
|
1006
|
-
} else {
|
|
1007
|
-
const accounts = await provider.request({ method: "eth_accounts" });
|
|
1008
|
-
if (!accounts || accounts.length === 0) {
|
|
1009
|
-
throw new ConfigurationError("No wallet accounts available");
|
|
1010
|
-
}
|
|
1011
|
-
walletAddress = accounts[0];
|
|
1012
|
-
}
|
|
1013
|
-
} else {
|
|
1014
|
-
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");
|
|
1015
1363
|
}
|
|
1364
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(this._normalizeIdentity(walletAddress));
|
|
1365
|
+
const chain = this._inferChainForAddress(walletAddress);
|
|
1366
|
+
const signatureMethod = signerIsEvm ? "eip191" : "ed25519";
|
|
1016
1367
|
const signedTimestamp = Date.now();
|
|
1017
1368
|
const message = constructVerificationMessage({
|
|
1018
1369
|
walletAddress,
|
|
1019
1370
|
signedTimestamp,
|
|
1020
|
-
data: { action: "access_private_proof", qHash },
|
|
1371
|
+
data: { action: "access_private_proof", qHash: proofId },
|
|
1021
1372
|
verifierIds: ["ownership-basic"],
|
|
1022
|
-
chainId:
|
|
1373
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
1023
1374
|
});
|
|
1024
1375
|
let signature;
|
|
1025
1376
|
try {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
});
|
|
1033
|
-
}
|
|
1377
|
+
signature = await signMessage({
|
|
1378
|
+
provider,
|
|
1379
|
+
message,
|
|
1380
|
+
walletAddress,
|
|
1381
|
+
...signerIsEvm ? {} : { chain }
|
|
1382
|
+
});
|
|
1034
1383
|
} catch (error) {
|
|
1035
1384
|
if (error.code === 4001) {
|
|
1036
1385
|
throw new ValidationError("User rejected signature request");
|
|
1037
1386
|
}
|
|
1038
1387
|
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
1039
1388
|
}
|
|
1040
|
-
const response = await this._makeRequest("GET", `/api/v1/verification/status/${
|
|
1389
|
+
const response = await this._makeRequest("GET", `/api/v1/verification/status/${proofId}`, null, {
|
|
1041
1390
|
"x-wallet-address": walletAddress,
|
|
1042
1391
|
"x-signature": signature,
|
|
1043
|
-
"x-signed-timestamp": signedTimestamp.toString()
|
|
1392
|
+
"x-signed-timestamp": signedTimestamp.toString(),
|
|
1393
|
+
...signerIsEvm ? {} : { "x-chain": chain, "x-signature-method": signatureMethod }
|
|
1044
1394
|
});
|
|
1045
1395
|
if (!response.success) {
|
|
1046
1396
|
throw new ApiError(
|
|
@@ -1081,7 +1431,7 @@ ${bytes.length}`;
|
|
|
1081
1431
|
* Polls the verification status until it reaches a terminal state (completed or failed).
|
|
1082
1432
|
* Useful for providing real-time feedback to users during verification.
|
|
1083
1433
|
*
|
|
1084
|
-
* @param {string}
|
|
1434
|
+
* @param {string} proofId - Proof ID to poll (standard). `qHash` is a deprecated alias (same value).
|
|
1085
1435
|
* @param {Object} [options] - Polling options
|
|
1086
1436
|
* @param {number} [options.interval=5000] - Polling interval in ms
|
|
1087
1437
|
* @param {number} [options.timeout=120000] - Total timeout in ms
|
|
@@ -1089,7 +1439,7 @@ ${bytes.length}`;
|
|
|
1089
1439
|
* @returns {Promise<Object>} Final verification status
|
|
1090
1440
|
*
|
|
1091
1441
|
* @example
|
|
1092
|
-
* const finalStatus = await client.pollProofStatus(
|
|
1442
|
+
* const finalStatus = await client.pollProofStatus(proofId, {
|
|
1093
1443
|
* interval: 3000,
|
|
1094
1444
|
* timeout: 60000,
|
|
1095
1445
|
* onProgress: (status) => {
|
|
@@ -1100,20 +1450,20 @@ ${bytes.length}`;
|
|
|
1100
1450
|
* }
|
|
1101
1451
|
* });
|
|
1102
1452
|
*/
|
|
1103
|
-
async pollProofStatus(
|
|
1453
|
+
async pollProofStatus(proofId, options = {}) {
|
|
1104
1454
|
const {
|
|
1105
1455
|
interval = 5e3,
|
|
1106
1456
|
timeout = 12e4,
|
|
1107
1457
|
onProgress
|
|
1108
1458
|
} = options;
|
|
1109
|
-
if (!
|
|
1110
|
-
throw new ValidationError("
|
|
1459
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1460
|
+
throw new ValidationError("proofId is required");
|
|
1111
1461
|
}
|
|
1112
1462
|
const startTime = Date.now();
|
|
1113
1463
|
let consecutiveRateLimits = 0;
|
|
1114
1464
|
while (Date.now() - startTime < timeout) {
|
|
1115
1465
|
try {
|
|
1116
|
-
const status = await this.getStatus(
|
|
1466
|
+
const status = await this.getStatus(proofId);
|
|
1117
1467
|
consecutiveRateLimits = 0;
|
|
1118
1468
|
if (onProgress && typeof onProgress === "function") {
|
|
1119
1469
|
onProgress(status.data || status);
|
|
@@ -1161,70 +1511,51 @@ ${bytes.length}`;
|
|
|
1161
1511
|
}
|
|
1162
1512
|
}
|
|
1163
1513
|
/** Revoke your own proof (owner-signed) */
|
|
1164
|
-
async revokeOwnProof(
|
|
1165
|
-
if (!
|
|
1166
|
-
throw new ValidationError("
|
|
1514
|
+
async revokeOwnProof(proofId, wallet) {
|
|
1515
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1516
|
+
throw new ValidationError("proofId is required");
|
|
1167
1517
|
}
|
|
1168
|
-
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";
|
|
1169
1526
|
const signedTimestamp = Date.now();
|
|
1170
|
-
const hubChainId = NEUS_CONSTANTS.HUB_CHAIN_ID;
|
|
1171
1527
|
const message = constructVerificationMessage({
|
|
1172
1528
|
walletAddress: address,
|
|
1173
1529
|
signedTimestamp,
|
|
1174
|
-
|
|
1530
|
+
// Keep wire payload key `qHash` for backwards compatibility.
|
|
1531
|
+
data: { action: "revoke_proof", qHash: proofId },
|
|
1175
1532
|
verifierIds: ["ownership-basic"],
|
|
1176
|
-
chainId:
|
|
1533
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
1177
1534
|
});
|
|
1178
1535
|
let signature;
|
|
1179
1536
|
try {
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
return hex;
|
|
1187
|
-
};
|
|
1188
|
-
const isFarcasterWallet = (() => {
|
|
1189
|
-
if (typeof window === "undefined")
|
|
1190
|
-
return false;
|
|
1191
|
-
try {
|
|
1192
|
-
const w = window;
|
|
1193
|
-
const fc = w.farcaster;
|
|
1194
|
-
if (!fc || !fc.context)
|
|
1195
|
-
return false;
|
|
1196
|
-
const fcProvider = fc.provider || fc.walletProvider || fc.context && fc.context.walletProvider;
|
|
1197
|
-
if (fcProvider === w.ethereum)
|
|
1198
|
-
return true;
|
|
1199
|
-
if (w.mini && w.mini.wallet === w.ethereum && fc && fc.context)
|
|
1200
|
-
return true;
|
|
1201
|
-
if (w.ethereum && fc && fc.context)
|
|
1202
|
-
return true;
|
|
1203
|
-
} catch {
|
|
1204
|
-
}
|
|
1205
|
-
return false;
|
|
1206
|
-
})();
|
|
1207
|
-
if (isFarcasterWallet) {
|
|
1208
|
-
try {
|
|
1209
|
-
const hexMsg = toHexUtf8(message);
|
|
1210
|
-
signature = await window.ethereum.request({ method: "personal_sign", params: [hexMsg, address] });
|
|
1211
|
-
} catch {
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
if (!signature) {
|
|
1215
|
-
signature = await window.ethereum.request({ method: "personal_sign", params: [message, address] });
|
|
1216
|
-
}
|
|
1537
|
+
signature = await signMessage({
|
|
1538
|
+
provider,
|
|
1539
|
+
message,
|
|
1540
|
+
walletAddress: address,
|
|
1541
|
+
...signerIsEvm ? {} : { chain }
|
|
1542
|
+
});
|
|
1217
1543
|
} catch (error) {
|
|
1218
1544
|
if (error.code === 4001) {
|
|
1219
1545
|
throw new ValidationError("User rejected revocation signature");
|
|
1220
1546
|
}
|
|
1221
1547
|
throw new ValidationError(`Failed to sign revocation: ${error.message}`);
|
|
1222
1548
|
}
|
|
1223
|
-
const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/${
|
|
1549
|
+
const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/${proofId}/revoke-self`, {
|
|
1224
1550
|
method: "POST",
|
|
1225
1551
|
// SECURITY: Do not put proof signatures into Authorization headers.
|
|
1226
1552
|
headers: { "Content-Type": "application/json" },
|
|
1227
|
-
body: JSON.stringify({
|
|
1553
|
+
body: JSON.stringify({
|
|
1554
|
+
walletAddress: address,
|
|
1555
|
+
signature,
|
|
1556
|
+
signedTimestamp,
|
|
1557
|
+
...signerIsEvm ? {} : { chain, signatureMethod }
|
|
1558
|
+
})
|
|
1228
1559
|
});
|
|
1229
1560
|
const json = await res.json();
|
|
1230
1561
|
if (!json.success) {
|
|
@@ -1238,7 +1569,7 @@ ${bytes.length}`;
|
|
|
1238
1569
|
/**
|
|
1239
1570
|
* GET PROOFS BY WALLET - Fetch proofs for a wallet address
|
|
1240
1571
|
*
|
|
1241
|
-
* @param {string} walletAddress - Wallet
|
|
1572
|
+
* @param {string} walletAddress - Wallet identity (EVM/Solana/DID)
|
|
1242
1573
|
* @param {Object} [options] - Filter options
|
|
1243
1574
|
* @param {number} [options.limit] - Max results (default: 50; higher limits require owner access)
|
|
1244
1575
|
* @param {number} [options.offset] - Pagination offset (default: 0)
|
|
@@ -1283,7 +1614,7 @@ ${bytes.length}`;
|
|
|
1283
1614
|
*
|
|
1284
1615
|
* Signs an owner-access intent and requests private proofs via signature headers.
|
|
1285
1616
|
*
|
|
1286
|
-
* @param {string} walletAddress - Wallet
|
|
1617
|
+
* @param {string} walletAddress - Wallet identity (EVM/Solana/DID)
|
|
1287
1618
|
* @param {Object} [options]
|
|
1288
1619
|
* @param {number} [options.limit] - Max results (server enforces caps)
|
|
1289
1620
|
* @param {number} [options.offset] - Pagination offset
|
|
@@ -1295,48 +1626,41 @@ ${bytes.length}`;
|
|
|
1295
1626
|
}
|
|
1296
1627
|
const id = walletAddress.trim();
|
|
1297
1628
|
const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
|
|
1629
|
+
const requestedIdentity = this._normalizeIdentity(id);
|
|
1298
1630
|
if (!wallet) {
|
|
1299
|
-
|
|
1631
|
+
const defaultWallet = this._getDefaultBrowserWallet();
|
|
1632
|
+
if (!defaultWallet) {
|
|
1300
1633
|
throw new ConfigurationError("No wallet provider available");
|
|
1301
1634
|
}
|
|
1302
|
-
wallet =
|
|
1635
|
+
wallet = defaultWallet;
|
|
1303
1636
|
}
|
|
1304
|
-
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1307
|
-
provider = wallet;
|
|
1308
|
-
} else if (wallet.selectedAddress || wallet.request) {
|
|
1309
|
-
provider = wallet;
|
|
1310
|
-
if (wallet.selectedAddress) {
|
|
1311
|
-
signerWalletAddress = wallet.selectedAddress;
|
|
1312
|
-
} else {
|
|
1313
|
-
const accounts = await provider.request({ method: "eth_accounts" });
|
|
1314
|
-
if (!accounts || accounts.length === 0) {
|
|
1315
|
-
throw new ConfigurationError("No wallet accounts available");
|
|
1316
|
-
}
|
|
1317
|
-
signerWalletAddress = accounts[0];
|
|
1318
|
-
}
|
|
1319
|
-
} else {
|
|
1320
|
-
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");
|
|
1321
1640
|
}
|
|
1641
|
+
const normalizedSigner = this._normalizeIdentity(signerWalletAddress);
|
|
1642
|
+
if (!normalizedSigner || normalizedSigner !== requestedIdentity) {
|
|
1643
|
+
throw new ValidationError("wallet must match walletAddress for private proof access");
|
|
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";
|
|
1322
1648
|
const signedTimestamp = Date.now();
|
|
1323
1649
|
const message = constructVerificationMessage({
|
|
1324
1650
|
walletAddress: signerWalletAddress,
|
|
1325
1651
|
signedTimestamp,
|
|
1326
|
-
data: { action: "access_private_proofs_by_wallet", walletAddress:
|
|
1652
|
+
data: { action: "access_private_proofs_by_wallet", walletAddress: normalizedSigner },
|
|
1327
1653
|
verifierIds: ["ownership-basic"],
|
|
1328
|
-
chainId:
|
|
1654
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
1329
1655
|
});
|
|
1330
1656
|
let signature;
|
|
1331
1657
|
try {
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
});
|
|
1339
|
-
}
|
|
1658
|
+
signature = await signMessage({
|
|
1659
|
+
provider,
|
|
1660
|
+
message,
|
|
1661
|
+
walletAddress: signerWalletAddress,
|
|
1662
|
+
...signerIsEvm ? {} : { chain }
|
|
1663
|
+
});
|
|
1340
1664
|
} catch (error) {
|
|
1341
1665
|
if (error.code === 4001) {
|
|
1342
1666
|
throw new ValidationError("User rejected signature request");
|
|
@@ -1352,7 +1676,8 @@ ${bytes.length}`;
|
|
|
1352
1676
|
const response = await this._makeRequest("GET", `/api/v1/proofs/byWallet/${encodeURIComponent(pathId)}${query}`, null, {
|
|
1353
1677
|
"x-wallet-address": signerWalletAddress,
|
|
1354
1678
|
"x-signature": signature,
|
|
1355
|
-
"x-signed-timestamp": signedTimestamp.toString()
|
|
1679
|
+
"x-signed-timestamp": signedTimestamp.toString(),
|
|
1680
|
+
...signerIsEvm ? {} : { "x-chain": chain, "x-signature-method": signatureMethod }
|
|
1356
1681
|
});
|
|
1357
1682
|
if (!response.success) {
|
|
1358
1683
|
throw new ApiError(`Failed to get proofs: ${response.error?.message || "Unauthorized"}`, response.error);
|
|
@@ -1369,25 +1694,31 @@ ${bytes.length}`;
|
|
|
1369
1694
|
/**
|
|
1370
1695
|
* GATE CHECK (API) - Minimal eligibility check
|
|
1371
1696
|
*
|
|
1372
|
-
* Calls the
|
|
1373
|
-
*
|
|
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.
|
|
1374
1702
|
*
|
|
1375
|
-
* Prefer this over `checkGate()` for
|
|
1703
|
+
* Prefer this over `checkGate()` for integrations that want the
|
|
1376
1704
|
* smallest, most stable surface area (and do NOT need full proof payloads).
|
|
1377
1705
|
*
|
|
1378
1706
|
* @param {Object} params - Gate check query params
|
|
1379
|
-
* @param {string} params.address - Wallet
|
|
1707
|
+
* @param {string} params.address - Wallet identity to check (EVM/Solana/DID)
|
|
1380
1708
|
* @param {Array<string>|string} [params.verifierIds] - Verifier IDs to match (array or comma-separated)
|
|
1381
1709
|
* @param {boolean} [params.requireAll] - Require all verifierIds on a single proof
|
|
1382
1710
|
* @param {number} [params.minCount] - Minimum number of matching proofs
|
|
1383
1711
|
* @param {number} [params.sinceDays] - Optional time window in days
|
|
1384
1712
|
* @param {number} [params.since] - Optional unix timestamp in ms (lower bound)
|
|
1385
1713
|
* @param {number} [params.limit] - Max rows to scan (server may clamp)
|
|
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
|
|
1386
1717
|
* @returns {Promise<Object>} API response ({ success, data })
|
|
1387
1718
|
*/
|
|
1388
1719
|
async gateCheck(params = {}) {
|
|
1389
1720
|
const address = (params.address || "").toString();
|
|
1390
|
-
if (!address
|
|
1721
|
+
if (!validateUniversalAddress(address, params.chain)) {
|
|
1391
1722
|
throw new ValidationError("Valid address is required");
|
|
1392
1723
|
}
|
|
1393
1724
|
const qs = new URLSearchParams();
|
|
@@ -1422,6 +1753,8 @@ ${bytes.length}`;
|
|
|
1422
1753
|
setIfPresent("sinceDays", params.sinceDays);
|
|
1423
1754
|
setIfPresent("since", params.since);
|
|
1424
1755
|
setIfPresent("limit", params.limit);
|
|
1756
|
+
setBoolIfPresent("includePrivate", params.includePrivate);
|
|
1757
|
+
setBoolIfPresent("includeQHashes", params.includeQHashes);
|
|
1425
1758
|
setIfPresent("referenceType", params.referenceType);
|
|
1426
1759
|
setIfPresent("referenceId", params.referenceId);
|
|
1427
1760
|
setIfPresent("tag", params.tag);
|
|
@@ -1442,7 +1775,40 @@ ${bytes.length}`;
|
|
|
1442
1775
|
setIfPresent("primaryWalletAddress", params.primaryWalletAddress);
|
|
1443
1776
|
setIfPresent("secondaryWalletAddress", params.secondaryWalletAddress);
|
|
1444
1777
|
setIfPresent("verificationMethod", params.verificationMethod);
|
|
1445
|
-
|
|
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);
|
|
1446
1812
|
if (!response.success) {
|
|
1447
1813
|
throw new ApiError(`Gate check failed: ${response.error?.message || "Unknown error"}`, response.error);
|
|
1448
1814
|
}
|
|
@@ -1466,7 +1832,7 @@ ${bytes.length}`;
|
|
|
1466
1832
|
* Supports verifier-specific:
|
|
1467
1833
|
* - NFT/Token: 'contractAddress', 'tokenId', 'chainId', 'ownerAddress', 'minBalance'
|
|
1468
1834
|
* - DNS: 'domain', 'walletAddress'
|
|
1469
|
-
* - Wallet-link: 'primaryWalletAddress', 'secondaryWalletAddress', '
|
|
1835
|
+
* - Wallet-link: 'primaryWalletAddress', 'secondaryWalletAddress', 'chain', 'signatureMethod'
|
|
1470
1836
|
* - Contract-ownership: 'contractAddress', 'chainId', 'owner', 'verificationMethod'
|
|
1471
1837
|
* Note: contentHash matching uses approximation in SDK; for exact SHA-256 matching, use backend API
|
|
1472
1838
|
* @param {Array} [params.proofs] - Pre-fetched proofs (skip API call)
|
|
@@ -1483,7 +1849,7 @@ ${bytes.length}`;
|
|
|
1483
1849
|
*/
|
|
1484
1850
|
async checkGate(params) {
|
|
1485
1851
|
const { walletAddress, requirements, proofs: preloadedProofs } = params;
|
|
1486
|
-
if (!
|
|
1852
|
+
if (!validateUniversalAddress(walletAddress)) {
|
|
1487
1853
|
throw new ValidationError("Valid walletAddress is required");
|
|
1488
1854
|
}
|
|
1489
1855
|
if (!Array.isArray(requirements) || requirements.length === 0) {
|
|
@@ -1677,16 +2043,20 @@ ${bytes.length}`;
|
|
|
1677
2043
|
* @private
|
|
1678
2044
|
*/
|
|
1679
2045
|
_formatResponse(response) {
|
|
1680
|
-
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;
|
|
1681
2050
|
const status = response?.data?.status || response?.status || response?.data?.resource?.status || (response?.success ? "completed" : "unknown");
|
|
1682
2051
|
return {
|
|
1683
2052
|
success: response.success,
|
|
1684
|
-
|
|
2053
|
+
proofId: finalProofId,
|
|
2054
|
+
qHash: finalQHash,
|
|
1685
2055
|
status,
|
|
1686
2056
|
data: response.data,
|
|
1687
2057
|
message: response.message,
|
|
1688
2058
|
timestamp: Date.now(),
|
|
1689
|
-
statusUrl:
|
|
2059
|
+
statusUrl: finalProofId ? `${this.baseUrl}/api/v1/verification/status/${finalProofId}` : null
|
|
1690
2060
|
};
|
|
1691
2061
|
}
|
|
1692
2062
|
/**
|