@neus/sdk 1.0.2 → 1.0.4
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 +53 -75
- package/SECURITY.md +33 -29
- package/cjs/client.cjs +678 -337
- package/cjs/errors.cjs +1 -0
- package/cjs/gates.cjs +1 -0
- package/cjs/index.cjs +927 -362
- package/cjs/utils.cjs +408 -32
- package/cli/neus.mjs +58 -0
- package/client.js +1957 -1728
- package/errors.js +5 -5
- package/gates.js +18 -18
- package/index.js +18 -3
- package/neus-logo.svg +3 -0
- package/package.json +21 -11
- package/types.d.ts +303 -53
- package/utils.js +1291 -777
- package/widgets/README.md +12 -20
- package/widgets/index.js +9 -9
- package/widgets/verify-gate/dist/ProofBadge.js +57 -52
- package/widgets/verify-gate/dist/VerifyGate.js +357 -121
- 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;
|
|
@@ -20,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
21
|
var client_exports = {};
|
|
21
22
|
__export(client_exports, {
|
|
22
23
|
NeusClient: () => NeusClient,
|
|
24
|
+
PORTABLE_PROOF_SIGNER_HEADER: () => PORTABLE_PROOF_SIGNER_HEADER,
|
|
23
25
|
constructVerificationMessage: () => constructVerificationMessage
|
|
24
26
|
});
|
|
25
27
|
module.exports = __toCommonJS(client_exports);
|
|
@@ -128,21 +130,77 @@ var ConfigurationError = class extends SDKError {
|
|
|
128
130
|
};
|
|
129
131
|
|
|
130
132
|
// utils.js
|
|
133
|
+
var PORTABLE_PROOF_SIGNER_HEADER = "Portable Proof Verification Request";
|
|
134
|
+
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
135
|
+
function encodeBase58Bytes(input) {
|
|
136
|
+
let source;
|
|
137
|
+
if (input instanceof Uint8Array) {
|
|
138
|
+
source = input;
|
|
139
|
+
} else if (input instanceof ArrayBuffer) {
|
|
140
|
+
source = new Uint8Array(input);
|
|
141
|
+
} else if (ArrayBuffer.isView(input)) {
|
|
142
|
+
source = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
|
|
143
|
+
} else if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(input)) {
|
|
144
|
+
source = new Uint8Array(input);
|
|
145
|
+
} else {
|
|
146
|
+
throw new SDKError("Unsupported non-EVM signature byte format", "INVALID_SIGNATURE_FORMAT");
|
|
147
|
+
}
|
|
148
|
+
if (source.length === 0) return "";
|
|
149
|
+
let zeroes = 0;
|
|
150
|
+
while (zeroes < source.length && source[zeroes] === 0) {
|
|
151
|
+
zeroes++;
|
|
152
|
+
}
|
|
153
|
+
const iFactor = Math.log(256) / Math.log(58);
|
|
154
|
+
const size = (source.length - zeroes) * iFactor + 1 >>> 0;
|
|
155
|
+
const b58 = new Uint8Array(size);
|
|
156
|
+
let length = 0;
|
|
157
|
+
for (let i = zeroes; i < source.length; i++) {
|
|
158
|
+
let carry = source[i];
|
|
159
|
+
let j = 0;
|
|
160
|
+
for (let k = size - 1; (carry !== 0 || j < length) && k >= 0; k--, j++) {
|
|
161
|
+
carry += 256 * b58[k];
|
|
162
|
+
b58[k] = carry % 58;
|
|
163
|
+
carry = carry / 58 | 0;
|
|
164
|
+
}
|
|
165
|
+
length = j;
|
|
166
|
+
}
|
|
167
|
+
let it = size - length;
|
|
168
|
+
while (it < size && b58[it] === 0) {
|
|
169
|
+
it++;
|
|
170
|
+
}
|
|
171
|
+
let out = BASE58_ALPHABET[0].repeat(zeroes);
|
|
172
|
+
for (; it < size; it++) {
|
|
173
|
+
out += BASE58_ALPHABET[b58[it]];
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
131
177
|
function deterministicStringify(obj) {
|
|
132
178
|
if (obj === null || obj === void 0) {
|
|
133
179
|
return JSON.stringify(obj);
|
|
134
180
|
}
|
|
135
181
|
if (typeof obj !== "object") {
|
|
182
|
+
if (typeof obj === "string") return JSON.stringify(obj.normalize("NFC"));
|
|
136
183
|
return JSON.stringify(obj);
|
|
137
184
|
}
|
|
138
185
|
if (Array.isArray(obj)) {
|
|
139
|
-
return
|
|
186
|
+
return `[${obj.map((item) => item === void 0 ? "null" : deterministicStringify(item)).join(",")}]`;
|
|
140
187
|
}
|
|
141
|
-
const sortedKeys = Object.keys(obj).sort();
|
|
188
|
+
const sortedKeys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
|
|
142
189
|
const pairs = sortedKeys.map(
|
|
143
|
-
(key) => JSON.stringify(key)
|
|
190
|
+
(key) => `${JSON.stringify(key)}:${deterministicStringify(obj[key])}`
|
|
144
191
|
);
|
|
145
|
-
return
|
|
192
|
+
return `{${pairs.join(",")}}`;
|
|
193
|
+
}
|
|
194
|
+
function chainLineForPortableProofSigner(chain, chainId) {
|
|
195
|
+
if (typeof chain === "string" && chain.length > 0) {
|
|
196
|
+
const m = chain.match(/^eip155:(\d+)$/);
|
|
197
|
+
if (m) return Number(m[1]);
|
|
198
|
+
return chain;
|
|
199
|
+
}
|
|
200
|
+
if (typeof chainId === "number" && Number.isFinite(chainId) && chainId > 0) {
|
|
201
|
+
return chainId;
|
|
202
|
+
}
|
|
203
|
+
throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
|
|
146
204
|
}
|
|
147
205
|
function constructVerificationMessage({ walletAddress, signedTimestamp, data, verifierIds, chainId, chain }) {
|
|
148
206
|
if (!walletAddress || typeof walletAddress !== "string") {
|
|
@@ -157,28 +215,28 @@ function constructVerificationMessage({ walletAddress, signedTimestamp, data, ve
|
|
|
157
215
|
if (!Array.isArray(verifierIds) || verifierIds.length === 0) {
|
|
158
216
|
throw new SDKError("verifierIds is required and must be a non-empty array", "INVALID_VERIFIER_IDS");
|
|
159
217
|
}
|
|
160
|
-
|
|
161
|
-
if (!chainContext) {
|
|
218
|
+
if ((typeof chain !== "string" || !chain.length) && !(typeof chainId === "number" && chainId > 0)) {
|
|
162
219
|
throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
|
|
163
220
|
}
|
|
164
|
-
if (
|
|
165
|
-
throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
|
|
166
|
-
}
|
|
167
|
-
if (chainContext === chain && (typeof chain !== "string" || !chain.includes(":"))) {
|
|
221
|
+
if (typeof chain === "string" && chain.length > 0 && !chain.includes(":")) {
|
|
168
222
|
throw new SDKError('chain must be a "namespace:reference" string', "INVALID_CHAIN");
|
|
169
223
|
}
|
|
224
|
+
if ((!chain || !chain.length) && typeof chainId !== "number") {
|
|
225
|
+
throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
|
|
226
|
+
}
|
|
227
|
+
const chainLine = chainLineForPortableProofSigner(chain, chainId);
|
|
170
228
|
const namespace = typeof chain === "string" && chain.includes(":") ? chain.split(":")[0] : "eip155";
|
|
171
229
|
const normalizedWalletAddress = namespace === "eip155" ? walletAddress.toLowerCase() : walletAddress;
|
|
172
230
|
const dataString = deterministicStringify(data);
|
|
173
231
|
const messageComponents = [
|
|
174
|
-
|
|
232
|
+
PORTABLE_PROOF_SIGNER_HEADER,
|
|
175
233
|
`Wallet: ${normalizedWalletAddress}`,
|
|
176
|
-
`Chain: ${
|
|
234
|
+
`Chain: ${chainLine}`,
|
|
177
235
|
`Verifiers: ${verifierIds.join(",")}`,
|
|
178
236
|
`Data: ${dataString}`,
|
|
179
237
|
`Timestamp: ${signedTimestamp}`
|
|
180
238
|
];
|
|
181
|
-
return messageComponents.join("\n");
|
|
239
|
+
return messageComponents.join("\n").normalize("NFC");
|
|
182
240
|
}
|
|
183
241
|
function validateWalletAddress(address) {
|
|
184
242
|
if (!address || typeof address !== "string") {
|
|
@@ -186,8 +244,127 @@ function validateWalletAddress(address) {
|
|
|
186
244
|
}
|
|
187
245
|
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
188
246
|
}
|
|
247
|
+
function validateUniversalAddress(address, chain) {
|
|
248
|
+
if (!address || typeof address !== "string") return false;
|
|
249
|
+
const value = address.trim();
|
|
250
|
+
if (!value) return false;
|
|
251
|
+
const chainRef = typeof chain === "string" ? chain.trim().toLowerCase() : "";
|
|
252
|
+
const namespace = chainRef.includes(":") ? chainRef.split(":")[0] : "";
|
|
253
|
+
if (validateWalletAddress(value)) return true;
|
|
254
|
+
if (namespace === "eip155") return false;
|
|
255
|
+
if (namespace === "solana") {
|
|
256
|
+
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(value);
|
|
257
|
+
}
|
|
258
|
+
if (namespace === "bip122") {
|
|
259
|
+
return /^(bc1|tb1|bcrt1)[a-z0-9]{11,87}$/.test(value.toLowerCase()) || /^[13mn2][a-km-zA-HJ-NP-Z1-9]{25,62}$/.test(value);
|
|
260
|
+
}
|
|
261
|
+
if (namespace === "near") {
|
|
262
|
+
return /^[a-z0-9._-]{2,64}$/.test(value);
|
|
263
|
+
}
|
|
264
|
+
return /^[A-Za-z0-9][A-Za-z0-9._:-]{1,127}$/.test(value);
|
|
265
|
+
}
|
|
266
|
+
function toHexUtf8(value) {
|
|
267
|
+
const input = typeof value === "string" ? value : String(value || "");
|
|
268
|
+
const bytes = new TextEncoder().encode(input);
|
|
269
|
+
return `0x${Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
270
|
+
}
|
|
271
|
+
async function signMessage({ provider, message, walletAddress, chain } = {}) {
|
|
272
|
+
const msg = typeof message === "string" ? message : String(message || "");
|
|
273
|
+
if (!msg) {
|
|
274
|
+
throw new SDKError("signMessage: message is required", "INVALID_ARGUMENT");
|
|
275
|
+
}
|
|
276
|
+
const resolvedProvider = provider || (typeof window !== "undefined" && window?.ethereum ? window.ethereum : null);
|
|
277
|
+
if (!resolvedProvider) {
|
|
278
|
+
throw new SDKError("signMessage: provider is required", "SIGNER_UNAVAILABLE");
|
|
279
|
+
}
|
|
280
|
+
const chainStr = typeof chain === "string" && chain.trim().length > 0 ? chain.trim() : "eip155";
|
|
281
|
+
const namespace = chainStr.includes(":") ? chainStr.split(":")[0] || "eip155" : "eip155";
|
|
282
|
+
const resolveAddress = async () => {
|
|
283
|
+
if (typeof walletAddress === "string" && walletAddress.trim().length > 0) return walletAddress;
|
|
284
|
+
if (namespace === "solana") {
|
|
285
|
+
if (resolvedProvider?.publicKey && typeof resolvedProvider.publicKey.toBase58 === "function") {
|
|
286
|
+
const pk = resolvedProvider.publicKey.toBase58();
|
|
287
|
+
if (typeof pk === "string" && pk) return pk;
|
|
288
|
+
}
|
|
289
|
+
if (typeof resolvedProvider.getAddress === "function") {
|
|
290
|
+
const addr = await resolvedProvider.getAddress().catch(() => null);
|
|
291
|
+
if (typeof addr === "string" && addr) return addr;
|
|
292
|
+
}
|
|
293
|
+
if (typeof resolvedProvider.address === "string" && resolvedProvider.address) return resolvedProvider.address;
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
if (typeof resolvedProvider.address === "string" && resolvedProvider.address) return resolvedProvider.address;
|
|
297
|
+
if (typeof resolvedProvider.getAddress === "function") return resolvedProvider.getAddress();
|
|
298
|
+
if (typeof resolvedProvider.request === "function") {
|
|
299
|
+
let accounts = await resolvedProvider.request({ method: "eth_accounts" }).catch(() => []);
|
|
300
|
+
if (!Array.isArray(accounts) || accounts.length === 0) {
|
|
301
|
+
accounts = await resolvedProvider.request({ method: "eth_requestAccounts" }).catch(() => []);
|
|
302
|
+
}
|
|
303
|
+
if (Array.isArray(accounts) && accounts[0]) return accounts[0];
|
|
304
|
+
}
|
|
305
|
+
return null;
|
|
306
|
+
};
|
|
307
|
+
if (namespace !== "eip155") {
|
|
308
|
+
if (typeof resolvedProvider.signMessage === "function") {
|
|
309
|
+
const encoded = typeof msg === "string" ? new TextEncoder().encode(msg) : msg;
|
|
310
|
+
const result = await resolvedProvider.signMessage(encoded);
|
|
311
|
+
if (typeof result === "string" && result) return result;
|
|
312
|
+
if (result instanceof Uint8Array) return encodeBase58Bytes(result);
|
|
313
|
+
if (result instanceof ArrayBuffer) return encodeBase58Bytes(new Uint8Array(result));
|
|
314
|
+
if (ArrayBuffer.isView(result)) return encodeBase58Bytes(result);
|
|
315
|
+
if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(result)) return encodeBase58Bytes(result);
|
|
316
|
+
}
|
|
317
|
+
throw new SDKError("Non-EVM signing requires provider.signMessage", "SIGNER_UNAVAILABLE");
|
|
318
|
+
}
|
|
319
|
+
const address = await resolveAddress();
|
|
320
|
+
if (typeof resolvedProvider.request === "function" && address) {
|
|
321
|
+
let firstPersonalSignError = null;
|
|
322
|
+
try {
|
|
323
|
+
const sig = await resolvedProvider.request({ method: "personal_sign", params: [msg, address] });
|
|
324
|
+
if (typeof sig === "string" && sig) return sig;
|
|
325
|
+
} catch (error) {
|
|
326
|
+
firstPersonalSignError = error;
|
|
327
|
+
}
|
|
328
|
+
let secondPersonalSignError = null;
|
|
329
|
+
try {
|
|
330
|
+
const sig = await resolvedProvider.request({ method: "personal_sign", params: [address, msg] });
|
|
331
|
+
if (typeof sig === "string" && sig) return sig;
|
|
332
|
+
} catch (error) {
|
|
333
|
+
secondPersonalSignError = error;
|
|
334
|
+
const signatureErrorMessage = String(
|
|
335
|
+
error?.message || error?.reason || firstPersonalSignError?.message || firstPersonalSignError?.reason || ""
|
|
336
|
+
).toLowerCase();
|
|
337
|
+
const needsHex = /byte|bytes|invalid byte sequence|encoding|non-hex/i.test(signatureErrorMessage);
|
|
338
|
+
if (needsHex) {
|
|
339
|
+
try {
|
|
340
|
+
const hexMsg = toHexUtf8(msg);
|
|
341
|
+
const sig = await resolvedProvider.request({ method: "personal_sign", params: [hexMsg, address] });
|
|
342
|
+
if (typeof sig === "string" && sig) return sig;
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
const sig = await resolvedProvider.request({ method: "eth_sign", params: [address, msg] });
|
|
349
|
+
if (typeof sig === "string" && sig) return sig;
|
|
350
|
+
} catch {
|
|
351
|
+
}
|
|
352
|
+
if (secondPersonalSignError || firstPersonalSignError) {
|
|
353
|
+
const lastError = secondPersonalSignError || firstPersonalSignError;
|
|
354
|
+
const isUserRejection = [4001, "ACTION_REJECTED"].includes(lastError?.code);
|
|
355
|
+
if (isUserRejection) {
|
|
356
|
+
throw lastError;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (typeof resolvedProvider.signMessage === "function") {
|
|
361
|
+
const result = await resolvedProvider.signMessage(msg);
|
|
362
|
+
if (typeof result === "string" && result) return result;
|
|
363
|
+
}
|
|
364
|
+
throw new SDKError("Unable to sign message with provided wallet/provider", "SIGNER_UNAVAILABLE");
|
|
365
|
+
}
|
|
189
366
|
var NEUS_CONSTANTS = {
|
|
190
|
-
|
|
367
|
+
/** Default EVM chain id for NEUS protocol signing context (`HUB_CHAIN_ID` name kept for compatibility). */
|
|
191
368
|
HUB_CHAIN_ID: 84532,
|
|
192
369
|
// Supported target chains for cross-chain propagation
|
|
193
370
|
TESTNET_CHAINS: [
|
|
@@ -217,18 +394,31 @@ var NEUS_CONSTANTS = {
|
|
|
217
394
|
};
|
|
218
395
|
|
|
219
396
|
// client.js
|
|
397
|
+
var FALLBACK_PUBLIC_VERIFIER_CATALOG = {
|
|
398
|
+
"ownership-basic": { supportsDirectApi: true },
|
|
399
|
+
"ownership-pseudonym": { supportsDirectApi: true },
|
|
400
|
+
"ownership-dns-txt": { supportsDirectApi: true },
|
|
401
|
+
"ownership-social": { supportsDirectApi: false },
|
|
402
|
+
"ownership-org-oauth": { supportsDirectApi: false },
|
|
403
|
+
"contract-ownership": { supportsDirectApi: true },
|
|
404
|
+
"nft-ownership": { supportsDirectApi: true },
|
|
405
|
+
"token-holding": { supportsDirectApi: true },
|
|
406
|
+
"wallet-link": { supportsDirectApi: true },
|
|
407
|
+
"wallet-risk": { supportsDirectApi: true },
|
|
408
|
+
"proof-of-human": { supportsDirectApi: false },
|
|
409
|
+
"agent-identity": { supportsDirectApi: true },
|
|
410
|
+
"agent-delegation": { supportsDirectApi: true },
|
|
411
|
+
"ai-content-moderation": { supportsDirectApi: true }
|
|
412
|
+
};
|
|
413
|
+
var EVM_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
|
|
220
414
|
var validateVerifierData = (verifierId, data) => {
|
|
221
415
|
if (!data || typeof data !== "object") {
|
|
222
416
|
return { valid: false, error: "Data object is required" };
|
|
223
417
|
}
|
|
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
418
|
switch (verifierId) {
|
|
229
419
|
case "ownership-basic":
|
|
230
|
-
if (!data.owner || !
|
|
231
|
-
return { valid: false, error: "owner (wallet address) is required" };
|
|
420
|
+
if (!data.owner || !validateUniversalAddress(data.owner, typeof data.chain === "string" ? data.chain : void 0)) {
|
|
421
|
+
return { valid: false, error: "owner (universal wallet address) is required" };
|
|
232
422
|
}
|
|
233
423
|
if (data.content !== void 0 && data.content !== null) {
|
|
234
424
|
if (typeof data.content !== "string") {
|
|
@@ -354,17 +544,20 @@ var validateVerifierData = (verifierId, data) => {
|
|
|
354
544
|
}
|
|
355
545
|
break;
|
|
356
546
|
case "wallet-link":
|
|
357
|
-
if (!data.primaryWalletAddress || !
|
|
547
|
+
if (!data.primaryWalletAddress || !validateUniversalAddress(data.primaryWalletAddress, data.chain)) {
|
|
358
548
|
return { valid: false, error: "primaryWalletAddress is required" };
|
|
359
549
|
}
|
|
360
|
-
if (!data.secondaryWalletAddress || !
|
|
550
|
+
if (!data.secondaryWalletAddress || !validateUniversalAddress(data.secondaryWalletAddress, data.chain)) {
|
|
361
551
|
return { valid: false, error: "secondaryWalletAddress is required" };
|
|
362
552
|
}
|
|
363
553
|
if (!data.signature || typeof data.signature !== "string") {
|
|
364
554
|
return { valid: false, error: "signature is required (signed by secondary wallet)" };
|
|
365
555
|
}
|
|
366
|
-
if (typeof data.
|
|
367
|
-
return { valid: false, error: "
|
|
556
|
+
if (typeof data.chain !== "string" || !/^[a-z0-9]+:[^\s]+$/.test(data.chain)) {
|
|
557
|
+
return { valid: false, error: "chain is required (namespace:reference)" };
|
|
558
|
+
}
|
|
559
|
+
if (typeof data.signatureMethod !== "string" || !data.signatureMethod.trim()) {
|
|
560
|
+
return { valid: false, error: "signatureMethod is required" };
|
|
368
561
|
}
|
|
369
562
|
if (typeof data.signedTimestamp !== "number") {
|
|
370
563
|
return { valid: false, error: "signedTimestamp is required" };
|
|
@@ -435,7 +628,10 @@ var validateVerifierData = (verifierId, data) => {
|
|
|
435
628
|
const maxBytes = 50 * 1024;
|
|
436
629
|
const bytes = typeof TextEncoder !== "undefined" ? new TextEncoder().encode(data.content).length : String(data.content).length;
|
|
437
630
|
if (bytes > maxBytes) {
|
|
438
|
-
return {
|
|
631
|
+
return {
|
|
632
|
+
valid: false,
|
|
633
|
+
error: `content exceeds ${maxBytes} bytes limit for ai-content-moderation verifier (text)`
|
|
634
|
+
};
|
|
439
635
|
}
|
|
440
636
|
} catch {
|
|
441
637
|
}
|
|
@@ -459,7 +655,7 @@ var validateVerifierData = (verifierId, data) => {
|
|
|
459
655
|
}
|
|
460
656
|
break;
|
|
461
657
|
case "wallet-risk":
|
|
462
|
-
if (data.walletAddress && !
|
|
658
|
+
if (data.walletAddress && !validateUniversalAddress(data.walletAddress, data.chain)) {
|
|
463
659
|
return { valid: false, error: "Invalid walletAddress" };
|
|
464
660
|
}
|
|
465
661
|
break;
|
|
@@ -491,6 +687,21 @@ var NeusClient = class {
|
|
|
491
687
|
if (typeof this.config.apiKey === "string" && this.config.apiKey.trim().length > 0) {
|
|
492
688
|
this.defaultHeaders["Authorization"] = `Bearer ${this.config.apiKey.trim()}`;
|
|
493
689
|
}
|
|
690
|
+
if (typeof this.config.appId === "string" && this.config.appId.trim().length > 0) {
|
|
691
|
+
this.defaultHeaders["X-Neus-App"] = this.config.appId.trim();
|
|
692
|
+
}
|
|
693
|
+
if (typeof this.config.paymentSignature === "string" && this.config.paymentSignature.trim().length > 0) {
|
|
694
|
+
this.defaultHeaders["PAYMENT-SIGNATURE"] = this.config.paymentSignature.trim();
|
|
695
|
+
}
|
|
696
|
+
if (this.config.extraHeaders && typeof this.config.extraHeaders === "object") {
|
|
697
|
+
for (const [k, v] of Object.entries(this.config.extraHeaders)) {
|
|
698
|
+
if (!k || v === void 0 || v === null) continue;
|
|
699
|
+
const key = String(k).trim();
|
|
700
|
+
const value = String(v).trim();
|
|
701
|
+
if (!key || !value) continue;
|
|
702
|
+
this.defaultHeaders[key] = value;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
494
705
|
try {
|
|
495
706
|
if (typeof window !== "undefined" && window.location && window.location.origin) {
|
|
496
707
|
this.defaultHeaders["X-Client-Origin"] = window.location.origin;
|
|
@@ -498,87 +709,183 @@ var NeusClient = class {
|
|
|
498
709
|
} catch {
|
|
499
710
|
}
|
|
500
711
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
712
|
+
_getHubChainId() {
|
|
713
|
+
const configured = Number(this.config?.hubChainId);
|
|
714
|
+
if (Number.isFinite(configured) && configured > 0) return Math.floor(configured);
|
|
715
|
+
return NEUS_CONSTANTS.HUB_CHAIN_ID;
|
|
716
|
+
}
|
|
717
|
+
_normalizeIdentity(value) {
|
|
718
|
+
let raw = String(value || "").trim();
|
|
719
|
+
if (!raw) return "";
|
|
720
|
+
const didMatch = raw.match(/^did:pkh:([^:]+):([^:]+):(.+)$/i);
|
|
721
|
+
if (didMatch && didMatch[3]) {
|
|
722
|
+
raw = String(didMatch[3]).trim();
|
|
723
|
+
}
|
|
724
|
+
return EVM_ADDRESS_RE.test(raw) ? raw.toLowerCase() : raw;
|
|
725
|
+
}
|
|
726
|
+
_inferChainForAddress(address, explicitChain) {
|
|
727
|
+
if (typeof explicitChain === "string" && explicitChain.includes(":")) return explicitChain.trim();
|
|
728
|
+
const raw = String(address || "").trim();
|
|
729
|
+
const didMatch = raw.match(/^did:pkh:([^:]+):([^:]+):(.+)$/i);
|
|
730
|
+
if (didMatch && didMatch[1] && didMatch[2]) {
|
|
731
|
+
return `${didMatch[1]}:${didMatch[2]}`;
|
|
732
|
+
}
|
|
733
|
+
if (EVM_ADDRESS_RE.test(raw)) {
|
|
734
|
+
return `eip155:${this._getHubChainId()}`;
|
|
735
|
+
}
|
|
736
|
+
return "solana:mainnet";
|
|
737
|
+
}
|
|
738
|
+
async _resolveWalletSigner(wallet) {
|
|
739
|
+
if (!wallet) {
|
|
740
|
+
throw new ConfigurationError("No wallet provider available");
|
|
741
|
+
}
|
|
742
|
+
if (wallet.address) {
|
|
743
|
+
return { signerWalletAddress: wallet.address, provider: wallet };
|
|
744
|
+
}
|
|
745
|
+
if (wallet.publicKey && typeof wallet.publicKey.toBase58 === "function") {
|
|
746
|
+
return { signerWalletAddress: wallet.publicKey.toBase58(), provider: wallet };
|
|
747
|
+
}
|
|
748
|
+
if (typeof wallet.getAddress === "function") {
|
|
749
|
+
const signerWalletAddress = await wallet.getAddress().catch(() => null);
|
|
750
|
+
return { signerWalletAddress, provider: wallet };
|
|
751
|
+
}
|
|
752
|
+
if (wallet.selectedAddress || wallet.request) {
|
|
753
|
+
const provider = wallet;
|
|
754
|
+
if (wallet.selectedAddress) {
|
|
755
|
+
return { signerWalletAddress: wallet.selectedAddress, provider };
|
|
756
|
+
}
|
|
757
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
758
|
+
if (!accounts || accounts.length === 0) {
|
|
759
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
760
|
+
}
|
|
761
|
+
return { signerWalletAddress: accounts[0], provider };
|
|
762
|
+
}
|
|
763
|
+
throw new ConfigurationError("Invalid wallet provider");
|
|
764
|
+
}
|
|
765
|
+
_getDefaultBrowserWallet() {
|
|
766
|
+
if (typeof window === "undefined") return null;
|
|
767
|
+
return window.ethereum || window.solana || window.phantom && window.phantom.solana || null;
|
|
768
|
+
}
|
|
769
|
+
async _buildPrivateGateAuth({ address, wallet, chain, signatureMethod } = {}) {
|
|
770
|
+
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
771
|
+
const { signerWalletAddress, provider } = await this._resolveWalletSigner(providerWallet);
|
|
772
|
+
if (!signerWalletAddress || typeof signerWalletAddress !== "string") {
|
|
773
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
774
|
+
}
|
|
775
|
+
const normalizedSigner = this._normalizeIdentity(signerWalletAddress);
|
|
776
|
+
const normalizedAddress = this._normalizeIdentity(address);
|
|
777
|
+
if (!normalizedSigner || normalizedSigner !== normalizedAddress) {
|
|
778
|
+
throw new ValidationError("wallet must match address when includePrivate=true");
|
|
779
|
+
}
|
|
780
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(normalizedSigner);
|
|
781
|
+
const resolvedChain = this._inferChainForAddress(normalizedSigner, chain);
|
|
782
|
+
const resolvedSignatureMethod = typeof signatureMethod === "string" && signatureMethod.trim() ? signatureMethod.trim() : signerIsEvm ? "eip191" : "ed25519";
|
|
783
|
+
const signedTimestamp = Date.now();
|
|
784
|
+
const message = constructVerificationMessage({
|
|
785
|
+
walletAddress: signerWalletAddress,
|
|
786
|
+
signedTimestamp,
|
|
787
|
+
data: { action: "gate_check_private_proofs", walletAddress: normalizedAddress },
|
|
788
|
+
verifierIds: ["ownership-basic"],
|
|
789
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain: resolvedChain }
|
|
790
|
+
});
|
|
791
|
+
let signature;
|
|
792
|
+
try {
|
|
793
|
+
signature = await signMessage({
|
|
794
|
+
provider,
|
|
795
|
+
message,
|
|
796
|
+
walletAddress: signerWalletAddress,
|
|
797
|
+
...signerIsEvm ? {} : { chain: resolvedChain }
|
|
798
|
+
});
|
|
799
|
+
} catch (error) {
|
|
800
|
+
if (error.code === 4001) {
|
|
801
|
+
throw new ValidationError("User rejected signature request");
|
|
802
|
+
}
|
|
803
|
+
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
804
|
+
}
|
|
805
|
+
return {
|
|
806
|
+
walletAddress: signerWalletAddress,
|
|
807
|
+
signature,
|
|
808
|
+
signedTimestamp,
|
|
809
|
+
...signerIsEvm ? {} : { chain: resolvedChain, signatureMethod: resolvedSignatureMethod }
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
async createGatePrivateAuth(params = {}) {
|
|
813
|
+
const address = (params.address || "").toString();
|
|
814
|
+
if (!validateUniversalAddress(address, params.chain)) {
|
|
815
|
+
throw new ValidationError("Valid address is required");
|
|
816
|
+
}
|
|
817
|
+
return this._buildPrivateGateAuth({
|
|
818
|
+
address,
|
|
819
|
+
wallet: params.wallet,
|
|
820
|
+
chain: params.chain,
|
|
821
|
+
signatureMethod: params.signatureMethod
|
|
822
|
+
});
|
|
823
|
+
}
|
|
504
824
|
/**
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
825
|
+
* Create a verification proof.
|
|
826
|
+
*
|
|
827
|
+
* Supports two paths:
|
|
828
|
+
* - **Auto:** Supply `verifier`, `content`, and/or `data` with an optional
|
|
829
|
+
* `wallet` provider. The SDK performs signing in the client.
|
|
830
|
+
* - **Manual:** Supply pre-signed `verifierIds`, `data`, `walletAddress`,
|
|
831
|
+
* `signature`, and `signedTimestamp`.
|
|
832
|
+
*
|
|
511
833
|
* @param {Object} params - Verification parameters
|
|
834
|
+
* @param {string} [params.verifier] - Verifier ID (auto path, e.g. 'ownership-basic')
|
|
835
|
+
* @param {string} [params.content] - Content to verify (auto path)
|
|
836
|
+
* @param {Object} [params.data] - Structured verification data
|
|
837
|
+
* @param {Object} [params.wallet] - Wallet provider (auto path)
|
|
838
|
+
* @param {Object} [params.options] - Additional options
|
|
512
839
|
* @param {Array<string>} [params.verifierIds] - Array of verifier IDs (manual path)
|
|
513
|
-
* @param {Object} [params.data] - Verification data object (manual path)
|
|
514
840
|
* @param {string} [params.walletAddress] - Wallet address that signed the request (manual path)
|
|
515
841
|
* @param {string} [params.signature] - EIP-191 signature (manual path)
|
|
516
842
|
* @param {number} [params.signedTimestamp] - Unix timestamp when signature was created (manual path)
|
|
517
|
-
* @param {number} [params.chainId] -
|
|
518
|
-
* @
|
|
519
|
-
*
|
|
520
|
-
* @param {string} [params.content] - Content/description (auto path)
|
|
521
|
-
* @param {Object} [params.wallet] - Optional injected wallet/provider (auto path)
|
|
522
|
-
* @returns {Promise<Object>} Verification result with qHash
|
|
523
|
-
*
|
|
843
|
+
* @param {number} [params.chainId] - EVM signing-context hint; when omitted, resolved to the NEUS protocol primary chain for signing
|
|
844
|
+
* @returns {Promise<Object>} Verification result with proofId
|
|
845
|
+
*
|
|
524
846
|
* @example
|
|
847
|
+
* // Auto path
|
|
848
|
+
* const proof = await client.verify({
|
|
849
|
+
* verifier: 'ownership-basic',
|
|
850
|
+
* content: 'Hello World',
|
|
851
|
+
* wallet: window.ethereum
|
|
852
|
+
* });
|
|
853
|
+
*
|
|
854
|
+
* @example
|
|
855
|
+
* // Manual path
|
|
525
856
|
* const proof = await client.verify({
|
|
526
857
|
* verifierIds: ['ownership-basic'],
|
|
527
|
-
* data: {
|
|
528
|
-
* content: "My content",
|
|
529
|
-
* owner: walletAddress, // or ownerAddress for nft-ownership/token-holding
|
|
530
|
-
* reference: { type: 'other', id: 'my-unique-identifier' }
|
|
531
|
-
* },
|
|
858
|
+
* data: { content: "My content", owner: walletAddress },
|
|
532
859
|
* walletAddress: '0x...',
|
|
533
860
|
* signature: '0x...',
|
|
534
861
|
* signedTimestamp: Date.now(),
|
|
535
862
|
* options: { targetChains: [421614, 11155111] }
|
|
536
863
|
* });
|
|
537
864
|
*/
|
|
538
|
-
/**
|
|
539
|
-
* Create a verification proof
|
|
540
|
-
*
|
|
541
|
-
* @param {Object} params - Verification parameters
|
|
542
|
-
* @param {string} [params.verifier] - Verifier ID (e.g., 'ownership-basic')
|
|
543
|
-
* @param {string} [params.content] - Content to verify
|
|
544
|
-
* @param {Object} [params.data] - Structured verification data
|
|
545
|
-
* @param {Object} [params.wallet] - Wallet provider
|
|
546
|
-
* @param {Object} [params.options] - Additional options
|
|
547
|
-
* @returns {Promise<Object>} Verification result with qHash
|
|
548
|
-
*
|
|
549
|
-
* @example
|
|
550
|
-
* // Simple ownership proof
|
|
551
|
-
* const proof = await client.verify({
|
|
552
|
-
* verifier: 'ownership-basic',
|
|
553
|
-
* content: 'Hello World',
|
|
554
|
-
* wallet: window.ethereum
|
|
555
|
-
* });
|
|
556
|
-
*/
|
|
557
865
|
async verify(params) {
|
|
558
866
|
if ((!params?.signature || !params?.walletAddress) && (params?.verifier || params?.content || params?.data)) {
|
|
559
867
|
const { content, verifier = "ownership-basic", data: data2 = null, wallet = null, options: options2 = {} } = params;
|
|
560
868
|
if (verifier === "ownership-basic" && !data2 && (!content || typeof content !== "string")) {
|
|
561
869
|
throw new ValidationError("content is required and must be a string (or use data param with owner + reference)");
|
|
562
870
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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
|
-
];
|
|
871
|
+
let verifierCatalog = FALLBACK_PUBLIC_VERIFIER_CATALOG;
|
|
872
|
+
try {
|
|
873
|
+
const discovered = await this.getVerifierCatalog();
|
|
874
|
+
if (discovered && discovered.metadata && Object.keys(discovered.metadata).length > 0) {
|
|
875
|
+
verifierCatalog = discovered.metadata;
|
|
876
|
+
}
|
|
877
|
+
} catch {
|
|
878
|
+
}
|
|
879
|
+
const validVerifiers = Object.keys(verifierCatalog);
|
|
579
880
|
if (!validVerifiers.includes(verifier)) {
|
|
580
881
|
throw new ValidationError(`Invalid verifier '${verifier}'. Must be one of: ${validVerifiers.join(", ")}.`);
|
|
581
882
|
}
|
|
883
|
+
if (verifierCatalog?.[verifier]?.supportsDirectApi === false) {
|
|
884
|
+
const hostedCheckoutUrl = options2?.hostedCheckoutUrl || "https://neus.network/verify";
|
|
885
|
+
throw new ValidationError(
|
|
886
|
+
`${verifier} requires hosted interactive checkout. Use VerifyGate or redirect to ${hostedCheckoutUrl}.`
|
|
887
|
+
);
|
|
888
|
+
}
|
|
582
889
|
const requiresDataParam = [
|
|
583
890
|
"ownership-dns-txt",
|
|
584
891
|
"wallet-link",
|
|
@@ -596,8 +903,12 @@ var NeusClient = class {
|
|
|
596
903
|
}
|
|
597
904
|
let walletAddress2, provider;
|
|
598
905
|
if (wallet) {
|
|
599
|
-
walletAddress2 = wallet.address || wallet.selectedAddress;
|
|
906
|
+
walletAddress2 = wallet.address || wallet.selectedAddress || wallet.walletAddress || (typeof wallet.getAddress === "function" ? await wallet.getAddress() : null);
|
|
600
907
|
provider = wallet.provider || wallet;
|
|
908
|
+
if (!walletAddress2 && provider && typeof provider.request === "function") {
|
|
909
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
910
|
+
walletAddress2 = Array.isArray(accounts) ? accounts[0] : null;
|
|
911
|
+
}
|
|
601
912
|
} else {
|
|
602
913
|
if (typeof window === "undefined" || !window.ethereum) {
|
|
603
914
|
throw new ConfigurationError("No Web3 wallet detected. Please install MetaMask or provide wallet parameter.");
|
|
@@ -673,14 +984,18 @@ var NeusClient = class {
|
|
|
673
984
|
if (!data2?.signature) {
|
|
674
985
|
throw new ValidationError("wallet-link requires signature in data parameter (signed by secondary wallet)");
|
|
675
986
|
}
|
|
676
|
-
if (typeof data2?.
|
|
677
|
-
throw new ValidationError("wallet-link requires
|
|
987
|
+
if (typeof data2?.chain !== "string" || !/^[a-z0-9]+:[^\s]+$/.test(data2.chain)) {
|
|
988
|
+
throw new ValidationError("wallet-link requires chain (namespace:reference) in data parameter");
|
|
989
|
+
}
|
|
990
|
+
if (typeof data2?.signatureMethod !== "string" || !data2.signatureMethod.trim()) {
|
|
991
|
+
throw new ValidationError("wallet-link requires signatureMethod in data parameter");
|
|
678
992
|
}
|
|
679
993
|
verificationData = {
|
|
680
994
|
primaryWalletAddress: walletAddress2,
|
|
681
995
|
secondaryWalletAddress: data2.secondaryWalletAddress,
|
|
682
996
|
signature: data2.signature,
|
|
683
|
-
|
|
997
|
+
chain: data2.chain,
|
|
998
|
+
signatureMethod: data2.signatureMethod,
|
|
684
999
|
signedTimestamp: data2?.signedTimestamp || Date.now()
|
|
685
1000
|
};
|
|
686
1001
|
} else if (verifier === "contract-ownership") {
|
|
@@ -706,7 +1021,10 @@ var NeusClient = class {
|
|
|
706
1021
|
...data2?.agentLabel && { agentLabel: data2.agentLabel },
|
|
707
1022
|
...data2?.agentType && { agentType: data2.agentType },
|
|
708
1023
|
...data2?.description && { description: data2.description },
|
|
709
|
-
...data2?.capabilities && { capabilities: data2.capabilities }
|
|
1024
|
+
...data2?.capabilities && { capabilities: data2.capabilities },
|
|
1025
|
+
...data2?.instructions && { instructions: data2.instructions },
|
|
1026
|
+
...data2?.skills && { skills: data2.skills },
|
|
1027
|
+
...data2?.services && { services: data2.services }
|
|
710
1028
|
};
|
|
711
1029
|
} else if (verifier === "agent-delegation") {
|
|
712
1030
|
if (!data2?.agentWallet) {
|
|
@@ -719,7 +1037,11 @@ var NeusClient = class {
|
|
|
719
1037
|
...data2?.scope && { scope: data2.scope },
|
|
720
1038
|
...data2?.permissions && { permissions: data2.permissions },
|
|
721
1039
|
...data2?.maxSpend && { maxSpend: data2.maxSpend },
|
|
722
|
-
...data2?.
|
|
1040
|
+
...data2?.allowedPaymentTypes && { allowedPaymentTypes: data2.allowedPaymentTypes },
|
|
1041
|
+
...data2?.receiptDisclosure && { receiptDisclosure: data2.receiptDisclosure },
|
|
1042
|
+
...data2?.expiresAt && { expiresAt: data2.expiresAt },
|
|
1043
|
+
...data2?.instructions && { instructions: data2.instructions },
|
|
1044
|
+
...data2?.skills && { skills: data2.skills }
|
|
723
1045
|
};
|
|
724
1046
|
} else if (verifier === "ai-content-moderation") {
|
|
725
1047
|
if (!data2?.content) {
|
|
@@ -769,48 +1091,41 @@ var NeusClient = class {
|
|
|
769
1091
|
signedTimestamp: signedTimestamp2,
|
|
770
1092
|
data: verificationData,
|
|
771
1093
|
verifierIds: verifierIds2,
|
|
772
|
-
chainId:
|
|
1094
|
+
chainId: this._getHubChainId()
|
|
773
1095
|
// Protocol-managed chain
|
|
774
1096
|
});
|
|
775
1097
|
let signature2;
|
|
776
1098
|
try {
|
|
777
|
-
const
|
|
1099
|
+
const toHexUtf82 = (s) => {
|
|
778
1100
|
try {
|
|
779
1101
|
const enc = new TextEncoder();
|
|
780
1102
|
const bytes = enc.encode(s);
|
|
781
1103
|
let hex = "0x";
|
|
782
|
-
for (let i = 0; i < bytes.length; i++)
|
|
783
|
-
hex += bytes[i].toString(16).padStart(2, "0");
|
|
1104
|
+
for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
|
|
784
1105
|
return hex;
|
|
785
1106
|
} catch {
|
|
786
1107
|
let hex = "0x";
|
|
787
|
-
for (let i = 0; i < s.length; i++)
|
|
788
|
-
hex += s.charCodeAt(i).toString(16).padStart(2, "0");
|
|
1108
|
+
for (let i = 0; i < s.length; i++) hex += s.charCodeAt(i).toString(16).padStart(2, "0");
|
|
789
1109
|
return hex;
|
|
790
1110
|
}
|
|
791
1111
|
};
|
|
792
1112
|
const isFarcasterWallet = (() => {
|
|
793
|
-
if (typeof window === "undefined")
|
|
794
|
-
return false;
|
|
1113
|
+
if (typeof window === "undefined") return false;
|
|
795
1114
|
try {
|
|
796
1115
|
const w = window;
|
|
797
1116
|
const fc = w.farcaster;
|
|
798
|
-
if (!fc || !fc.context)
|
|
799
|
-
return false;
|
|
1117
|
+
if (!fc || !fc.context) return false;
|
|
800
1118
|
const fcProvider = fc.provider || fc.walletProvider || fc.context && fc.context.walletProvider;
|
|
801
|
-
if (fcProvider === provider)
|
|
802
|
-
|
|
803
|
-
if (w.
|
|
804
|
-
return true;
|
|
805
|
-
if (w.ethereum === provider && fc && fc.context)
|
|
806
|
-
return true;
|
|
1119
|
+
if (fcProvider === provider) return true;
|
|
1120
|
+
if (w.mini && w.mini.wallet === provider && fc && fc.context) return true;
|
|
1121
|
+
if (w.ethereum === provider && fc && fc.context) return true;
|
|
807
1122
|
} catch {
|
|
808
1123
|
}
|
|
809
1124
|
return false;
|
|
810
1125
|
})();
|
|
811
1126
|
if (isFarcasterWallet) {
|
|
812
1127
|
try {
|
|
813
|
-
const hexMsg =
|
|
1128
|
+
const hexMsg = toHexUtf82(message);
|
|
814
1129
|
signature2 = await provider.request({ method: "personal_sign", params: [hexMsg, walletAddress2] });
|
|
815
1130
|
} catch (e) {
|
|
816
1131
|
}
|
|
@@ -822,7 +1137,8 @@ var NeusClient = class {
|
|
|
822
1137
|
const msg = String(e && (e.message || e.reason) || e || "").toLowerCase();
|
|
823
1138
|
const errCode = e && (e.code || e.error && e.error.code) || null;
|
|
824
1139
|
const needsHex = /byte|bytes|invalid byte sequence|encoding|non-hex/i.test(msg);
|
|
825
|
-
const
|
|
1140
|
+
const unsupportedRe = /method.*not.*supported|unsupported|not implemented|method not found|unknown method|does not support/i;
|
|
1141
|
+
const methodUnsupported = unsupportedRe.test(msg) || errCode === -32601 || errCode === 4200 || msg.includes("personal_sign") && msg.includes("not") || msg.includes("request method") && msg.includes("not supported");
|
|
826
1142
|
if (methodUnsupported) {
|
|
827
1143
|
this._log("personal_sign not supported; attempting eth_sign fallback");
|
|
828
1144
|
try {
|
|
@@ -831,35 +1147,30 @@ var NeusClient = class {
|
|
|
831
1147
|
const prefix = `Ethereum Signed Message:
|
|
832
1148
|
${bytes.length}`;
|
|
833
1149
|
const full = new Uint8Array(prefix.length + bytes.length);
|
|
834
|
-
for (let i = 0; i < prefix.length; i++)
|
|
835
|
-
full[i] = prefix.charCodeAt(i);
|
|
1150
|
+
for (let i = 0; i < prefix.length; i++) full[i] = prefix.charCodeAt(i);
|
|
836
1151
|
full.set(bytes, prefix.length);
|
|
837
1152
|
let payloadHex = "0x";
|
|
838
|
-
for (let i = 0; i < full.length; i++)
|
|
839
|
-
payloadHex += full[i].toString(16).padStart(2, "0");
|
|
1153
|
+
for (let i = 0; i < full.length; i++) payloadHex += full[i].toString(16).padStart(2, "0");
|
|
840
1154
|
try {
|
|
841
|
-
if (typeof window !== "undefined")
|
|
842
|
-
window.__NEUS_ALLOW_ETH_SIGN__ = true;
|
|
1155
|
+
if (typeof window !== "undefined") window.__NEUS_ALLOW_ETH_SIGN__ = true;
|
|
843
1156
|
} catch {
|
|
844
1157
|
}
|
|
845
1158
|
signature2 = await provider.request({ method: "eth_sign", params: [walletAddress2, payloadHex], neusAllowEthSign: true });
|
|
846
1159
|
try {
|
|
847
|
-
if (typeof window !== "undefined")
|
|
848
|
-
delete window.__NEUS_ALLOW_ETH_SIGN__;
|
|
1160
|
+
if (typeof window !== "undefined") delete window.__NEUS_ALLOW_ETH_SIGN__;
|
|
849
1161
|
} catch {
|
|
850
1162
|
}
|
|
851
1163
|
} catch (fallbackErr) {
|
|
852
1164
|
this._log("eth_sign fallback failed", { message: fallbackErr?.message || String(fallbackErr) });
|
|
853
1165
|
try {
|
|
854
|
-
if (typeof window !== "undefined")
|
|
855
|
-
delete window.__NEUS_ALLOW_ETH_SIGN__;
|
|
1166
|
+
if (typeof window !== "undefined") delete window.__NEUS_ALLOW_ETH_SIGN__;
|
|
856
1167
|
} catch {
|
|
857
1168
|
}
|
|
858
1169
|
throw e;
|
|
859
1170
|
}
|
|
860
1171
|
} else if (needsHex) {
|
|
861
1172
|
this._log("Retrying personal_sign with hex-encoded message");
|
|
862
|
-
const hexMsg =
|
|
1173
|
+
const hexMsg = toHexUtf82(message);
|
|
863
1174
|
signature2 = await provider.request({ method: "personal_sign", params: [hexMsg, walletAddress2] });
|
|
864
1175
|
} else {
|
|
865
1176
|
throw e;
|
|
@@ -894,8 +1205,7 @@ ${bytes.length}`;
|
|
|
894
1205
|
} = params;
|
|
895
1206
|
const resolvedChainId = chainId || (chain ? null : NEUS_CONSTANTS.HUB_CHAIN_ID);
|
|
896
1207
|
const normalizeVerifierId = (id) => {
|
|
897
|
-
if (typeof id !== "string")
|
|
898
|
-
return id;
|
|
1208
|
+
if (typeof id !== "string") return id;
|
|
899
1209
|
const match = id.match(/^(.*)@\d+$/);
|
|
900
1210
|
return match ? match[1] : id;
|
|
901
1211
|
};
|
|
@@ -930,10 +1240,9 @@ ${bytes.length}`;
|
|
|
930
1240
|
// Privacy and storage options (defaults)
|
|
931
1241
|
privacyLevel: options?.privacyLevel || "private",
|
|
932
1242
|
publicDisplay: options?.publicDisplay || false,
|
|
933
|
-
storeOriginalContent: options?.storeOriginalContent
|
|
1243
|
+
storeOriginalContent: typeof options?.storeOriginalContent === "boolean" ? options.storeOriginalContent : true
|
|
934
1244
|
};
|
|
935
|
-
if (typeof options?.enableIpfs === "boolean")
|
|
936
|
-
optionsPayload.enableIpfs = options.enableIpfs;
|
|
1245
|
+
if (typeof options?.enableIpfs === "boolean") optionsPayload.enableIpfs = options.enableIpfs;
|
|
937
1246
|
const requestData = {
|
|
938
1247
|
verifierIds: normalizedVerifierIds,
|
|
939
1248
|
data,
|
|
@@ -951,96 +1260,94 @@ ${bytes.length}`;
|
|
|
951
1260
|
}
|
|
952
1261
|
return this._formatResponse(response);
|
|
953
1262
|
}
|
|
954
|
-
// ============================================================================
|
|
955
|
-
// STATUS AND UTILITY METHODS
|
|
956
|
-
// ============================================================================
|
|
957
1263
|
/**
|
|
958
|
-
* Get
|
|
1264
|
+
* Get proof record by proof receipt id.
|
|
959
1265
|
*
|
|
960
|
-
* @param {string}
|
|
961
|
-
* @returns {Promise<Object>}
|
|
1266
|
+
* @param {string} proofId - Proof receipt ID (0x + 64 hex).
|
|
1267
|
+
* @returns {Promise<Object>} Proof record and verification state
|
|
962
1268
|
*
|
|
963
1269
|
* @example
|
|
964
|
-
* const result = await client.
|
|
1270
|
+
* const result = await client.getProof('0x...');
|
|
965
1271
|
* console.log('Status:', result.status);
|
|
966
1272
|
*/
|
|
967
|
-
async
|
|
968
|
-
if (!
|
|
969
|
-
throw new ValidationError("
|
|
1273
|
+
async getProof(proofId) {
|
|
1274
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1275
|
+
throw new ValidationError("proofId is required");
|
|
970
1276
|
}
|
|
971
|
-
const response = await this._makeRequest("GET", `/api/v1/
|
|
1277
|
+
const response = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`);
|
|
972
1278
|
if (!response.success) {
|
|
973
|
-
throw new ApiError(`Failed to get
|
|
1279
|
+
throw new ApiError(`Failed to get proof: ${response.error?.message || "Unknown error"}`, response.error);
|
|
974
1280
|
}
|
|
975
1281
|
return this._formatResponse(response);
|
|
976
1282
|
}
|
|
977
1283
|
/**
|
|
978
|
-
* Get private proof
|
|
1284
|
+
* Get private proof record with wallet signature
|
|
979
1285
|
*
|
|
980
|
-
* @param {string}
|
|
1286
|
+
* @param {string} proofId - Proof receipt ID.
|
|
981
1287
|
* @param {Object} wallet - Wallet provider (window.ethereum or ethers Wallet)
|
|
982
|
-
* @returns {Promise<Object>} Private
|
|
1288
|
+
* @returns {Promise<Object>} Private proof record and verification state
|
|
983
1289
|
*
|
|
984
1290
|
* @example
|
|
985
|
-
*
|
|
986
|
-
* const privateData = await client.getPrivateStatus(qHash, window.ethereum);
|
|
1291
|
+
* const privateData = await client.getPrivateProof(proofId, window.ethereum);
|
|
987
1292
|
*/
|
|
988
|
-
async
|
|
989
|
-
if (!
|
|
990
|
-
throw new ValidationError("
|
|
1293
|
+
async getPrivateProof(proofId, wallet = null) {
|
|
1294
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1295
|
+
throw new ValidationError("proofId is required");
|
|
991
1296
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1297
|
+
const isPreSignedAuth = wallet && typeof wallet === "object" && typeof wallet.walletAddress === "string" && typeof wallet.signature === "string" && typeof wallet.signedTimestamp === "number";
|
|
1298
|
+
if (isPreSignedAuth) {
|
|
1299
|
+
const auth = wallet;
|
|
1300
|
+
const headers = {
|
|
1301
|
+
"x-wallet-address": String(auth.walletAddress),
|
|
1302
|
+
"x-signature": String(auth.signature),
|
|
1303
|
+
"x-signed-timestamp": String(auth.signedTimestamp),
|
|
1304
|
+
...typeof auth.chain === "string" && auth.chain.trim() ? { "x-chain": auth.chain.trim() } : {},
|
|
1305
|
+
...typeof auth.signatureMethod === "string" && auth.signatureMethod.trim() ? { "x-signature-method": auth.signatureMethod.trim() } : {}
|
|
1306
|
+
};
|
|
1307
|
+
const response2 = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`, null, headers);
|
|
1308
|
+
if (!response2.success) {
|
|
1309
|
+
throw new ApiError(
|
|
1310
|
+
`Failed to access private proof: ${response2.error?.message || "Unauthorized"}`,
|
|
1311
|
+
response2.error
|
|
1312
|
+
);
|
|
995
1313
|
}
|
|
996
|
-
|
|
1314
|
+
return this._formatResponse(response2);
|
|
997
1315
|
}
|
|
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");
|
|
1316
|
+
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
1317
|
+
const { signerWalletAddress: walletAddress, provider } = await this._resolveWalletSigner(providerWallet);
|
|
1318
|
+
if (!walletAddress || typeof walletAddress !== "string") {
|
|
1319
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
1015
1320
|
}
|
|
1321
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(this._normalizeIdentity(walletAddress));
|
|
1322
|
+
const chain = this._inferChainForAddress(walletAddress);
|
|
1323
|
+
const signatureMethod = signerIsEvm ? "eip191" : "ed25519";
|
|
1016
1324
|
const signedTimestamp = Date.now();
|
|
1017
1325
|
const message = constructVerificationMessage({
|
|
1018
1326
|
walletAddress,
|
|
1019
1327
|
signedTimestamp,
|
|
1020
|
-
data: { action: "access_private_proof", qHash },
|
|
1328
|
+
data: { action: "access_private_proof", qHash: proofId },
|
|
1021
1329
|
verifierIds: ["ownership-basic"],
|
|
1022
|
-
chainId:
|
|
1330
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
1023
1331
|
});
|
|
1024
1332
|
let signature;
|
|
1025
1333
|
try {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
});
|
|
1033
|
-
}
|
|
1334
|
+
signature = await signMessage({
|
|
1335
|
+
provider,
|
|
1336
|
+
message,
|
|
1337
|
+
walletAddress,
|
|
1338
|
+
...signerIsEvm ? {} : { chain }
|
|
1339
|
+
});
|
|
1034
1340
|
} catch (error) {
|
|
1035
1341
|
if (error.code === 4001) {
|
|
1036
1342
|
throw new ValidationError("User rejected signature request");
|
|
1037
1343
|
}
|
|
1038
1344
|
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
1039
1345
|
}
|
|
1040
|
-
const response = await this._makeRequest("GET", `/api/v1/
|
|
1346
|
+
const response = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`, null, {
|
|
1041
1347
|
"x-wallet-address": walletAddress,
|
|
1042
1348
|
"x-signature": signature,
|
|
1043
|
-
"x-signed-timestamp": signedTimestamp.toString()
|
|
1349
|
+
"x-signed-timestamp": signedTimestamp.toString(),
|
|
1350
|
+
...signerIsEvm ? {} : { "x-chain": chain, "x-signature-method": signatureMethod }
|
|
1044
1351
|
});
|
|
1045
1352
|
if (!response.success) {
|
|
1046
1353
|
throw new ApiError(
|
|
@@ -1069,27 +1376,39 @@ ${bytes.length}`;
|
|
|
1069
1376
|
* @returns {Promise<string[]>} Array of verifier IDs
|
|
1070
1377
|
*/
|
|
1071
1378
|
async getVerifiers() {
|
|
1379
|
+
const catalog = await this.getVerifierCatalog();
|
|
1380
|
+
return Array.isArray(catalog?.data) ? catalog.data : [];
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Get the public verifier catalog with per-verifier capabilities.
|
|
1384
|
+
* @returns {Promise<{data: string[], metadata: Record<string, { supportsDirectApi?: boolean }>, meta?: object}>}
|
|
1385
|
+
*/
|
|
1386
|
+
async getVerifierCatalog() {
|
|
1072
1387
|
const response = await this._makeRequest("GET", "/api/v1/verification/verifiers");
|
|
1073
1388
|
if (!response.success) {
|
|
1074
1389
|
throw new ApiError(`Failed to get verifiers: ${response.error?.message || "Unknown error"}`, response.error);
|
|
1075
1390
|
}
|
|
1076
|
-
return
|
|
1391
|
+
return {
|
|
1392
|
+
data: Array.isArray(response.data) ? response.data : [],
|
|
1393
|
+
metadata: response.metadata && typeof response.metadata === "object" && !Array.isArray(response.metadata) ? response.metadata : {},
|
|
1394
|
+
meta: response.meta && typeof response.meta === "object" && !Array.isArray(response.meta) ? response.meta : {}
|
|
1395
|
+
};
|
|
1077
1396
|
}
|
|
1078
1397
|
/**
|
|
1079
1398
|
* POLL PROOF STATUS - Wait for verification completion
|
|
1080
|
-
*
|
|
1399
|
+
*
|
|
1081
1400
|
* Polls the verification status until it reaches a terminal state (completed or failed).
|
|
1082
1401
|
* Useful for providing real-time feedback to users during verification.
|
|
1083
|
-
*
|
|
1084
|
-
* @param {string}
|
|
1402
|
+
*
|
|
1403
|
+
* @param {string} proofId - Proof ID to poll.
|
|
1085
1404
|
* @param {Object} [options] - Polling options
|
|
1086
1405
|
* @param {number} [options.interval=5000] - Polling interval in ms
|
|
1087
1406
|
* @param {number} [options.timeout=120000] - Total timeout in ms
|
|
1088
1407
|
* @param {Function} [options.onProgress] - Progress callback function
|
|
1089
1408
|
* @returns {Promise<Object>} Final verification status
|
|
1090
|
-
*
|
|
1409
|
+
*
|
|
1091
1410
|
* @example
|
|
1092
|
-
* const finalStatus = await client.pollProofStatus(
|
|
1411
|
+
* const finalStatus = await client.pollProofStatus(proofId, {
|
|
1093
1412
|
* interval: 3000,
|
|
1094
1413
|
* timeout: 60000,
|
|
1095
1414
|
* onProgress: (status) => {
|
|
@@ -1100,20 +1419,20 @@ ${bytes.length}`;
|
|
|
1100
1419
|
* }
|
|
1101
1420
|
* });
|
|
1102
1421
|
*/
|
|
1103
|
-
async pollProofStatus(
|
|
1422
|
+
async pollProofStatus(proofId, options = {}) {
|
|
1104
1423
|
const {
|
|
1105
1424
|
interval = 5e3,
|
|
1106
1425
|
timeout = 12e4,
|
|
1107
1426
|
onProgress
|
|
1108
1427
|
} = options;
|
|
1109
|
-
if (!
|
|
1110
|
-
throw new ValidationError("
|
|
1428
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1429
|
+
throw new ValidationError("proofId is required");
|
|
1111
1430
|
}
|
|
1112
1431
|
const startTime = Date.now();
|
|
1113
1432
|
let consecutiveRateLimits = 0;
|
|
1114
1433
|
while (Date.now() - startTime < timeout) {
|
|
1115
1434
|
try {
|
|
1116
|
-
const status = await this.
|
|
1435
|
+
const status = await this.getProof(proofId);
|
|
1117
1436
|
consecutiveRateLimits = 0;
|
|
1118
1437
|
if (onProgress && typeof onProgress === "function") {
|
|
1119
1438
|
onProgress(status.data || status);
|
|
@@ -1146,7 +1465,7 @@ ${bytes.length}`;
|
|
|
1146
1465
|
}
|
|
1147
1466
|
/**
|
|
1148
1467
|
* DETECT CHAIN ID - Get current wallet chain
|
|
1149
|
-
*
|
|
1468
|
+
*
|
|
1150
1469
|
* @returns {Promise<number>} Current chain ID
|
|
1151
1470
|
*/
|
|
1152
1471
|
async detectChainId() {
|
|
@@ -1161,70 +1480,49 @@ ${bytes.length}`;
|
|
|
1161
1480
|
}
|
|
1162
1481
|
}
|
|
1163
1482
|
/** Revoke your own proof (owner-signed) */
|
|
1164
|
-
async revokeOwnProof(
|
|
1165
|
-
if (!
|
|
1166
|
-
throw new ValidationError("
|
|
1483
|
+
async revokeOwnProof(proofId, wallet) {
|
|
1484
|
+
if (!proofId || typeof proofId !== "string") {
|
|
1485
|
+
throw new ValidationError("proofId is required");
|
|
1486
|
+
}
|
|
1487
|
+
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
1488
|
+
const { signerWalletAddress: address, provider } = await this._resolveWalletSigner(providerWallet);
|
|
1489
|
+
if (!address || typeof address !== "string") {
|
|
1490
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
1167
1491
|
}
|
|
1168
|
-
const
|
|
1492
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(this._normalizeIdentity(address));
|
|
1493
|
+
const chain = this._inferChainForAddress(address);
|
|
1494
|
+
const signatureMethod = signerIsEvm ? "eip191" : "ed25519";
|
|
1169
1495
|
const signedTimestamp = Date.now();
|
|
1170
|
-
const hubChainId = NEUS_CONSTANTS.HUB_CHAIN_ID;
|
|
1171
1496
|
const message = constructVerificationMessage({
|
|
1172
1497
|
walletAddress: address,
|
|
1173
1498
|
signedTimestamp,
|
|
1174
|
-
data: { action: "revoke_proof", qHash },
|
|
1499
|
+
data: { action: "revoke_proof", qHash: proofId },
|
|
1175
1500
|
verifierIds: ["ownership-basic"],
|
|
1176
|
-
chainId:
|
|
1501
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
1177
1502
|
});
|
|
1178
1503
|
let signature;
|
|
1179
1504
|
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
|
-
}
|
|
1505
|
+
signature = await signMessage({
|
|
1506
|
+
provider,
|
|
1507
|
+
message,
|
|
1508
|
+
walletAddress: address,
|
|
1509
|
+
...signerIsEvm ? {} : { chain }
|
|
1510
|
+
});
|
|
1217
1511
|
} catch (error) {
|
|
1218
1512
|
if (error.code === 4001) {
|
|
1219
1513
|
throw new ValidationError("User rejected revocation signature");
|
|
1220
1514
|
}
|
|
1221
1515
|
throw new ValidationError(`Failed to sign revocation: ${error.message}`);
|
|
1222
1516
|
}
|
|
1223
|
-
const res = await fetch(`${this.config.apiUrl}/api/v1/proofs
|
|
1517
|
+
const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/revoke-self/${proofId}`, {
|
|
1224
1518
|
method: "POST",
|
|
1225
|
-
// SECURITY: Do not put proof signatures into Authorization headers.
|
|
1226
1519
|
headers: { "Content-Type": "application/json" },
|
|
1227
|
-
body: JSON.stringify({
|
|
1520
|
+
body: JSON.stringify({
|
|
1521
|
+
walletAddress: address,
|
|
1522
|
+
signature,
|
|
1523
|
+
signedTimestamp,
|
|
1524
|
+
...signerIsEvm ? {} : { chain, signatureMethod }
|
|
1525
|
+
})
|
|
1228
1526
|
});
|
|
1229
1527
|
const json = await res.json();
|
|
1230
1528
|
if (!json.success) {
|
|
@@ -1232,18 +1530,16 @@ ${bytes.length}`;
|
|
|
1232
1530
|
}
|
|
1233
1531
|
return true;
|
|
1234
1532
|
}
|
|
1235
|
-
// ============================================================================
|
|
1236
|
-
// PROOFS & GATING METHODS
|
|
1237
|
-
// ============================================================================
|
|
1238
1533
|
/**
|
|
1239
1534
|
* GET PROOFS BY WALLET - Fetch proofs for a wallet address
|
|
1240
|
-
*
|
|
1241
|
-
* @param {string} walletAddress - Wallet
|
|
1535
|
+
*
|
|
1536
|
+
* @param {string} walletAddress - Wallet identity (EVM/Solana/DID)
|
|
1242
1537
|
* @param {Object} [options] - Filter options
|
|
1243
1538
|
* @param {number} [options.limit] - Max results (default: 50; higher limits require owner access)
|
|
1244
1539
|
* @param {number} [options.offset] - Pagination offset (default: 0)
|
|
1540
|
+
* @param {string} [options.qHash] - Filter to single proof by qHash
|
|
1245
1541
|
* @returns {Promise<Object>} Proofs result
|
|
1246
|
-
*
|
|
1542
|
+
*
|
|
1247
1543
|
* @example
|
|
1248
1544
|
* const result = await client.getProofsByWallet('0x...', {
|
|
1249
1545
|
* limit: 50,
|
|
@@ -1257,14 +1553,13 @@ ${bytes.length}`;
|
|
|
1257
1553
|
const id = walletAddress.trim();
|
|
1258
1554
|
const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
|
|
1259
1555
|
const qs = [];
|
|
1260
|
-
if (options.limit)
|
|
1261
|
-
|
|
1262
|
-
if (options.
|
|
1263
|
-
qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
|
|
1556
|
+
if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
|
|
1557
|
+
if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
|
|
1558
|
+
if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
|
|
1264
1559
|
const query = qs.length ? `?${qs.join("&")}` : "";
|
|
1265
1560
|
const response = await this._makeRequest(
|
|
1266
1561
|
"GET",
|
|
1267
|
-
`/api/v1/proofs/
|
|
1562
|
+
`/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`
|
|
1268
1563
|
);
|
|
1269
1564
|
if (!response.success) {
|
|
1270
1565
|
throw new ApiError(`Failed to get proofs: ${response.error?.message || "Unknown error"}`, response.error);
|
|
@@ -1283,10 +1578,11 @@ ${bytes.length}`;
|
|
|
1283
1578
|
*
|
|
1284
1579
|
* Signs an owner-access intent and requests private proofs via signature headers.
|
|
1285
1580
|
*
|
|
1286
|
-
* @param {string} walletAddress - Wallet
|
|
1581
|
+
* @param {string} walletAddress - Wallet identity (EVM/Solana/DID)
|
|
1287
1582
|
* @param {Object} [options]
|
|
1288
1583
|
* @param {number} [options.limit] - Max results (server enforces caps)
|
|
1289
1584
|
* @param {number} [options.offset] - Pagination offset
|
|
1585
|
+
* @param {string} [options.qHash] - Filter to single proof by qHash
|
|
1290
1586
|
* @param {Object} [wallet] - Optional injected wallet/provider (MetaMask/ethers Wallet)
|
|
1291
1587
|
*/
|
|
1292
1588
|
async getPrivateProofsByWallet(walletAddress, options = {}, wallet = null) {
|
|
@@ -1295,48 +1591,41 @@ ${bytes.length}`;
|
|
|
1295
1591
|
}
|
|
1296
1592
|
const id = walletAddress.trim();
|
|
1297
1593
|
const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
|
|
1594
|
+
const requestedIdentity = this._normalizeIdentity(id);
|
|
1298
1595
|
if (!wallet) {
|
|
1299
|
-
|
|
1596
|
+
const defaultWallet = this._getDefaultBrowserWallet();
|
|
1597
|
+
if (!defaultWallet) {
|
|
1300
1598
|
throw new ConfigurationError("No wallet provider available");
|
|
1301
1599
|
}
|
|
1302
|
-
wallet =
|
|
1600
|
+
wallet = defaultWallet;
|
|
1303
1601
|
}
|
|
1304
|
-
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
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");
|
|
1602
|
+
const { signerWalletAddress, provider } = await this._resolveWalletSigner(wallet);
|
|
1603
|
+
if (!signerWalletAddress || typeof signerWalletAddress !== "string") {
|
|
1604
|
+
throw new ConfigurationError("No wallet accounts available");
|
|
1605
|
+
}
|
|
1606
|
+
const normalizedSigner = this._normalizeIdentity(signerWalletAddress);
|
|
1607
|
+
if (!normalizedSigner || normalizedSigner !== requestedIdentity) {
|
|
1608
|
+
throw new ValidationError("wallet must match walletAddress for private proof access");
|
|
1321
1609
|
}
|
|
1610
|
+
const signerIsEvm = EVM_ADDRESS_RE.test(normalizedSigner);
|
|
1611
|
+
const chain = this._inferChainForAddress(normalizedSigner, options?.chain);
|
|
1612
|
+
const signatureMethod = typeof options?.signatureMethod === "string" && options.signatureMethod.trim() ? options.signatureMethod.trim() : signerIsEvm ? "eip191" : "ed25519";
|
|
1322
1613
|
const signedTimestamp = Date.now();
|
|
1323
1614
|
const message = constructVerificationMessage({
|
|
1324
1615
|
walletAddress: signerWalletAddress,
|
|
1325
1616
|
signedTimestamp,
|
|
1326
|
-
data: { action: "access_private_proofs_by_wallet", walletAddress:
|
|
1617
|
+
data: { action: "access_private_proofs_by_wallet", walletAddress: normalizedSigner },
|
|
1327
1618
|
verifierIds: ["ownership-basic"],
|
|
1328
|
-
chainId:
|
|
1619
|
+
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
1329
1620
|
});
|
|
1330
1621
|
let signature;
|
|
1331
1622
|
try {
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
});
|
|
1339
|
-
}
|
|
1623
|
+
signature = await signMessage({
|
|
1624
|
+
provider,
|
|
1625
|
+
message,
|
|
1626
|
+
walletAddress: signerWalletAddress,
|
|
1627
|
+
...signerIsEvm ? {} : { chain }
|
|
1628
|
+
});
|
|
1340
1629
|
} catch (error) {
|
|
1341
1630
|
if (error.code === 4001) {
|
|
1342
1631
|
throw new ValidationError("User rejected signature request");
|
|
@@ -1344,15 +1633,15 @@ ${bytes.length}`;
|
|
|
1344
1633
|
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
1345
1634
|
}
|
|
1346
1635
|
const qs = [];
|
|
1347
|
-
if (options.limit)
|
|
1348
|
-
|
|
1349
|
-
if (options.
|
|
1350
|
-
qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
|
|
1636
|
+
if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
|
|
1637
|
+
if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
|
|
1638
|
+
if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
|
|
1351
1639
|
const query = qs.length ? `?${qs.join("&")}` : "";
|
|
1352
|
-
const response = await this._makeRequest("GET", `/api/v1/proofs/
|
|
1640
|
+
const response = await this._makeRequest("GET", `/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`, null, {
|
|
1353
1641
|
"x-wallet-address": signerWalletAddress,
|
|
1354
1642
|
"x-signature": signature,
|
|
1355
|
-
"x-signed-timestamp": signedTimestamp.toString()
|
|
1643
|
+
"x-signed-timestamp": signedTimestamp.toString(),
|
|
1644
|
+
...signerIsEvm ? {} : { "x-chain": chain, "x-signature-method": signatureMethod }
|
|
1356
1645
|
});
|
|
1357
1646
|
if (!response.success) {
|
|
1358
1647
|
throw new ApiError(`Failed to get proofs: ${response.error?.message || "Unauthorized"}`, response.error);
|
|
@@ -1367,51 +1656,52 @@ ${bytes.length}`;
|
|
|
1367
1656
|
};
|
|
1368
1657
|
}
|
|
1369
1658
|
/**
|
|
1370
|
-
*
|
|
1659
|
+
* Gate check (HTTP API) — minimal eligibility response.
|
|
1371
1660
|
*
|
|
1372
|
-
* Calls the
|
|
1373
|
-
*
|
|
1661
|
+
* Calls the gate endpoint and returns a **minimal** yes/no response.
|
|
1662
|
+
* By default this checks **public + unlisted** proofs.
|
|
1374
1663
|
*
|
|
1375
|
-
*
|
|
1376
|
-
*
|
|
1664
|
+
* When `includePrivate=true`, this can perform owner-signed private checks
|
|
1665
|
+
* (no full proof payloads returned) by providing a wallet/provider.
|
|
1666
|
+
*
|
|
1667
|
+
* Prefer this over `checkGate()` when you need the smallest, most stable
|
|
1668
|
+
* response shape and do not need full proof payloads.
|
|
1377
1669
|
*
|
|
1378
1670
|
* @param {Object} params - Gate check query params
|
|
1379
|
-
* @param {string} params.address - Wallet
|
|
1671
|
+
* @param {string} params.address - Wallet identity to check (EVM/Solana/DID)
|
|
1380
1672
|
* @param {Array<string>|string} [params.verifierIds] - Verifier IDs to match (array or comma-separated)
|
|
1381
1673
|
* @param {boolean} [params.requireAll] - Require all verifierIds on a single proof
|
|
1382
1674
|
* @param {number} [params.minCount] - Minimum number of matching proofs
|
|
1383
1675
|
* @param {number} [params.sinceDays] - Optional time window in days
|
|
1384
1676
|
* @param {number} [params.since] - Optional unix timestamp in ms (lower bound)
|
|
1385
1677
|
* @param {number} [params.limit] - Max rows to scan (server may clamp)
|
|
1678
|
+
* @param {boolean} [params.includePrivate] - Include private proofs for owner-authenticated requests
|
|
1679
|
+
* @param {boolean} [params.includeQHashes] - Include matched qHashes in response (minimal IDs only)
|
|
1680
|
+
* @param {Object} [params.wallet] - Optional wallet/provider used to sign includePrivate owner checks
|
|
1386
1681
|
* @returns {Promise<Object>} API response ({ success, data })
|
|
1387
1682
|
*/
|
|
1388
1683
|
async gateCheck(params = {}) {
|
|
1389
1684
|
const address = (params.address || "").toString();
|
|
1390
|
-
if (!address
|
|
1685
|
+
if (!validateUniversalAddress(address, params.chain)) {
|
|
1391
1686
|
throw new ValidationError("Valid address is required");
|
|
1392
1687
|
}
|
|
1393
1688
|
const qs = new URLSearchParams();
|
|
1394
1689
|
qs.set("address", address);
|
|
1395
1690
|
const setIfPresent = (key, value) => {
|
|
1396
|
-
if (value === void 0 || value === null)
|
|
1397
|
-
return;
|
|
1691
|
+
if (value === void 0 || value === null) return;
|
|
1398
1692
|
const str = typeof value === "string" ? value : String(value);
|
|
1399
|
-
if (str.length === 0)
|
|
1400
|
-
return;
|
|
1693
|
+
if (str.length === 0) return;
|
|
1401
1694
|
qs.set(key, str);
|
|
1402
1695
|
};
|
|
1403
1696
|
const setBoolIfPresent = (key, value) => {
|
|
1404
|
-
if (value === void 0 || value === null)
|
|
1405
|
-
return;
|
|
1697
|
+
if (value === void 0 || value === null) return;
|
|
1406
1698
|
qs.set(key, value ? "true" : "false");
|
|
1407
1699
|
};
|
|
1408
1700
|
const setCsvIfPresent = (key, value) => {
|
|
1409
|
-
if (value === void 0 || value === null)
|
|
1410
|
-
return;
|
|
1701
|
+
if (value === void 0 || value === null) return;
|
|
1411
1702
|
if (Array.isArray(value)) {
|
|
1412
1703
|
const items = value.map((v) => String(v).trim()).filter(Boolean);
|
|
1413
|
-
if (items.length)
|
|
1414
|
-
qs.set(key, items.join(","));
|
|
1704
|
+
if (items.length) qs.set(key, items.join(","));
|
|
1415
1705
|
return;
|
|
1416
1706
|
}
|
|
1417
1707
|
setIfPresent(key, value);
|
|
@@ -1422,6 +1712,8 @@ ${bytes.length}`;
|
|
|
1422
1712
|
setIfPresent("sinceDays", params.sinceDays);
|
|
1423
1713
|
setIfPresent("since", params.since);
|
|
1424
1714
|
setIfPresent("limit", params.limit);
|
|
1715
|
+
setBoolIfPresent("includePrivate", params.includePrivate);
|
|
1716
|
+
setBoolIfPresent("includeQHashes", params.includeQHashes);
|
|
1425
1717
|
setIfPresent("referenceType", params.referenceType);
|
|
1426
1718
|
setIfPresent("referenceId", params.referenceId);
|
|
1427
1719
|
setIfPresent("tag", params.tag);
|
|
@@ -1435,6 +1727,8 @@ ${bytes.length}`;
|
|
|
1435
1727
|
setIfPresent("domain", params.domain);
|
|
1436
1728
|
setIfPresent("minBalance", params.minBalance);
|
|
1437
1729
|
setIfPresent("provider", params.provider);
|
|
1730
|
+
setIfPresent("handle", params.handle);
|
|
1731
|
+
setIfPresent("namespace", params.namespace);
|
|
1438
1732
|
setIfPresent("ownerAddress", params.ownerAddress);
|
|
1439
1733
|
setIfPresent("riskLevel", params.riskLevel);
|
|
1440
1734
|
setBoolIfPresent("sanctioned", params.sanctioned);
|
|
@@ -1442,18 +1736,57 @@ ${bytes.length}`;
|
|
|
1442
1736
|
setIfPresent("primaryWalletAddress", params.primaryWalletAddress);
|
|
1443
1737
|
setIfPresent("secondaryWalletAddress", params.secondaryWalletAddress);
|
|
1444
1738
|
setIfPresent("verificationMethod", params.verificationMethod);
|
|
1445
|
-
|
|
1739
|
+
let headersOverride = null;
|
|
1740
|
+
if (params.includePrivate === true) {
|
|
1741
|
+
const provided = params.privateAuth && typeof params.privateAuth === "object" ? params.privateAuth : null;
|
|
1742
|
+
let auth = provided;
|
|
1743
|
+
if (!auth) {
|
|
1744
|
+
const walletCandidate = params.wallet || this._getDefaultBrowserWallet();
|
|
1745
|
+
if (walletCandidate) {
|
|
1746
|
+
auth = await this._buildPrivateGateAuth({
|
|
1747
|
+
address,
|
|
1748
|
+
wallet: walletCandidate,
|
|
1749
|
+
chain: params.chain,
|
|
1750
|
+
signatureMethod: params.signatureMethod
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
if (!auth) {
|
|
1755
|
+
} else {
|
|
1756
|
+
const normalizedAuthWallet = this._normalizeIdentity(auth.walletAddress);
|
|
1757
|
+
const normalizedAddress = this._normalizeIdentity(address);
|
|
1758
|
+
if (!normalizedAuthWallet || normalizedAuthWallet !== normalizedAddress) {
|
|
1759
|
+
throw new ValidationError("privateAuth.walletAddress must match address when includePrivate=true");
|
|
1760
|
+
}
|
|
1761
|
+
const authChain = typeof auth.chain === "string" && auth.chain.includes(":") ? auth.chain.trim() : null;
|
|
1762
|
+
const authSignatureMethod = typeof auth.signatureMethod === "string" && auth.signatureMethod.trim() ? auth.signatureMethod.trim() : null;
|
|
1763
|
+
headersOverride = {
|
|
1764
|
+
"x-wallet-address": String(auth.walletAddress),
|
|
1765
|
+
"x-signature": String(auth.signature),
|
|
1766
|
+
"x-signed-timestamp": String(auth.signedTimestamp),
|
|
1767
|
+
...authChain ? { "x-chain": authChain } : {},
|
|
1768
|
+
...authSignatureMethod ? { "x-signature-method": authSignatureMethod } : {}
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
const response = await this._makeRequest("GET", `/api/v1/proofs/check?${qs.toString()}`, null, headersOverride);
|
|
1446
1773
|
if (!response.success) {
|
|
1447
1774
|
throw new ApiError(`Gate check failed: ${response.error?.message || "Unknown error"}`, response.error);
|
|
1448
1775
|
}
|
|
1449
1776
|
return response;
|
|
1450
1777
|
}
|
|
1451
1778
|
/**
|
|
1452
|
-
* CHECK GATE
|
|
1453
|
-
*
|
|
1779
|
+
* CHECK GATE — Local preview against proofs you already have in memory or from `getProofsByWallet`.
|
|
1780
|
+
*
|
|
1781
|
+
* **Not authoritative for access control.** For production allow/deny, use {@link NeusClient#gateCheck}
|
|
1782
|
+
* (`GET /api/v1/proofs/check`), which applies the same rules as the NEUS API. This method is useful for
|
|
1783
|
+
* UI previews, offline-ish flows, or when you already fetched proofs and want a quick match without
|
|
1784
|
+
* another round trip — but it can disagree with the server (e.g. `contentHash` matching uses a local
|
|
1785
|
+
* approximation when proof data only has inline `content`; the API uses the standard server-side hash).
|
|
1786
|
+
*
|
|
1454
1787
|
* Gate-first verification: checks if wallet has valid proofs satisfying requirements.
|
|
1455
1788
|
* Returns which requirements are missing/expired.
|
|
1456
|
-
*
|
|
1789
|
+
*
|
|
1457
1790
|
* @param {Object} params - Gate check parameters
|
|
1458
1791
|
* @param {string} params.walletAddress - Target wallet
|
|
1459
1792
|
* @param {Array<Object>} params.requirements - Array of gate requirements
|
|
@@ -1466,12 +1799,12 @@ ${bytes.length}`;
|
|
|
1466
1799
|
* Supports verifier-specific:
|
|
1467
1800
|
* - NFT/Token: 'contractAddress', 'tokenId', 'chainId', 'ownerAddress', 'minBalance'
|
|
1468
1801
|
* - DNS: 'domain', 'walletAddress'
|
|
1469
|
-
* - Wallet-link: 'primaryWalletAddress', 'secondaryWalletAddress', '
|
|
1802
|
+
* - Wallet-link: 'primaryWalletAddress', 'secondaryWalletAddress', 'chain', 'signatureMethod'
|
|
1470
1803
|
* - Contract-ownership: 'contractAddress', 'chainId', 'owner', 'verificationMethod'
|
|
1471
1804
|
* Note: contentHash matching uses approximation in SDK; for exact SHA-256 matching, use backend API
|
|
1472
1805
|
* @param {Array} [params.proofs] - Pre-fetched proofs (skip API call)
|
|
1473
1806
|
* @returns {Promise<Object>} Gate result with satisfied, missing, existing
|
|
1474
|
-
*
|
|
1807
|
+
*
|
|
1475
1808
|
* @example
|
|
1476
1809
|
* // Basic gate check
|
|
1477
1810
|
* const result = await client.checkGate({
|
|
@@ -1483,7 +1816,7 @@ ${bytes.length}`;
|
|
|
1483
1816
|
*/
|
|
1484
1817
|
async checkGate(params) {
|
|
1485
1818
|
const { walletAddress, requirements, proofs: preloadedProofs } = params;
|
|
1486
|
-
if (!
|
|
1819
|
+
if (!validateUniversalAddress(walletAddress)) {
|
|
1487
1820
|
throw new ValidationError("Valid walletAddress is required");
|
|
1488
1821
|
}
|
|
1489
1822
|
if (!Array.isArray(requirements) || requirements.length === 0) {
|
|
@@ -1504,20 +1837,20 @@ ${bytes.length}`;
|
|
|
1504
1837
|
const verifier = verifiedVerifiers.find(
|
|
1505
1838
|
(v) => v.verifierId === verifierId && v.verified === true
|
|
1506
1839
|
);
|
|
1507
|
-
if (!verifier)
|
|
1508
|
-
|
|
1509
|
-
if (proof.revokedAt)
|
|
1510
|
-
return false;
|
|
1840
|
+
if (!verifier) return false;
|
|
1841
|
+
if (proof.revokedAt) return false;
|
|
1511
1842
|
if (maxAgeMs) {
|
|
1512
1843
|
const proofTimestamp = proof.createdAt || proof.signedTimestamp || 0;
|
|
1513
1844
|
const proofAge = now - proofTimestamp;
|
|
1514
|
-
if (proofAge > maxAgeMs)
|
|
1515
|
-
return false;
|
|
1845
|
+
if (proofAge > maxAgeMs) return false;
|
|
1516
1846
|
}
|
|
1517
1847
|
if (match && typeof match === "object") {
|
|
1518
1848
|
const data = verifier.data || {};
|
|
1519
1849
|
const input = data.input || {};
|
|
1520
|
-
|
|
1850
|
+
const matchObj = Array.isArray(match) ? Object.fromEntries(
|
|
1851
|
+
match.filter((m) => m && m.path && String(m.value ?? "").trim() !== "").map((m) => [String(m.path).trim(), m.value])
|
|
1852
|
+
) : match;
|
|
1853
|
+
for (const [key, expected] of Object.entries(matchObj)) {
|
|
1521
1854
|
let actualValue = null;
|
|
1522
1855
|
if (key.includes(".")) {
|
|
1523
1856
|
const parts = key.split(".");
|
|
@@ -1542,6 +1875,7 @@ ${bytes.length}`;
|
|
|
1542
1875
|
actualValue = data.reference?.id || data.content;
|
|
1543
1876
|
}
|
|
1544
1877
|
if (actualValue === void 0) {
|
|
1878
|
+
const claims = data.claims || {};
|
|
1545
1879
|
if (key === "contractAddress") {
|
|
1546
1880
|
actualValue = input.contractAddress || data.contractAddress;
|
|
1547
1881
|
} else if (key === "tokenId") {
|
|
@@ -1560,6 +1894,22 @@ ${bytes.length}`;
|
|
|
1560
1894
|
actualValue = data.verificationMethod;
|
|
1561
1895
|
} else if (key === "domain") {
|
|
1562
1896
|
actualValue = data.domain;
|
|
1897
|
+
} else if (key === "handle") {
|
|
1898
|
+
actualValue = data.handle || data.pseudonymId;
|
|
1899
|
+
} else if (key === "namespace") {
|
|
1900
|
+
actualValue = data.namespace !== void 0 && data.namespace !== null && data.namespace !== "" ? data.namespace : "neus";
|
|
1901
|
+
} else if (key === "claims.sanctions_passed") {
|
|
1902
|
+
actualValue = claims.sanctions_passed ?? claims.sanctionsPassed;
|
|
1903
|
+
} else if (key === "claims.age_min") {
|
|
1904
|
+
actualValue = claims.age_min ?? claims.ageMin;
|
|
1905
|
+
} else if (key === "neusPersonhoodId") {
|
|
1906
|
+
actualValue = data.neusPersonhoodId;
|
|
1907
|
+
} else if (key === "riskLevel") {
|
|
1908
|
+
actualValue = data.riskLevel;
|
|
1909
|
+
} else if (key === "sanctioned") {
|
|
1910
|
+
actualValue = data.sanctioned;
|
|
1911
|
+
} else if (key === "poisoned") {
|
|
1912
|
+
actualValue = data.poisoned;
|
|
1563
1913
|
}
|
|
1564
1914
|
}
|
|
1565
1915
|
if (key === "contentHash" && actualValue === void 0 && data.content) {
|
|
@@ -1571,7 +1921,7 @@ ${bytes.length}`;
|
|
|
1571
1921
|
hash = (hash << 5) - hash + char;
|
|
1572
1922
|
hash = hash & hash;
|
|
1573
1923
|
}
|
|
1574
|
-
actualValue =
|
|
1924
|
+
actualValue = `0x${Math.abs(hash).toString(16).padStart(64, "0").substring(0, 66)}`;
|
|
1575
1925
|
} catch {
|
|
1576
1926
|
actualValue = String(data.content);
|
|
1577
1927
|
}
|
|
@@ -1581,11 +1931,16 @@ ${bytes.length}`;
|
|
|
1581
1931
|
if (actualValue === void 0 || actualValue === null) {
|
|
1582
1932
|
return false;
|
|
1583
1933
|
}
|
|
1934
|
+
if (typeof actualValue === "boolean" || key && (key.includes("sanctions") || key.includes("sanctioned") || key.includes("poisoned"))) {
|
|
1935
|
+
const bActual = Boolean(actualValue);
|
|
1936
|
+
const bExpected = expected === true || expected === "true" || String(expected).toLowerCase() === "true";
|
|
1937
|
+
if (bActual !== bExpected) return false;
|
|
1938
|
+
continue;
|
|
1939
|
+
}
|
|
1584
1940
|
if (key === "chainId" || key === "tokenId" && (typeof actualValue === "number" || !isNaN(Number(actualValue)))) {
|
|
1585
1941
|
normalizedActual = Number(actualValue);
|
|
1586
1942
|
normalizedExpected = Number(expected);
|
|
1587
|
-
if (isNaN(normalizedActual) || isNaN(normalizedExpected))
|
|
1588
|
-
return false;
|
|
1943
|
+
if (isNaN(normalizedActual) || isNaN(normalizedExpected)) return false;
|
|
1589
1944
|
} else if (typeof actualValue === "string" && (actualValue.startsWith("0x") || actualValue.length > 20)) {
|
|
1590
1945
|
normalizedActual = actualValue.toLowerCase();
|
|
1591
1946
|
normalizedExpected = typeof expected === "string" ? String(expected).toLowerCase() : expected;
|
|
@@ -1614,13 +1969,6 @@ ${bytes.length}`;
|
|
|
1614
1969
|
allProofs: proofs
|
|
1615
1970
|
};
|
|
1616
1971
|
}
|
|
1617
|
-
// ============================================================================
|
|
1618
|
-
// PRIVATE UTILITY METHODS
|
|
1619
|
-
// ============================================================================
|
|
1620
|
-
/**
|
|
1621
|
-
* Get connected wallet address
|
|
1622
|
-
* @private
|
|
1623
|
-
*/
|
|
1624
1972
|
async _getWalletAddress() {
|
|
1625
1973
|
if (typeof window === "undefined" || !window.ethereum) {
|
|
1626
1974
|
throw new ConfigurationError("No Web3 wallet detected");
|
|
@@ -1631,10 +1979,6 @@ ${bytes.length}`;
|
|
|
1631
1979
|
}
|
|
1632
1980
|
return accounts[0];
|
|
1633
1981
|
}
|
|
1634
|
-
/**
|
|
1635
|
-
* Make HTTP request to API
|
|
1636
|
-
* @private
|
|
1637
|
-
*/
|
|
1638
1982
|
async _makeRequest(method, endpoint, data = null, headersOverride = null) {
|
|
1639
1983
|
const url = `${this.baseUrl}${endpoint}`;
|
|
1640
1984
|
const controller = new AbortController();
|
|
@@ -1672,27 +2016,23 @@ ${bytes.length}`;
|
|
|
1672
2016
|
throw new NetworkError(`Network error: ${error.message}`);
|
|
1673
2017
|
}
|
|
1674
2018
|
}
|
|
1675
|
-
/**
|
|
1676
|
-
* Format API response for consistent structure
|
|
1677
|
-
* @private
|
|
1678
|
-
*/
|
|
1679
2019
|
_formatResponse(response) {
|
|
1680
|
-
const
|
|
2020
|
+
const proofId = response?.data?.proofId || response?.proofId || response?.data?.resource?.proofId || response?.data?.qHash || response?.qHash || response?.data?.resource?.qHash || response?.data?.id;
|
|
2021
|
+
const qHash = response?.data?.qHash || response?.qHash || response?.data?.resource?.qHash || proofId || response?.data?.id;
|
|
2022
|
+
const finalProofId = proofId || qHash || null;
|
|
2023
|
+
const finalQHash = qHash || proofId || finalProofId;
|
|
1681
2024
|
const status = response?.data?.status || response?.status || response?.data?.resource?.status || (response?.success ? "completed" : "unknown");
|
|
1682
2025
|
return {
|
|
1683
2026
|
success: response.success,
|
|
1684
|
-
|
|
2027
|
+
proofId: finalProofId,
|
|
2028
|
+
qHash: finalQHash,
|
|
1685
2029
|
status,
|
|
1686
2030
|
data: response.data,
|
|
1687
2031
|
message: response.message,
|
|
1688
2032
|
timestamp: Date.now(),
|
|
1689
|
-
|
|
2033
|
+
proofUrl: finalProofId ? `${this.baseUrl}/api/v1/proofs/${finalProofId}` : null
|
|
1690
2034
|
};
|
|
1691
2035
|
}
|
|
1692
|
-
/**
|
|
1693
|
-
* Check if status is terminal (completed or failed)
|
|
1694
|
-
* @private
|
|
1695
|
-
*/
|
|
1696
2036
|
_isTerminalStatus(status) {
|
|
1697
2037
|
const terminalStates = [
|
|
1698
2038
|
"verified",
|
|
@@ -1723,5 +2063,6 @@ ${bytes.length}`;
|
|
|
1723
2063
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1724
2064
|
0 && (module.exports = {
|
|
1725
2065
|
NeusClient,
|
|
2066
|
+
PORTABLE_PROOF_SIGNER_HEADER,
|
|
1726
2067
|
constructVerificationMessage
|
|
1727
2068
|
});
|