UNPKG

eip-712

Version:

Tiny library with utility functions that can help with signing and verifying EIP-712 based messages

152 lines (113 loc) 4.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.asArray = exports.getMessage = exports.getStructHash = exports.encodeData = exports.getTypeHash = exports.encodeType = exports.getDependencies = void 0; var _options = require("./options"); var _types = require("./types"); var _utils = require("./utils"); const EIP_191_PREFIX = Buffer.from('1901', 'hex'); const getDependencies = (typedData, type, options, dependencies = []) => { if (!(0, _utils.validateTypedData)(typedData, options)) { throw new Error('Typed data does not match JSON schema'); } const match = type.match(_types.TYPE_REGEX); const actualType = match[0]; if (dependencies.includes(actualType)) { return dependencies; } if (!typedData.types[actualType]) { return dependencies; } return [actualType, ...typedData.types[actualType].reduce((previous, type) => [...previous, ...getDependencies(typedData, type.type, options, previous).filter(dependency => !previous.includes(dependency))], [])]; }; exports.getDependencies = getDependencies; const encodeType = (typedData, type, options) => { const [primary, ...dependencies] = getDependencies(typedData, type, options); const types = [primary, ...dependencies.sort()]; return types.map(dependency => { return `${dependency}(${typedData.types[dependency].map(type => `${type.type} ${type.name}`)})`; }).join(''); }; exports.encodeType = encodeType; const getTypeHash = (typedData, type, options) => { return (0, _utils.keccak256)(encodeType(typedData, type, options), 'utf8'); }; exports.getTypeHash = getTypeHash; const encodeValue = (typedData, type, data, options) => { const match = type.match(_types.ARRAY_REGEX); if (match) { const arrayType = match[1]; const length = Number(match[2]) || undefined; if (!Array.isArray(data)) { throw new Error('Cannot encode data: value is not of array type'); } if (length && data.length !== length) { throw new Error(`Cannot encode data: expected length of ${length}, but got ${data.length}`); } const encodedData = data.map(item => encodeValue(typedData, arrayType, item, options)); const types = encodedData.map(item => item[0]); const values = encodedData.map(item => item[1]); return ['bytes32', (0, _utils.keccak256)((0, _utils.encode)(types, values))]; } if (typedData.types[type]) { return ['bytes32', getStructHash(typedData, type, data, options)]; } if (type === 'string') { return ['bytes32', (0, _utils.keccak256)(data, 'utf8')]; } if (type === 'bytes') { return ['bytes32', (0, _utils.keccak256)(Buffer.isBuffer(data) ? data : (0, _utils.toBuffer)(data), 'hex')]; } return [type, data]; }; const encodeData = (typedData, type, data, options) => { const [types, values] = typedData.types[type].reduce(([types, values], field) => { if (data[field.name] === undefined || data[field.name] === null) { throw new Error(`Cannot encode data: missing data for '${field.name}'`); } const value = data[field.name]; const [type, encodedValue] = encodeValue(typedData, field.type, value, options); return [[...types, type], [...values, encodedValue]]; }, [['bytes32'], [getTypeHash(typedData, type, options)]]); return (0, _utils.encode)(types, values); }; exports.encodeData = encodeData; const getStructHash = (typedData, type, data, options) => { return (0, _utils.keccak256)(encodeData(typedData, type, data, options)); }; exports.getStructHash = getStructHash; const getMessage = (typedData, hash, options) => { const { domain } = (0, _options.getOptions)(options); const message = Buffer.concat([EIP_191_PREFIX, getStructHash(typedData, domain, typedData.domain, options), getStructHash(typedData, typedData.primaryType, typedData.message, options)]); if (hash) { return (0, _utils.keccak256)(message); } return message; }; exports.getMessage = getMessage; const asArray = (typedData, type = typedData.primaryType, data = typedData.message, options) => { if (!(0, _utils.validateTypedData)(typedData, options)) { throw new Error('Typed data does not match JSON schema'); } if (!typedData.types[type]) { throw new Error('Cannot get data as array: type does not exist'); } return typedData.types[type].reduce((array, { name, type }) => { if (typedData.types[type]) { if (!data[name]) { throw new Error(`Cannot get data as array: missing data for '${name}'`); } return [...array, asArray(typedData, type, data[name], options)]; } const value = data[name]; return [...array, value]; }, []); }; exports.asArray = asArray; //# sourceMappingURL=eip-712.js.map