@qrlwallet/connect 5.0.3 → 5.1.1

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/dist/index.mjs CHANGED
@@ -461,7 +461,7 @@ function isQrlSignedTypedDataResult(value) {
461
461
  try {
462
462
  if (!isSigningResultRecord(value)) return false;
463
463
  const keys = hasOwn(value, "descriptor") ? TYPED_RESULT_KEYS_WITH_DESCRIPTOR : TYPED_RESULT_KEYS;
464
- return hasExactOwnKeys(value, keys) && value.schemeVersion === "QRL-SIGN-TYPED-v1" && isSigningResultRecord(value.domain) && hasValidSigningFields(value);
464
+ return hasExactOwnKeys(value, keys) && (value.schemeVersion === "QRL-SIGN-TYPED-v1" || value.schemeVersion === "QRL-SIGN-TYPED-v2") && isSigningResultRecord(value.domain) && hasValidSigningFields(value);
465
465
  } catch {
466
466
  return false;
467
467
  }
@@ -2976,8 +2976,10 @@ var ConnectionManager = _ConnectionManager;
2976
2976
  // src/signing/ctx.ts
2977
2977
  var SCHEME_VERSION_MSG = "QRL-SIGN-MSG-v1";
2978
2978
  var SCHEME_VERSION_TYPED = "QRL-SIGN-TYPED-v1";
2979
+ var SCHEME_VERSION_TYPED_V2 = "QRL-SIGN-TYPED-v2";
2979
2980
  var SCHEME_TAG_MSG = new TextEncoder().encode(SCHEME_VERSION_MSG);
2980
2981
  var SCHEME_TAG_TYPED = new TextEncoder().encode(SCHEME_VERSION_TYPED);
2982
+ var SCHEME_TAG_TYPED_V2 = new TextEncoder().encode(SCHEME_VERSION_TYPED_V2);
2981
2983
  var DIGEST_LEN = 64;
2982
2984
 
2983
2985
  // src/signing/bytes.ts
@@ -3017,7 +3019,14 @@ function concatBytesArr(parts) {
3017
3019
  }
3018
3020
 
3019
3021
  // src/signing/typedData.ts
3020
- var SLOT = 32;
3022
+ var SLOT_BYTES = Object.freeze({
3023
+ [SCHEME_VERSION_TYPED]: 32,
3024
+ [SCHEME_VERSION_TYPED_V2]: 64
3025
+ });
3026
+ var SCHEME_TAGS = Object.freeze({
3027
+ [SCHEME_VERSION_TYPED]: SCHEME_TAG_TYPED,
3028
+ [SCHEME_VERSION_TYPED_V2]: SCHEME_TAG_TYPED_V2
3029
+ });
3021
3030
  var TYPED_DATA_LIMITS = Object.freeze({
3022
3031
  maxTypes: 32,
3023
3032
  maxFieldsPerType: 32,
@@ -3069,21 +3078,30 @@ function parsePayload(payload) {
3069
3078
  var ATOMIC_RE = /^(?:(address|bool|string|bytes)|(u?int)(\d+)|bytes(\d+)|(.+?)\[(\d*)\])$/;
3070
3079
  var IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
3071
3080
  var UNSAFE_OBJECT_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
3081
+ function newBudget(schemeVersion) {
3082
+ return {
3083
+ remainingValues: TYPED_DATA_LIMITS.maxEncodedValues,
3084
+ slot: SLOT_BYTES[schemeVersion]
3085
+ };
3086
+ }
3072
3087
  function consumeValue(budget) {
3073
3088
  budget.remainingValues--;
3074
3089
  if (budget.remainingValues < 0) throw new Error("typed data contains too many encoded values");
3075
3090
  }
3091
+ function inputPreview(value) {
3092
+ return value.length > 32 ? `${value.slice(0, 32)}... (length ${value.length})` : value;
3093
+ }
3076
3094
  function assertIdentifier(value, label) {
3077
3095
  if (!IDENTIFIER_RE.test(value) || value.length > TYPED_DATA_LIMITS.maxIdentifierLength || UNSAFE_OBJECT_KEYS.has(value)) {
3078
- throw new Error(`invalid ${label}: ${value}`);
3096
+ throw new Error(`invalid ${label}: ${inputPreview(value)}`);
3079
3097
  }
3080
3098
  }
3081
3099
  function parseFieldType(type, types, depth = 0) {
3082
3100
  if (depth > TYPED_DATA_LIMITS.maxArrayNesting) {
3083
- throw new Error(`type nesting too deep: ${type}`);
3101
+ throw new Error(`type nesting too deep: ${inputPreview(type)}`);
3084
3102
  }
3085
3103
  if (type.length > TYPED_DATA_LIMITS.maxFieldTypeLength) {
3086
- throw new Error(`field type too long: ${type}`);
3104
+ throw new Error(`field type too long: ${inputPreview(type)}`);
3087
3105
  }
3088
3106
  const m = ATOMIC_RE.exec(type);
3089
3107
  if (m) {
@@ -3094,14 +3112,14 @@ function parseFieldType(type, types, depth = 0) {
3094
3112
  if (intKind) {
3095
3113
  const width = Number(intWidthStr);
3096
3114
  if (!Number.isInteger(width) || width < 8 || width > 256 || width % 8 !== 0) {
3097
- throw new Error(`invalid int width: ${type}`);
3115
+ throw new Error(`invalid int width: ${inputPreview(type)}`);
3098
3116
  }
3099
3117
  return { kind: intKind === "uint" ? "uintN" : "intN", width };
3100
3118
  }
3101
3119
  if (bytesWidthStr) {
3102
3120
  const width = Number(bytesWidthStr);
3103
3121
  if (!Number.isInteger(width) || width < 1 || width > 32) {
3104
- throw new Error(`invalid bytesN width: ${type}`);
3122
+ throw new Error(`invalid bytesN width: ${inputPreview(type)}`);
3105
3123
  }
3106
3124
  return { kind: "bytesN", width };
3107
3125
  }
@@ -3110,7 +3128,7 @@ function parseFieldType(type, types, depth = 0) {
3110
3128
  if (sizeStr) {
3111
3129
  const size = Number(sizeStr);
3112
3130
  if (!Number.isSafeInteger(size) || size <= 0 || size > TYPED_DATA_LIMITS.maxArrayLength) {
3113
- throw new Error(`invalid array size: ${type}`);
3131
+ throw new Error(`invalid array size: ${inputPreview(type)}`);
3114
3132
  }
3115
3133
  return { kind: "array", inner: innerType, size };
3116
3134
  }
@@ -3120,7 +3138,7 @@ function parseFieldType(type, types, depth = 0) {
3120
3138
  if (Object.prototype.hasOwnProperty.call(types, type)) {
3121
3139
  return { kind: "ref", name: type };
3122
3140
  }
3123
- throw new Error(`unknown type: ${type}`);
3141
+ throw new Error(`unknown type: ${inputPreview(type)}`);
3124
3142
  }
3125
3143
  function isReservedAtomicTypeName(name) {
3126
3144
  if (/^(?:address|bool|string|bytes)$/.test(name)) return true;
@@ -3137,24 +3155,35 @@ function isReservedAtomicTypeName(name) {
3137
3155
  return false;
3138
3156
  }
3139
3157
  function baseTypeName(type) {
3140
- return type.replace(/(\[\d*\])+$/, "");
3158
+ let end = type.length;
3159
+ while (end > 0 && type[end - 1] === "]") {
3160
+ let start = end - 2;
3161
+ while (start >= 0) {
3162
+ const code = type.charCodeAt(start);
3163
+ if (code < 48 || code > 57) break;
3164
+ start--;
3165
+ }
3166
+ if (start < 0 || type[start] !== "[") break;
3167
+ end = start;
3168
+ }
3169
+ return type.slice(0, end);
3141
3170
  }
3142
3171
  function collectDependencies(primary, types) {
3143
3172
  if (!Object.prototype.hasOwnProperty.call(types, primary)) {
3144
- throw new Error(`unknown primary type: ${primary}`);
3173
+ throw new Error(`unknown primary type: ${inputPreview(primary)}`);
3145
3174
  }
3146
3175
  const visited = /* @__PURE__ */ new Set();
3147
3176
  const visit = (name, path) => {
3148
3177
  if (path.length > TYPED_DATA_LIMITS.maxTypeGraphDepth) {
3149
- throw new Error(`type graph nesting too deep: ${[...path, name].join(" -> ")}`);
3178
+ throw new Error(`type graph nesting too deep: ${inputPreview([...path, name].join(" -> "))}`);
3150
3179
  }
3151
3180
  if (path.includes(name)) {
3152
- throw new Error(`cyclic type reference: ${[...path, name].join(" -> ")}`);
3181
+ throw new Error(`cyclic type reference: ${inputPreview([...path, name].join(" -> "))}`);
3153
3182
  }
3154
3183
  if (visited.has(name)) return;
3155
3184
  visited.add(name);
3156
3185
  const def = types[name];
3157
- if (!def) throw new Error(`unknown type: ${name}`);
3186
+ if (!def) throw new Error(`unknown type: ${inputPreview(name)}`);
3158
3187
  for (const f of def) {
3159
3188
  const base = baseTypeName(f.type);
3160
3189
  if (Object.prototype.hasOwnProperty.call(types, base)) {
@@ -3175,11 +3204,11 @@ function validateTypeMap(types) {
3175
3204
  for (const [name, def] of entries) {
3176
3205
  assertIdentifier(name, "struct name");
3177
3206
  if (name !== "QRLDomain" && isReservedAtomicTypeName(name)) {
3178
- throw new Error(`struct name is reserved by an atomic type: ${name}`);
3207
+ throw new Error(`struct name is reserved by an atomic type: ${inputPreview(name)}`);
3179
3208
  }
3180
3209
  const defUnknown = def;
3181
3210
  if (!Array.isArray(defUnknown) || def.length === 0 || def.length > TYPED_DATA_LIMITS.maxFieldsPerType) {
3182
- throw new Error(`empty or invalid struct: ${name}`);
3211
+ throw new Error(`empty or invalid struct: ${inputPreview(name)}`);
3183
3212
  }
3184
3213
  totalFields += def.length;
3185
3214
  if (totalFields > TYPED_DATA_LIMITS.maxTotalFields) {
@@ -3188,14 +3217,17 @@ function validateTypeMap(types) {
3188
3217
  const seen = /* @__PURE__ */ new Set();
3189
3218
  for (const f of def) {
3190
3219
  if (!f || typeof f.name !== "string" || !f.name) {
3191
- throw new Error(`bad field in ${name}`);
3220
+ throw new Error(`bad field in ${inputPreview(name)}`);
3192
3221
  }
3193
- assertIdentifier(f.name, `field name in ${name}`);
3222
+ assertIdentifier(f.name, `field name in ${inputPreview(name)}`);
3194
3223
  if (typeof f.type !== "string" || !f.type) {
3195
- throw new Error(`bad field type in ${name}.${f.name}`);
3224
+ throw new Error(`bad field type in ${inputPreview(name)}.${inputPreview(f.name)}`);
3225
+ }
3226
+ if (f.type.length > TYPED_DATA_LIMITS.maxFieldTypeLength) {
3227
+ throw new Error(`field type too long: ${inputPreview(f.type)}`);
3196
3228
  }
3197
3229
  if (seen.has(f.name)) {
3198
- throw new Error(`duplicate field "${f.name}" in ${name}`);
3230
+ throw new Error(`duplicate field "${inputPreview(f.name)}" in ${inputPreview(name)}`);
3199
3231
  }
3200
3232
  seen.add(f.name);
3201
3233
  }
@@ -3207,7 +3239,7 @@ function encodeType(primary, types) {
3207
3239
  const others = [...deps].filter((n) => n !== primary).sort();
3208
3240
  return [primary, ...others].map((name) => {
3209
3241
  const fields = types[name];
3210
- if (!fields) throw new Error(`unknown type: ${name}`);
3242
+ if (!fields) throw new Error(`unknown type: ${inputPreview(name)}`);
3211
3243
  const inner = fields.map((f) => `${f.type} ${f.name}`).join(",");
3212
3244
  return `${name}(${inner})`;
3213
3245
  }).join("");
@@ -3215,44 +3247,46 @@ function encodeType(primary, types) {
3215
3247
  function typeHash(primary, types) {
3216
3248
  return shake256Digest(new TextEncoder().encode(encodeType(primary, types)), DIGEST_LEN);
3217
3249
  }
3218
- function parseQAddress(addr) {
3250
+ function parseQAddress(addr, slot) {
3219
3251
  if (!isCurrentQrlAddress(addr)) {
3220
- throw new Error(`invalid Q-address: ${String(addr)}`);
3252
+ throw new Error(`invalid Q-address: ${inputPreview(String(addr))}`);
3221
3253
  }
3222
3254
  const bytes = hexToBytes("0x" + addr.slice(1).toLowerCase());
3223
- if (bytes.length > SLOT) {
3255
+ if (bytes.length > slot) {
3224
3256
  throw new Error("qrl_signTypedData v1 does not support QIP-55 address fields");
3225
3257
  }
3226
3258
  return bytes;
3227
3259
  }
3228
- function padLeft32(bytes) {
3229
- if (bytes.length > SLOT) throw new Error("cannot pad: bytes > 32");
3230
- const out = new Uint8Array(SLOT);
3231
- out.set(bytes, SLOT - bytes.length);
3260
+ function padLeft(bytes, slot) {
3261
+ if (bytes.length > slot) throw new Error(`cannot pad: bytes > ${slot}`);
3262
+ const out = new Uint8Array(slot);
3263
+ out.set(bytes, slot - bytes.length);
3232
3264
  return out;
3233
3265
  }
3234
- function padRight32(bytes) {
3235
- if (bytes.length > SLOT) throw new Error("cannot pad: bytes > 32");
3236
- const out = new Uint8Array(SLOT);
3266
+ function padRight(bytes, slot) {
3267
+ if (bytes.length > slot) throw new Error(`cannot pad: bytes > ${slot}`);
3268
+ const out = new Uint8Array(slot);
3237
3269
  out.set(bytes, 0);
3238
3270
  return out;
3239
3271
  }
3240
- function bigIntToSlot(value, width, signed) {
3272
+ function bigIntToSlot(value, width, signed, slot) {
3241
3273
  if (signed) {
3242
3274
  const limit = 1n << BigInt(width - 1);
3243
3275
  if (value >= limit || value < -limit) {
3244
- throw new Error(`int${width} out of range: ${value}`);
3276
+ throw new Error(`int${width} out of range: ${inputPreview(String(value))}`);
3245
3277
  }
3246
3278
  } else {
3247
- if (value < 0n) throw new Error(`uint${width} negative: ${value}`);
3279
+ if (value < 0n) throw new Error(`uint${width} negative: ${inputPreview(String(value))}`);
3248
3280
  const limit = 1n << BigInt(width);
3249
- if (value >= limit) throw new Error(`uint${width} out of range: ${value}`);
3281
+ if (value >= limit)
3282
+ throw new Error(`uint${width} out of range: ${inputPreview(String(value))}`);
3250
3283
  }
3251
- const slotMask = (1n << 256n) - 1n;
3252
- const repr = value < 0n ? value + (1n << 256n) & slotMask : value;
3253
- const out = new Uint8Array(SLOT);
3284
+ const slotBits = BigInt(slot * 8);
3285
+ const slotMask = (1n << slotBits) - 1n;
3286
+ const repr = value < 0n ? value + (1n << slotBits) & slotMask : value;
3287
+ const out = new Uint8Array(slot);
3254
3288
  let v = repr;
3255
- for (let i = SLOT - 1; i >= 0; i--) {
3289
+ for (let i = slot - 1; i >= 0; i--) {
3256
3290
  out[i] = Number(v & 0xffn);
3257
3291
  v >>= 8n;
3258
3292
  }
@@ -3268,7 +3302,7 @@ function parseIntValue(v, typeLabel) {
3268
3302
  return isNegative ? -abs : abs;
3269
3303
  }
3270
3304
  if (!/^-?(0|[1-9]\d*)$/.test(v)) {
3271
- throw new Error(`invalid ${typeLabel} string: ${v}`);
3305
+ throw new Error(`invalid ${typeLabel} string: ${inputPreview(v)}`);
3272
3306
  }
3273
3307
  return BigInt(v);
3274
3308
  }
@@ -3282,26 +3316,26 @@ function parseIntValue(v, typeLabel) {
3282
3316
  }
3283
3317
  function encodeFieldWithBudget(type, value, types, budget, depth) {
3284
3318
  if (depth > TYPED_DATA_LIMITS.maxTypeGraphDepth + TYPED_DATA_LIMITS.maxArrayNesting) {
3285
- throw new Error(`value nesting too deep: ${type}`);
3319
+ throw new Error(`value nesting too deep: ${inputPreview(type)}`);
3286
3320
  }
3287
3321
  consumeValue(budget);
3288
3322
  const parsed = parseFieldType(type, types);
3289
3323
  switch (parsed.kind) {
3290
3324
  case "ref":
3291
3325
  if (!isMessageObject(value)) {
3292
- throw new Error(`struct field expects object: ${type}`);
3326
+ throw new Error(`struct field expects object: ${inputPreview(type)}`);
3293
3327
  }
3294
3328
  return hashStructWithBudget(parsed.name, value, types, budget, depth + 1);
3295
3329
  case "address":
3296
3330
  if (typeof value !== "string") {
3297
3331
  throw new Error(`address field expects string: ${typeof value}`);
3298
3332
  }
3299
- return padLeft32(parseQAddress(value));
3333
+ return padLeft(parseQAddress(value, budget.slot), budget.slot);
3300
3334
  case "bool":
3301
3335
  if (typeof value !== "boolean") {
3302
3336
  throw new Error(`bool field expects boolean: ${typeof value}`);
3303
3337
  }
3304
- return padLeft32(new Uint8Array([value ? 1 : 0]));
3338
+ return padLeft(new Uint8Array([value ? 1 : 0]), budget.slot);
3305
3339
  case "string": {
3306
3340
  if (typeof value !== "string") {
3307
3341
  throw new Error(`string field expects string: ${typeof value}`);
@@ -3324,9 +3358,19 @@ function encodeFieldWithBudget(type, value, types, budget, depth) {
3324
3358
  }
3325
3359
  return shake256Digest(hexToBytes(value), DIGEST_LEN);
3326
3360
  case "uintN":
3327
- return bigIntToSlot(parseIntValue(value, `uint${parsed.width}`), parsed.width, false);
3361
+ return bigIntToSlot(
3362
+ parseIntValue(value, `uint${parsed.width}`),
3363
+ parsed.width,
3364
+ false,
3365
+ budget.slot
3366
+ );
3328
3367
  case "intN":
3329
- return bigIntToSlot(parseIntValue(value, `int${parsed.width}`), parsed.width, true);
3368
+ return bigIntToSlot(
3369
+ parseIntValue(value, `int${parsed.width}`),
3370
+ parsed.width,
3371
+ true,
3372
+ budget.slot
3373
+ );
3330
3374
  case "bytesN": {
3331
3375
  if (typeof value !== "string") {
3332
3376
  throw new Error(`bytes${parsed.width} expects 0x-hex string: ${typeof value}`);
@@ -3338,17 +3382,19 @@ function encodeFieldWithBudget(type, value, types, budget, depth) {
3338
3382
  if (raw.length !== parsed.width) {
3339
3383
  throw new Error(`bytes${parsed.width} requires ${parsed.width} bytes, got ${raw.length}`);
3340
3384
  }
3341
- return padRight32(raw);
3385
+ return padRight(raw, budget.slot);
3342
3386
  }
3343
3387
  case "array": {
3344
3388
  if (!Array.isArray(value)) {
3345
3389
  throw new Error(`array field expects array: ${typeof value}`);
3346
3390
  }
3347
3391
  if (value.length > TYPED_DATA_LIMITS.maxArrayLength) {
3348
- throw new Error(`array ${type} exceeds length limit`);
3392
+ throw new Error(`array ${inputPreview(type)} exceeds length limit`);
3349
3393
  }
3350
3394
  if (parsed.size !== void 0 && value.length !== parsed.size) {
3351
- throw new Error(`fixed array ${type} requires length ${parsed.size}, got ${value.length}`);
3395
+ throw new Error(
3396
+ `fixed array ${inputPreview(type)} requires length ${parsed.size}, got ${value.length}`
3397
+ );
3352
3398
  }
3353
3399
  const chunks = value.map(
3354
3400
  (v) => encodeFieldWithBudget(parsed.inner, v, types, budget, depth + 1)
@@ -3357,20 +3403,15 @@ function encodeFieldWithBudget(type, value, types, budget, depth) {
3357
3403
  }
3358
3404
  }
3359
3405
  }
3360
- function encodeField(type, value, types) {
3406
+ function encodeField(type, value, types, schemeVersion) {
3361
3407
  validateTypeMap(types);
3362
- return encodeFieldWithBudget(
3363
- type,
3364
- value,
3365
- types,
3366
- { remainingValues: TYPED_DATA_LIMITS.maxEncodedValues },
3367
- 0
3368
- );
3408
+ const scheme = schemeVersion ?? schemeVersionForTypes(types);
3409
+ return encodeFieldWithBudget(type, value, types, newBudget(scheme), 0);
3369
3410
  }
3370
3411
  function hashStructWithBudget(primary, data, types, budget, depth) {
3371
3412
  consumeValue(budget);
3372
3413
  const fields = types[primary];
3373
- if (!fields) throw new Error(`unknown struct: ${primary}`);
3414
+ if (!fields) throw new Error(`unknown struct: ${inputPreview(primary)}`);
3374
3415
  const expected = new Set(fields.map((f) => f.name));
3375
3416
  let ownFieldCount = 0;
3376
3417
  for (const k in data) {
@@ -3379,26 +3420,23 @@ function hashStructWithBudget(primary, data, types, budget, depth) {
3379
3420
  if (ownFieldCount > TYPED_DATA_LIMITS.maxEncodedValues) {
3380
3421
  throw new Error("typed data object contains too many fields");
3381
3422
  }
3382
- if (!expected.has(k)) throw new Error(`unknown field in ${primary}: ${k}`);
3423
+ if (!expected.has(k)) {
3424
+ throw new Error(`unknown field in ${inputPreview(primary)}: ${inputPreview(k)}`);
3425
+ }
3383
3426
  }
3384
3427
  const parts = [typeHash(primary, types)];
3385
3428
  for (const f of fields) {
3386
3429
  if (!Object.prototype.hasOwnProperty.call(data, f.name)) {
3387
- throw new Error(`missing field ${primary}.${f.name}`);
3430
+ throw new Error(`missing field ${inputPreview(primary)}.${inputPreview(f.name)}`);
3388
3431
  }
3389
3432
  parts.push(encodeFieldWithBudget(f.type, data[f.name], types, budget, depth + 1));
3390
3433
  }
3391
3434
  return shake256Digest(concatBytesArr(parts), DIGEST_LEN);
3392
3435
  }
3393
- function hashStruct(primary, data, types) {
3436
+ function hashStruct(primary, data, types, schemeVersion) {
3394
3437
  validateTypeMap(types);
3395
- return hashStructWithBudget(
3396
- primary,
3397
- data,
3398
- types,
3399
- { remainingValues: TYPED_DATA_LIMITS.maxEncodedValues },
3400
- 0
3401
- );
3438
+ const scheme = schemeVersion ?? schemeVersionForTypes(types);
3439
+ return hashStructWithBudget(primary, data, types, newBudget(scheme), 0);
3402
3440
  }
3403
3441
  var RESERVED_DOMAIN_FIELDS = {
3404
3442
  name: "string",
@@ -3415,11 +3453,13 @@ function validateDomainTypes(types) {
3415
3453
  const expected = RESERVED_DOMAIN_FIELDS[f.name];
3416
3454
  if (!expected) {
3417
3455
  throw new Error(
3418
- `QRLDomain field "${f.name}" not in reserved set (name, version, chainId, verifyingContract, salt)`
3456
+ `QRLDomain field "${inputPreview(f.name)}" not in reserved set (name, version, chainId, verifyingContract, salt)`
3419
3457
  );
3420
3458
  }
3421
3459
  if (f.type !== expected) {
3422
- throw new Error(`QRLDomain field "${f.name}" must be type "${expected}", got "${f.type}"`);
3460
+ throw new Error(
3461
+ `QRLDomain field "${inputPreview(f.name)}" must be type "${expected}", got "${inputPreview(f.type)}"`
3462
+ );
3423
3463
  }
3424
3464
  if (f.name === "name") hasName = true;
3425
3465
  }
@@ -3431,10 +3471,10 @@ function validatePayloadReachability(primary, types) {
3431
3471
  for (const t of collectDependencies(root, types)) reachable.add(t);
3432
3472
  }
3433
3473
  for (const k of Object.keys(types)) {
3434
- if (!reachable.has(k)) throw new Error(`unused referenced type: ${k}`);
3474
+ if (!reachable.has(k)) throw new Error(`unused referenced type: ${inputPreview(k)}`);
3435
3475
  }
3436
3476
  }
3437
- function computeTypedDataDigest(payload) {
3477
+ function parseAndValidatePayload(payload) {
3438
3478
  const parsed = parsePayload(payload);
3439
3479
  validateTypeMap(parsed.types);
3440
3480
  assertIdentifier(parsed.primaryType, "primary type");
@@ -3443,7 +3483,26 @@ function computeTypedDataDigest(payload) {
3443
3483
  }
3444
3484
  validateDomainTypes(parsed.types);
3445
3485
  validatePayloadReachability(parsed.primaryType, parsed.types);
3446
- const budget = { remainingValues: TYPED_DATA_LIMITS.maxEncodedValues };
3486
+ return parsed;
3487
+ }
3488
+ function schemeVersionForTypes(types) {
3489
+ for (const fields of Object.values(types)) {
3490
+ if (fields.some((f) => baseTypeName(f.type) === "address")) {
3491
+ return SCHEME_VERSION_TYPED_V2;
3492
+ }
3493
+ }
3494
+ return SCHEME_VERSION_TYPED;
3495
+ }
3496
+ function typedDataSchemeVersion(payload) {
3497
+ return schemeVersionForTypes(parseAndValidatePayload(payload).types);
3498
+ }
3499
+ function typedDataSchemeTag(schemeVersion) {
3500
+ return SCHEME_TAGS[schemeVersion];
3501
+ }
3502
+ function computeTypedDataDigest(payload) {
3503
+ const parsed = parseAndValidatePayload(payload);
3504
+ const schemeVersion = schemeVersionForTypes(parsed.types);
3505
+ const budget = newBudget(schemeVersion);
3447
3506
  const domainHash = hashStructWithBudget("QRLDomain", parsed.domain, parsed.types, budget, 0);
3448
3507
  const messageHash = hashStructWithBudget(
3449
3508
  parsed.primaryType,
@@ -3452,7 +3511,10 @@ function computeTypedDataDigest(payload) {
3452
3511
  budget,
3453
3512
  0
3454
3513
  );
3455
- return shake256Digest(concatBytes(SCHEME_TAG_TYPED, domainHash, messageHash), DIGEST_LEN);
3514
+ return shake256Digest(
3515
+ concatBytes(SCHEME_TAGS[schemeVersion], domainHash, messageHash),
3516
+ DIGEST_LEN
3517
+ );
3456
3518
  }
3457
3519
 
3458
3520
  // src/utils/platform.ts
@@ -3644,9 +3706,8 @@ function validateRestrictedRequest(method, params, authorizedAccounts, currentCh
3644
3706
  if (params[0] !== authorizedAccount) {
3645
3707
  throw new Error("qrl_signTypedData signer is not the authorized account");
3646
3708
  }
3647
- throw new Error(
3648
- "qrl_signTypedData is unavailable for QIP-55 until the 64-byte word encoding and signing scheme version are finalized"
3649
- );
3709
+ computeTypedDataDigest(params[1]);
3710
+ return void 0;
3650
3711
  }
3651
3712
  function requiresAuthorizedAccount(method) {
3652
3713
  return method === "qrl_sendTransaction" || method === "qrl_signTransaction" || method === "qrl_signMessage" || method === "qrl_signTypedData";
@@ -4292,9 +4353,13 @@ function verifyMessageBytes(signature, publicKey, messageBytes) {
4292
4353
  const digest = computeMessageDigest(messageBytes);
4293
4354
  return mldsaVerify(signature, digest, publicKey, SCHEME_TAG_MSG);
4294
4355
  }
4295
- function verifyTypedDataBytes(signature, publicKey, payload) {
4356
+ function verifyTypedDataBytes(signature, publicKey, payload, claimedSchemeVersion) {
4357
+ const schemeVersion = typedDataSchemeVersion(payload);
4358
+ if (claimedSchemeVersion !== void 0 && claimedSchemeVersion !== schemeVersion) {
4359
+ return false;
4360
+ }
4296
4361
  const digest = computeTypedDataDigest(payload);
4297
- return mldsaVerify(signature, digest, publicKey, SCHEME_TAG_TYPED);
4362
+ return mldsaVerify(signature, digest, publicKey, typedDataSchemeTag(schemeVersion));
4298
4363
  }
4299
4364
  function verifyMessageSignature({
4300
4365
  signature,
@@ -4314,13 +4379,14 @@ function verifyMessageSignature({
4314
4379
  function verifyTypedDataSignature({
4315
4380
  signature,
4316
4381
  publicKey,
4317
- payload
4382
+ payload,
4383
+ schemeVersion
4318
4384
  }) {
4319
4385
  try {
4320
4386
  const sig = fixedBytesOrHex(signature, ML_DSA_87_SIGNATURE_BYTES);
4321
4387
  const pk = fixedBytesOrHex(publicKey, ML_DSA_87_PUBLIC_KEY_BYTES);
4322
4388
  if (!sig || !pk) return false;
4323
- return verifyTypedDataBytes(sig, pk, payload);
4389
+ return verifyTypedDataBytes(sig, pk, payload, schemeVersion);
4324
4390
  } catch {
4325
4391
  return false;
4326
4392
  }
@@ -4358,7 +4424,8 @@ function verifyTypedDataForSigner({
4358
4424
  descriptor,
4359
4425
  signature,
4360
4426
  publicKey,
4361
- payload
4427
+ payload,
4428
+ schemeVersion
4362
4429
  }) {
4363
4430
  try {
4364
4431
  if (descriptor === void 0) return false;
@@ -4366,7 +4433,7 @@ function verifyTypedDataForSigner({
4366
4433
  const publicKeyBytes = fixedBytesOrHex(publicKey, ML_DSA_87_PUBLIC_KEY_BYTES);
4367
4434
  const signatureBytes = fixedBytesOrHex(signature, ML_DSA_87_SIGNATURE_BYTES);
4368
4435
  if (!descriptorBytes || !publicKeyBytes || !signatureBytes) return false;
4369
- return publicKeyMatchesSigner(expectedSigner, descriptorBytes, publicKeyBytes) && verifyTypedDataBytes(signatureBytes, publicKeyBytes, payload);
4436
+ return publicKeyMatchesSigner(expectedSigner, descriptorBytes, publicKeyBytes) && verifyTypedDataBytes(signatureBytes, publicKeyBytes, payload, schemeVersion);
4370
4437
  } catch {
4371
4438
  return false;
4372
4439
  }
@@ -4407,8 +4474,10 @@ export {
4407
4474
  RESTRICTED_METHODS,
4408
4475
  SCHEME_TAG_MSG,
4409
4476
  SCHEME_TAG_TYPED,
4477
+ SCHEME_TAG_TYPED_V2,
4410
4478
  SCHEME_VERSION_MSG,
4411
4479
  SCHEME_VERSION_TYPED,
4480
+ SCHEME_VERSION_TYPED_V2,
4412
4481
  SocketClient,
4413
4482
  TYPED_DATA_LIMITS,
4414
4483
  UNRESTRICTED_METHODS,
@@ -4442,6 +4511,8 @@ export {
4442
4511
  parseConnectionURI,
4443
4512
  qip55AddressFromBytes,
4444
4513
  typeHash,
4514
+ typedDataSchemeTag,
4515
+ typedDataSchemeVersion,
4445
4516
  verifyMessage,
4446
4517
  verifyMessageForSigner,
4447
4518
  verifyMessageSignature,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qrlwallet/connect",
3
- "version": "5.0.3",
3
+ "version": "5.1.1",
4
4
  "packageManager": "npm@10.9.8",
5
5
  "description": "Connect your dApp to QRL Wallet via QR code or deep link",
6
6
  "main": "dist/index.js",