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
JavaScript
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
;