@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.js CHANGED
@@ -59,8 +59,10 @@ __export(index_exports, {
59
59
  RESTRICTED_METHODS: () => RESTRICTED_METHODS,
60
60
  SCHEME_TAG_MSG: () => SCHEME_TAG_MSG,
61
61
  SCHEME_TAG_TYPED: () => SCHEME_TAG_TYPED,
62
+ SCHEME_TAG_TYPED_V2: () => SCHEME_TAG_TYPED_V2,
62
63
  SCHEME_VERSION_MSG: () => SCHEME_VERSION_MSG,
63
64
  SCHEME_VERSION_TYPED: () => SCHEME_VERSION_TYPED,
65
+ SCHEME_VERSION_TYPED_V2: () => SCHEME_VERSION_TYPED_V2,
64
66
  SocketClient: () => SocketClient,
65
67
  TYPED_DATA_LIMITS: () => TYPED_DATA_LIMITS,
66
68
  UNRESTRICTED_METHODS: () => UNRESTRICTED_METHODS,
@@ -94,6 +96,8 @@ __export(index_exports, {
94
96
  parseConnectionURI: () => parseConnectionURI,
95
97
  qip55AddressFromBytes: () => qip55AddressFromBytes,
96
98
  typeHash: () => typeHash,
99
+ typedDataSchemeTag: () => typedDataSchemeTag,
100
+ typedDataSchemeVersion: () => typedDataSchemeVersion,
97
101
  verifyMessage: () => verifyMessage,
98
102
  verifyMessageForSigner: () => verifyMessageForSigner,
99
103
  verifyMessageSignature: () => verifyMessageSignature,
@@ -566,7 +570,7 @@ function isQrlSignedTypedDataResult(value) {
566
570
  try {
567
571
  if (!isSigningResultRecord(value)) return false;
568
572
  const keys = hasOwn(value, "descriptor") ? TYPED_RESULT_KEYS_WITH_DESCRIPTOR : TYPED_RESULT_KEYS;
569
- return hasExactOwnKeys(value, keys) && value.schemeVersion === "QRL-SIGN-TYPED-v1" && isSigningResultRecord(value.domain) && hasValidSigningFields(value);
573
+ return hasExactOwnKeys(value, keys) && (value.schemeVersion === "QRL-SIGN-TYPED-v1" || value.schemeVersion === "QRL-SIGN-TYPED-v2") && isSigningResultRecord(value.domain) && hasValidSigningFields(value);
570
574
  } catch {
571
575
  return false;
572
576
  }
@@ -3081,8 +3085,10 @@ var ConnectionManager = _ConnectionManager;
3081
3085
  // src/signing/ctx.ts
3082
3086
  var SCHEME_VERSION_MSG = "QRL-SIGN-MSG-v1";
3083
3087
  var SCHEME_VERSION_TYPED = "QRL-SIGN-TYPED-v1";
3088
+ var SCHEME_VERSION_TYPED_V2 = "QRL-SIGN-TYPED-v2";
3084
3089
  var SCHEME_TAG_MSG = new TextEncoder().encode(SCHEME_VERSION_MSG);
3085
3090
  var SCHEME_TAG_TYPED = new TextEncoder().encode(SCHEME_VERSION_TYPED);
3091
+ var SCHEME_TAG_TYPED_V2 = new TextEncoder().encode(SCHEME_VERSION_TYPED_V2);
3086
3092
  var DIGEST_LEN = 64;
3087
3093
 
3088
3094
  // src/signing/bytes.ts
@@ -3122,7 +3128,14 @@ function concatBytesArr(parts) {
3122
3128
  }
3123
3129
 
3124
3130
  // src/signing/typedData.ts
3125
- var SLOT = 32;
3131
+ var SLOT_BYTES = Object.freeze({
3132
+ [SCHEME_VERSION_TYPED]: 32,
3133
+ [SCHEME_VERSION_TYPED_V2]: 64
3134
+ });
3135
+ var SCHEME_TAGS = Object.freeze({
3136
+ [SCHEME_VERSION_TYPED]: SCHEME_TAG_TYPED,
3137
+ [SCHEME_VERSION_TYPED_V2]: SCHEME_TAG_TYPED_V2
3138
+ });
3126
3139
  var TYPED_DATA_LIMITS = Object.freeze({
3127
3140
  maxTypes: 32,
3128
3141
  maxFieldsPerType: 32,
@@ -3174,21 +3187,30 @@ function parsePayload(payload) {
3174
3187
  var ATOMIC_RE = /^(?:(address|bool|string|bytes)|(u?int)(\d+)|bytes(\d+)|(.+?)\[(\d*)\])$/;
3175
3188
  var IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
3176
3189
  var UNSAFE_OBJECT_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
3190
+ function newBudget(schemeVersion) {
3191
+ return {
3192
+ remainingValues: TYPED_DATA_LIMITS.maxEncodedValues,
3193
+ slot: SLOT_BYTES[schemeVersion]
3194
+ };
3195
+ }
3177
3196
  function consumeValue(budget) {
3178
3197
  budget.remainingValues--;
3179
3198
  if (budget.remainingValues < 0) throw new Error("typed data contains too many encoded values");
3180
3199
  }
3200
+ function inputPreview(value) {
3201
+ return value.length > 32 ? `${value.slice(0, 32)}... (length ${value.length})` : value;
3202
+ }
3181
3203
  function assertIdentifier(value, label) {
3182
3204
  if (!IDENTIFIER_RE.test(value) || value.length > TYPED_DATA_LIMITS.maxIdentifierLength || UNSAFE_OBJECT_KEYS.has(value)) {
3183
- throw new Error(`invalid ${label}: ${value}`);
3205
+ throw new Error(`invalid ${label}: ${inputPreview(value)}`);
3184
3206
  }
3185
3207
  }
3186
3208
  function parseFieldType(type, types, depth = 0) {
3187
3209
  if (depth > TYPED_DATA_LIMITS.maxArrayNesting) {
3188
- throw new Error(`type nesting too deep: ${type}`);
3210
+ throw new Error(`type nesting too deep: ${inputPreview(type)}`);
3189
3211
  }
3190
3212
  if (type.length > TYPED_DATA_LIMITS.maxFieldTypeLength) {
3191
- throw new Error(`field type too long: ${type}`);
3213
+ throw new Error(`field type too long: ${inputPreview(type)}`);
3192
3214
  }
3193
3215
  const m = ATOMIC_RE.exec(type);
3194
3216
  if (m) {
@@ -3199,14 +3221,14 @@ function parseFieldType(type, types, depth = 0) {
3199
3221
  if (intKind) {
3200
3222
  const width = Number(intWidthStr);
3201
3223
  if (!Number.isInteger(width) || width < 8 || width > 256 || width % 8 !== 0) {
3202
- throw new Error(`invalid int width: ${type}`);
3224
+ throw new Error(`invalid int width: ${inputPreview(type)}`);
3203
3225
  }
3204
3226
  return { kind: intKind === "uint" ? "uintN" : "intN", width };
3205
3227
  }
3206
3228
  if (bytesWidthStr) {
3207
3229
  const width = Number(bytesWidthStr);
3208
3230
  if (!Number.isInteger(width) || width < 1 || width > 32) {
3209
- throw new Error(`invalid bytesN width: ${type}`);
3231
+ throw new Error(`invalid bytesN width: ${inputPreview(type)}`);
3210
3232
  }
3211
3233
  return { kind: "bytesN", width };
3212
3234
  }
@@ -3215,7 +3237,7 @@ function parseFieldType(type, types, depth = 0) {
3215
3237
  if (sizeStr) {
3216
3238
  const size = Number(sizeStr);
3217
3239
  if (!Number.isSafeInteger(size) || size <= 0 || size > TYPED_DATA_LIMITS.maxArrayLength) {
3218
- throw new Error(`invalid array size: ${type}`);
3240
+ throw new Error(`invalid array size: ${inputPreview(type)}`);
3219
3241
  }
3220
3242
  return { kind: "array", inner: innerType, size };
3221
3243
  }
@@ -3225,7 +3247,7 @@ function parseFieldType(type, types, depth = 0) {
3225
3247
  if (Object.prototype.hasOwnProperty.call(types, type)) {
3226
3248
  return { kind: "ref", name: type };
3227
3249
  }
3228
- throw new Error(`unknown type: ${type}`);
3250
+ throw new Error(`unknown type: ${inputPreview(type)}`);
3229
3251
  }
3230
3252
  function isReservedAtomicTypeName(name) {
3231
3253
  if (/^(?:address|bool|string|bytes)$/.test(name)) return true;
@@ -3242,24 +3264,35 @@ function isReservedAtomicTypeName(name) {
3242
3264
  return false;
3243
3265
  }
3244
3266
  function baseTypeName(type) {
3245
- return type.replace(/(\[\d*\])+$/, "");
3267
+ let end = type.length;
3268
+ while (end > 0 && type[end - 1] === "]") {
3269
+ let start = end - 2;
3270
+ while (start >= 0) {
3271
+ const code = type.charCodeAt(start);
3272
+ if (code < 48 || code > 57) break;
3273
+ start--;
3274
+ }
3275
+ if (start < 0 || type[start] !== "[") break;
3276
+ end = start;
3277
+ }
3278
+ return type.slice(0, end);
3246
3279
  }
3247
3280
  function collectDependencies(primary, types) {
3248
3281
  if (!Object.prototype.hasOwnProperty.call(types, primary)) {
3249
- throw new Error(`unknown primary type: ${primary}`);
3282
+ throw new Error(`unknown primary type: ${inputPreview(primary)}`);
3250
3283
  }
3251
3284
  const visited = /* @__PURE__ */ new Set();
3252
3285
  const visit = (name, path) => {
3253
3286
  if (path.length > TYPED_DATA_LIMITS.maxTypeGraphDepth) {
3254
- throw new Error(`type graph nesting too deep: ${[...path, name].join(" -> ")}`);
3287
+ throw new Error(`type graph nesting too deep: ${inputPreview([...path, name].join(" -> "))}`);
3255
3288
  }
3256
3289
  if (path.includes(name)) {
3257
- throw new Error(`cyclic type reference: ${[...path, name].join(" -> ")}`);
3290
+ throw new Error(`cyclic type reference: ${inputPreview([...path, name].join(" -> "))}`);
3258
3291
  }
3259
3292
  if (visited.has(name)) return;
3260
3293
  visited.add(name);
3261
3294
  const def = types[name];
3262
- if (!def) throw new Error(`unknown type: ${name}`);
3295
+ if (!def) throw new Error(`unknown type: ${inputPreview(name)}`);
3263
3296
  for (const f of def) {
3264
3297
  const base = baseTypeName(f.type);
3265
3298
  if (Object.prototype.hasOwnProperty.call(types, base)) {
@@ -3280,11 +3313,11 @@ function validateTypeMap(types) {
3280
3313
  for (const [name, def] of entries) {
3281
3314
  assertIdentifier(name, "struct name");
3282
3315
  if (name !== "QRLDomain" && isReservedAtomicTypeName(name)) {
3283
- throw new Error(`struct name is reserved by an atomic type: ${name}`);
3316
+ throw new Error(`struct name is reserved by an atomic type: ${inputPreview(name)}`);
3284
3317
  }
3285
3318
  const defUnknown = def;
3286
3319
  if (!Array.isArray(defUnknown) || def.length === 0 || def.length > TYPED_DATA_LIMITS.maxFieldsPerType) {
3287
- throw new Error(`empty or invalid struct: ${name}`);
3320
+ throw new Error(`empty or invalid struct: ${inputPreview(name)}`);
3288
3321
  }
3289
3322
  totalFields += def.length;
3290
3323
  if (totalFields > TYPED_DATA_LIMITS.maxTotalFields) {
@@ -3293,14 +3326,17 @@ function validateTypeMap(types) {
3293
3326
  const seen = /* @__PURE__ */ new Set();
3294
3327
  for (const f of def) {
3295
3328
  if (!f || typeof f.name !== "string" || !f.name) {
3296
- throw new Error(`bad field in ${name}`);
3329
+ throw new Error(`bad field in ${inputPreview(name)}`);
3297
3330
  }
3298
- assertIdentifier(f.name, `field name in ${name}`);
3331
+ assertIdentifier(f.name, `field name in ${inputPreview(name)}`);
3299
3332
  if (typeof f.type !== "string" || !f.type) {
3300
- throw new Error(`bad field type in ${name}.${f.name}`);
3333
+ throw new Error(`bad field type in ${inputPreview(name)}.${inputPreview(f.name)}`);
3334
+ }
3335
+ if (f.type.length > TYPED_DATA_LIMITS.maxFieldTypeLength) {
3336
+ throw new Error(`field type too long: ${inputPreview(f.type)}`);
3301
3337
  }
3302
3338
  if (seen.has(f.name)) {
3303
- throw new Error(`duplicate field "${f.name}" in ${name}`);
3339
+ throw new Error(`duplicate field "${inputPreview(f.name)}" in ${inputPreview(name)}`);
3304
3340
  }
3305
3341
  seen.add(f.name);
3306
3342
  }
@@ -3312,7 +3348,7 @@ function encodeType(primary, types) {
3312
3348
  const others = [...deps].filter((n) => n !== primary).sort();
3313
3349
  return [primary, ...others].map((name) => {
3314
3350
  const fields = types[name];
3315
- if (!fields) throw new Error(`unknown type: ${name}`);
3351
+ if (!fields) throw new Error(`unknown type: ${inputPreview(name)}`);
3316
3352
  const inner = fields.map((f) => `${f.type} ${f.name}`).join(",");
3317
3353
  return `${name}(${inner})`;
3318
3354
  }).join("");
@@ -3320,44 +3356,46 @@ function encodeType(primary, types) {
3320
3356
  function typeHash(primary, types) {
3321
3357
  return shake256Digest(new TextEncoder().encode(encodeType(primary, types)), DIGEST_LEN);
3322
3358
  }
3323
- function parseQAddress(addr) {
3359
+ function parseQAddress(addr, slot) {
3324
3360
  if (!isCurrentQrlAddress(addr)) {
3325
- throw new Error(`invalid Q-address: ${String(addr)}`);
3361
+ throw new Error(`invalid Q-address: ${inputPreview(String(addr))}`);
3326
3362
  }
3327
3363
  const bytes = hexToBytes("0x" + addr.slice(1).toLowerCase());
3328
- if (bytes.length > SLOT) {
3364
+ if (bytes.length > slot) {
3329
3365
  throw new Error("qrl_signTypedData v1 does not support QIP-55 address fields");
3330
3366
  }
3331
3367
  return bytes;
3332
3368
  }
3333
- function padLeft32(bytes) {
3334
- if (bytes.length > SLOT) throw new Error("cannot pad: bytes > 32");
3335
- const out = new Uint8Array(SLOT);
3336
- out.set(bytes, SLOT - bytes.length);
3369
+ function padLeft(bytes, slot) {
3370
+ if (bytes.length > slot) throw new Error(`cannot pad: bytes > ${slot}`);
3371
+ const out = new Uint8Array(slot);
3372
+ out.set(bytes, slot - bytes.length);
3337
3373
  return out;
3338
3374
  }
3339
- function padRight32(bytes) {
3340
- if (bytes.length > SLOT) throw new Error("cannot pad: bytes > 32");
3341
- const out = new Uint8Array(SLOT);
3375
+ function padRight(bytes, slot) {
3376
+ if (bytes.length > slot) throw new Error(`cannot pad: bytes > ${slot}`);
3377
+ const out = new Uint8Array(slot);
3342
3378
  out.set(bytes, 0);
3343
3379
  return out;
3344
3380
  }
3345
- function bigIntToSlot(value, width, signed) {
3381
+ function bigIntToSlot(value, width, signed, slot) {
3346
3382
  if (signed) {
3347
3383
  const limit = 1n << BigInt(width - 1);
3348
3384
  if (value >= limit || value < -limit) {
3349
- throw new Error(`int${width} out of range: ${value}`);
3385
+ throw new Error(`int${width} out of range: ${inputPreview(String(value))}`);
3350
3386
  }
3351
3387
  } else {
3352
- if (value < 0n) throw new Error(`uint${width} negative: ${value}`);
3388
+ if (value < 0n) throw new Error(`uint${width} negative: ${inputPreview(String(value))}`);
3353
3389
  const limit = 1n << BigInt(width);
3354
- if (value >= limit) throw new Error(`uint${width} out of range: ${value}`);
3390
+ if (value >= limit)
3391
+ throw new Error(`uint${width} out of range: ${inputPreview(String(value))}`);
3355
3392
  }
3356
- const slotMask = (1n << 256n) - 1n;
3357
- const repr = value < 0n ? value + (1n << 256n) & slotMask : value;
3358
- const out = new Uint8Array(SLOT);
3393
+ const slotBits = BigInt(slot * 8);
3394
+ const slotMask = (1n << slotBits) - 1n;
3395
+ const repr = value < 0n ? value + (1n << slotBits) & slotMask : value;
3396
+ const out = new Uint8Array(slot);
3359
3397
  let v = repr;
3360
- for (let i = SLOT - 1; i >= 0; i--) {
3398
+ for (let i = slot - 1; i >= 0; i--) {
3361
3399
  out[i] = Number(v & 0xffn);
3362
3400
  v >>= 8n;
3363
3401
  }
@@ -3373,7 +3411,7 @@ function parseIntValue(v, typeLabel) {
3373
3411
  return isNegative ? -abs : abs;
3374
3412
  }
3375
3413
  if (!/^-?(0|[1-9]\d*)$/.test(v)) {
3376
- throw new Error(`invalid ${typeLabel} string: ${v}`);
3414
+ throw new Error(`invalid ${typeLabel} string: ${inputPreview(v)}`);
3377
3415
  }
3378
3416
  return BigInt(v);
3379
3417
  }
@@ -3387,26 +3425,26 @@ function parseIntValue(v, typeLabel) {
3387
3425
  }
3388
3426
  function encodeFieldWithBudget(type, value, types, budget, depth) {
3389
3427
  if (depth > TYPED_DATA_LIMITS.maxTypeGraphDepth + TYPED_DATA_LIMITS.maxArrayNesting) {
3390
- throw new Error(`value nesting too deep: ${type}`);
3428
+ throw new Error(`value nesting too deep: ${inputPreview(type)}`);
3391
3429
  }
3392
3430
  consumeValue(budget);
3393
3431
  const parsed = parseFieldType(type, types);
3394
3432
  switch (parsed.kind) {
3395
3433
  case "ref":
3396
3434
  if (!isMessageObject(value)) {
3397
- throw new Error(`struct field expects object: ${type}`);
3435
+ throw new Error(`struct field expects object: ${inputPreview(type)}`);
3398
3436
  }
3399
3437
  return hashStructWithBudget(parsed.name, value, types, budget, depth + 1);
3400
3438
  case "address":
3401
3439
  if (typeof value !== "string") {
3402
3440
  throw new Error(`address field expects string: ${typeof value}`);
3403
3441
  }
3404
- return padLeft32(parseQAddress(value));
3442
+ return padLeft(parseQAddress(value, budget.slot), budget.slot);
3405
3443
  case "bool":
3406
3444
  if (typeof value !== "boolean") {
3407
3445
  throw new Error(`bool field expects boolean: ${typeof value}`);
3408
3446
  }
3409
- return padLeft32(new Uint8Array([value ? 1 : 0]));
3447
+ return padLeft(new Uint8Array([value ? 1 : 0]), budget.slot);
3410
3448
  case "string": {
3411
3449
  if (typeof value !== "string") {
3412
3450
  throw new Error(`string field expects string: ${typeof value}`);
@@ -3429,9 +3467,19 @@ function encodeFieldWithBudget(type, value, types, budget, depth) {
3429
3467
  }
3430
3468
  return shake256Digest(hexToBytes(value), DIGEST_LEN);
3431
3469
  case "uintN":
3432
- return bigIntToSlot(parseIntValue(value, `uint${parsed.width}`), parsed.width, false);
3470
+ return bigIntToSlot(
3471
+ parseIntValue(value, `uint${parsed.width}`),
3472
+ parsed.width,
3473
+ false,
3474
+ budget.slot
3475
+ );
3433
3476
  case "intN":
3434
- return bigIntToSlot(parseIntValue(value, `int${parsed.width}`), parsed.width, true);
3477
+ return bigIntToSlot(
3478
+ parseIntValue(value, `int${parsed.width}`),
3479
+ parsed.width,
3480
+ true,
3481
+ budget.slot
3482
+ );
3435
3483
  case "bytesN": {
3436
3484
  if (typeof value !== "string") {
3437
3485
  throw new Error(`bytes${parsed.width} expects 0x-hex string: ${typeof value}`);
@@ -3443,17 +3491,19 @@ function encodeFieldWithBudget(type, value, types, budget, depth) {
3443
3491
  if (raw.length !== parsed.width) {
3444
3492
  throw new Error(`bytes${parsed.width} requires ${parsed.width} bytes, got ${raw.length}`);
3445
3493
  }
3446
- return padRight32(raw);
3494
+ return padRight(raw, budget.slot);
3447
3495
  }
3448
3496
  case "array": {
3449
3497
  if (!Array.isArray(value)) {
3450
3498
  throw new Error(`array field expects array: ${typeof value}`);
3451
3499
  }
3452
3500
  if (value.length > TYPED_DATA_LIMITS.maxArrayLength) {
3453
- throw new Error(`array ${type} exceeds length limit`);
3501
+ throw new Error(`array ${inputPreview(type)} exceeds length limit`);
3454
3502
  }
3455
3503
  if (parsed.size !== void 0 && value.length !== parsed.size) {
3456
- throw new Error(`fixed array ${type} requires length ${parsed.size}, got ${value.length}`);
3504
+ throw new Error(
3505
+ `fixed array ${inputPreview(type)} requires length ${parsed.size}, got ${value.length}`
3506
+ );
3457
3507
  }
3458
3508
  const chunks = value.map(
3459
3509
  (v) => encodeFieldWithBudget(parsed.inner, v, types, budget, depth + 1)
@@ -3462,20 +3512,15 @@ function encodeFieldWithBudget(type, value, types, budget, depth) {
3462
3512
  }
3463
3513
  }
3464
3514
  }
3465
- function encodeField(type, value, types) {
3515
+ function encodeField(type, value, types, schemeVersion) {
3466
3516
  validateTypeMap(types);
3467
- return encodeFieldWithBudget(
3468
- type,
3469
- value,
3470
- types,
3471
- { remainingValues: TYPED_DATA_LIMITS.maxEncodedValues },
3472
- 0
3473
- );
3517
+ const scheme = schemeVersion ?? schemeVersionForTypes(types);
3518
+ return encodeFieldWithBudget(type, value, types, newBudget(scheme), 0);
3474
3519
  }
3475
3520
  function hashStructWithBudget(primary, data, types, budget, depth) {
3476
3521
  consumeValue(budget);
3477
3522
  const fields = types[primary];
3478
- if (!fields) throw new Error(`unknown struct: ${primary}`);
3523
+ if (!fields) throw new Error(`unknown struct: ${inputPreview(primary)}`);
3479
3524
  const expected = new Set(fields.map((f) => f.name));
3480
3525
  let ownFieldCount = 0;
3481
3526
  for (const k in data) {
@@ -3484,26 +3529,23 @@ function hashStructWithBudget(primary, data, types, budget, depth) {
3484
3529
  if (ownFieldCount > TYPED_DATA_LIMITS.maxEncodedValues) {
3485
3530
  throw new Error("typed data object contains too many fields");
3486
3531
  }
3487
- if (!expected.has(k)) throw new Error(`unknown field in ${primary}: ${k}`);
3532
+ if (!expected.has(k)) {
3533
+ throw new Error(`unknown field in ${inputPreview(primary)}: ${inputPreview(k)}`);
3534
+ }
3488
3535
  }
3489
3536
  const parts = [typeHash(primary, types)];
3490
3537
  for (const f of fields) {
3491
3538
  if (!Object.prototype.hasOwnProperty.call(data, f.name)) {
3492
- throw new Error(`missing field ${primary}.${f.name}`);
3539
+ throw new Error(`missing field ${inputPreview(primary)}.${inputPreview(f.name)}`);
3493
3540
  }
3494
3541
  parts.push(encodeFieldWithBudget(f.type, data[f.name], types, budget, depth + 1));
3495
3542
  }
3496
3543
  return shake256Digest(concatBytesArr(parts), DIGEST_LEN);
3497
3544
  }
3498
- function hashStruct(primary, data, types) {
3545
+ function hashStruct(primary, data, types, schemeVersion) {
3499
3546
  validateTypeMap(types);
3500
- return hashStructWithBudget(
3501
- primary,
3502
- data,
3503
- types,
3504
- { remainingValues: TYPED_DATA_LIMITS.maxEncodedValues },
3505
- 0
3506
- );
3547
+ const scheme = schemeVersion ?? schemeVersionForTypes(types);
3548
+ return hashStructWithBudget(primary, data, types, newBudget(scheme), 0);
3507
3549
  }
3508
3550
  var RESERVED_DOMAIN_FIELDS = {
3509
3551
  name: "string",
@@ -3520,11 +3562,13 @@ function validateDomainTypes(types) {
3520
3562
  const expected = RESERVED_DOMAIN_FIELDS[f.name];
3521
3563
  if (!expected) {
3522
3564
  throw new Error(
3523
- `QRLDomain field "${f.name}" not in reserved set (name, version, chainId, verifyingContract, salt)`
3565
+ `QRLDomain field "${inputPreview(f.name)}" not in reserved set (name, version, chainId, verifyingContract, salt)`
3524
3566
  );
3525
3567
  }
3526
3568
  if (f.type !== expected) {
3527
- throw new Error(`QRLDomain field "${f.name}" must be type "${expected}", got "${f.type}"`);
3569
+ throw new Error(
3570
+ `QRLDomain field "${inputPreview(f.name)}" must be type "${expected}", got "${inputPreview(f.type)}"`
3571
+ );
3528
3572
  }
3529
3573
  if (f.name === "name") hasName = true;
3530
3574
  }
@@ -3536,10 +3580,10 @@ function validatePayloadReachability(primary, types) {
3536
3580
  for (const t of collectDependencies(root, types)) reachable.add(t);
3537
3581
  }
3538
3582
  for (const k of Object.keys(types)) {
3539
- if (!reachable.has(k)) throw new Error(`unused referenced type: ${k}`);
3583
+ if (!reachable.has(k)) throw new Error(`unused referenced type: ${inputPreview(k)}`);
3540
3584
  }
3541
3585
  }
3542
- function computeTypedDataDigest(payload) {
3586
+ function parseAndValidatePayload(payload) {
3543
3587
  const parsed = parsePayload(payload);
3544
3588
  validateTypeMap(parsed.types);
3545
3589
  assertIdentifier(parsed.primaryType, "primary type");
@@ -3548,7 +3592,26 @@ function computeTypedDataDigest(payload) {
3548
3592
  }
3549
3593
  validateDomainTypes(parsed.types);
3550
3594
  validatePayloadReachability(parsed.primaryType, parsed.types);
3551
- const budget = { remainingValues: TYPED_DATA_LIMITS.maxEncodedValues };
3595
+ return parsed;
3596
+ }
3597
+ function schemeVersionForTypes(types) {
3598
+ for (const fields of Object.values(types)) {
3599
+ if (fields.some((f) => baseTypeName(f.type) === "address")) {
3600
+ return SCHEME_VERSION_TYPED_V2;
3601
+ }
3602
+ }
3603
+ return SCHEME_VERSION_TYPED;
3604
+ }
3605
+ function typedDataSchemeVersion(payload) {
3606
+ return schemeVersionForTypes(parseAndValidatePayload(payload).types);
3607
+ }
3608
+ function typedDataSchemeTag(schemeVersion) {
3609
+ return SCHEME_TAGS[schemeVersion];
3610
+ }
3611
+ function computeTypedDataDigest(payload) {
3612
+ const parsed = parseAndValidatePayload(payload);
3613
+ const schemeVersion = schemeVersionForTypes(parsed.types);
3614
+ const budget = newBudget(schemeVersion);
3552
3615
  const domainHash = hashStructWithBudget("QRLDomain", parsed.domain, parsed.types, budget, 0);
3553
3616
  const messageHash = hashStructWithBudget(
3554
3617
  parsed.primaryType,
@@ -3557,7 +3620,10 @@ function computeTypedDataDigest(payload) {
3557
3620
  budget,
3558
3621
  0
3559
3622
  );
3560
- return shake256Digest(concatBytes(SCHEME_TAG_TYPED, domainHash, messageHash), DIGEST_LEN);
3623
+ return shake256Digest(
3624
+ concatBytes(SCHEME_TAGS[schemeVersion], domainHash, messageHash),
3625
+ DIGEST_LEN
3626
+ );
3561
3627
  }
3562
3628
 
3563
3629
  // src/utils/platform.ts
@@ -3749,9 +3815,8 @@ function validateRestrictedRequest(method, params, authorizedAccounts, currentCh
3749
3815
  if (params[0] !== authorizedAccount) {
3750
3816
  throw new Error("qrl_signTypedData signer is not the authorized account");
3751
3817
  }
3752
- throw new Error(
3753
- "qrl_signTypedData is unavailable for QIP-55 until the 64-byte word encoding and signing scheme version are finalized"
3754
- );
3818
+ computeTypedDataDigest(params[1]);
3819
+ return void 0;
3755
3820
  }
3756
3821
  function requiresAuthorizedAccount(method) {
3757
3822
  return method === "qrl_sendTransaction" || method === "qrl_signTransaction" || method === "qrl_signMessage" || method === "qrl_signTypedData";
@@ -4397,9 +4462,13 @@ function verifyMessageBytes(signature, publicKey, messageBytes) {
4397
4462
  const digest = computeMessageDigest(messageBytes);
4398
4463
  return mldsaVerify(signature, digest, publicKey, SCHEME_TAG_MSG);
4399
4464
  }
4400
- function verifyTypedDataBytes(signature, publicKey, payload) {
4465
+ function verifyTypedDataBytes(signature, publicKey, payload, claimedSchemeVersion) {
4466
+ const schemeVersion = typedDataSchemeVersion(payload);
4467
+ if (claimedSchemeVersion !== void 0 && claimedSchemeVersion !== schemeVersion) {
4468
+ return false;
4469
+ }
4401
4470
  const digest = computeTypedDataDigest(payload);
4402
- return mldsaVerify(signature, digest, publicKey, SCHEME_TAG_TYPED);
4471
+ return mldsaVerify(signature, digest, publicKey, typedDataSchemeTag(schemeVersion));
4403
4472
  }
4404
4473
  function verifyMessageSignature({
4405
4474
  signature,
@@ -4419,13 +4488,14 @@ function verifyMessageSignature({
4419
4488
  function verifyTypedDataSignature({
4420
4489
  signature,
4421
4490
  publicKey,
4422
- payload
4491
+ payload,
4492
+ schemeVersion
4423
4493
  }) {
4424
4494
  try {
4425
4495
  const sig = fixedBytesOrHex(signature, ML_DSA_87_SIGNATURE_BYTES);
4426
4496
  const pk = fixedBytesOrHex(publicKey, ML_DSA_87_PUBLIC_KEY_BYTES);
4427
4497
  if (!sig || !pk) return false;
4428
- return verifyTypedDataBytes(sig, pk, payload);
4498
+ return verifyTypedDataBytes(sig, pk, payload, schemeVersion);
4429
4499
  } catch {
4430
4500
  return false;
4431
4501
  }
@@ -4463,7 +4533,8 @@ function verifyTypedDataForSigner({
4463
4533
  descriptor,
4464
4534
  signature,
4465
4535
  publicKey,
4466
- payload
4536
+ payload,
4537
+ schemeVersion
4467
4538
  }) {
4468
4539
  try {
4469
4540
  if (descriptor === void 0) return false;
@@ -4471,7 +4542,7 @@ function verifyTypedDataForSigner({
4471
4542
  const publicKeyBytes = fixedBytesOrHex(publicKey, ML_DSA_87_PUBLIC_KEY_BYTES);
4472
4543
  const signatureBytes = fixedBytesOrHex(signature, ML_DSA_87_SIGNATURE_BYTES);
4473
4544
  if (!descriptorBytes || !publicKeyBytes || !signatureBytes) return false;
4474
- return publicKeyMatchesSigner(expectedSigner, descriptorBytes, publicKeyBytes) && verifyTypedDataBytes(signatureBytes, publicKeyBytes, payload);
4545
+ return publicKeyMatchesSigner(expectedSigner, descriptorBytes, publicKeyBytes) && verifyTypedDataBytes(signatureBytes, publicKeyBytes, payload, schemeVersion);
4475
4546
  } catch {
4476
4547
  return false;
4477
4548
  }
@@ -4513,8 +4584,10 @@ function verifyTypedData(params) {
4513
4584
  RESTRICTED_METHODS,
4514
4585
  SCHEME_TAG_MSG,
4515
4586
  SCHEME_TAG_TYPED,
4587
+ SCHEME_TAG_TYPED_V2,
4516
4588
  SCHEME_VERSION_MSG,
4517
4589
  SCHEME_VERSION_TYPED,
4590
+ SCHEME_VERSION_TYPED_V2,
4518
4591
  SocketClient,
4519
4592
  TYPED_DATA_LIMITS,
4520
4593
  UNRESTRICTED_METHODS,
@@ -4548,6 +4621,8 @@ function verifyTypedData(params) {
4548
4621
  parseConnectionURI,
4549
4622
  qip55AddressFromBytes,
4550
4623
  typeHash,
4624
+ typedDataSchemeTag,
4625
+ typedDataSchemeVersion,
4551
4626
  verifyMessage,
4552
4627
  verifyMessageForSigner,
4553
4628
  verifyMessageSignature,