Сообщение об ошибке
Invalid yParityOrV value
Также выводится как
- Error: Invalid yParityOrV value
Библиотеки ведут себя по-разному: ethers 6 нормализует значения в стиле EIP-155 (35 и выше) и без ошибок выполняет восстановление по той же подписи (это показано в воспроизведении); для других неожиданных значений, например 5, он выбрасывает «invalid v». Поэтому код, который переходит с ethers на viem, может начать падать на подписях, которые раньше проходили проверку.
viem (TypeScript) — recoverAddress / recoverMessageAddress / recoverPublicKey
Что это означает
Последний байт подписи (идентификатор восстановления) не входит в число значений, которые принимает viem: 0 или 1 (`yParity`) либо 27 или 28 (устаревший `v`). Подписи сообщений и типизированных данных всегда используют одно из них; другие значения появляются из-за соглашений, принятых при подписи транзакций, или из-за ошибок в порядке байтов. viem останавливается до восстановления.
Почему это происходит
Значение v транзакции EIP-155 использовано для сообщения
частоУстаревшие транзакции кодируют сеть в v (`chainId * 2 + 35 + yParity`, например 37/38 в основной сети). Код, который использует для сообщений вспомогательные функции подписи транзакций или берёт v из транзакции, выдаёт значения, которые viem отклоняет.
Аппаратный кошелёк или библиотека возвращает v иначе
иногдаНекоторые интеграции подписантов возвращают бит восстановления как 0/1 в отдельном поле или прибавляют 27 дважды. Тогда склеенная подпись заканчивается неожиданным байтом.
Компоненты склеены в неправильном порядке
иногдаЕсли собрать подпись как v‖r‖s (в таком виде её возвращают некоторые API), а не r‖s‖v, на месте v окажется случайный байт из s.
Как исправить
- 1.
Нормализуйте v перед восстановлением
Приведите значения EIP-155 и 0/1 к 27/28 (или к yParity 0/1) и убедитесь, что подпись собрана как r‖s‖v.
ts import { hexToNumber, numberToHex, type Hex } from "viem"; // Message signatures carry v = 27/28 (or 0/1); map EIP-155 style values back. function normaliseV(signature: Hex): Hex { let v = hexToNumber(`0x${signature.slice(130)}`); if (v >= 35) v = ((v - 35) % 2) + 27; // EIP-155: chainId * 2 + 35 + yParity if (v === 0 || v === 1) v += 27; return `${signature.slice(0, 130)}${numberToHex(v).slice(2)}` as Hex; }