@ethersproject/hash
Advanced tools
Comparing version 5.6.0 to 6.0.0-beta.1
@@ -1,2 +0,2 @@ | ||
export declare const version = "hash/5.6.0"; | ||
export declare const version = "@ethersproject/hash@6.0.0-beta.1"; | ||
//# sourceMappingURL=_version.d.ts.map |
@@ -1,5 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.version = void 0; | ||
exports.version = "hash/5.6.0"; | ||
export const version = "@ethersproject/hash@6.0.0-beta.1"; | ||
//# sourceMappingURL=_version.js.map |
@@ -1,2 +0,2 @@ | ||
export declare function id(text: string): string; | ||
export declare function id(value: string): string; | ||
//# sourceMappingURL=id.d.ts.map |
@@ -1,10 +0,6 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.id = void 0; | ||
var keccak256_1 = require("@ethersproject/keccak256"); | ||
var strings_1 = require("@ethersproject/strings"); | ||
function id(text) { | ||
return (0, keccak256_1.keccak256)((0, strings_1.toUtf8Bytes)(text)); | ||
import { keccak256 } from "@ethersproject/crypto"; | ||
import { toUtf8Bytes } from "@ethersproject/strings"; | ||
export function id(value) { | ||
return keccak256(toUtf8Bytes(value)); | ||
} | ||
exports.id = id; | ||
//# sourceMappingURL=id.js.map |
@@ -1,6 +0,6 @@ | ||
import { id } from "./id"; | ||
import { dnsEncode, isValidName, namehash } from "./namehash"; | ||
import { hashMessage, messagePrefix } from "./message"; | ||
import { TypedDataEncoder as _TypedDataEncoder } from "./typed-data"; | ||
export { id, dnsEncode, namehash, isValidName, messagePrefix, hashMessage, _TypedDataEncoder, }; | ||
export { id } from "./id.js"; | ||
export { isValidName, namehash, dnsEncode } from "./namehash.js"; | ||
export { messagePrefix, hashMessage } from "./message.js"; | ||
export { TypedDataEncoder } from "./typed-data.js"; | ||
export type { TypedDataDomain, TypedDataField } from "./typed-data.js"; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,15 +0,5 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports._TypedDataEncoder = exports.hashMessage = exports.messagePrefix = exports.isValidName = exports.namehash = exports.dnsEncode = exports.id = void 0; | ||
var id_1 = require("./id"); | ||
Object.defineProperty(exports, "id", { enumerable: true, get: function () { return id_1.id; } }); | ||
var namehash_1 = require("./namehash"); | ||
Object.defineProperty(exports, "dnsEncode", { enumerable: true, get: function () { return namehash_1.dnsEncode; } }); | ||
Object.defineProperty(exports, "isValidName", { enumerable: true, get: function () { return namehash_1.isValidName; } }); | ||
Object.defineProperty(exports, "namehash", { enumerable: true, get: function () { return namehash_1.namehash; } }); | ||
var message_1 = require("./message"); | ||
Object.defineProperty(exports, "hashMessage", { enumerable: true, get: function () { return message_1.hashMessage; } }); | ||
Object.defineProperty(exports, "messagePrefix", { enumerable: true, get: function () { return message_1.messagePrefix; } }); | ||
var typed_data_1 = require("./typed-data"); | ||
Object.defineProperty(exports, "_TypedDataEncoder", { enumerable: true, get: function () { return typed_data_1.TypedDataEncoder; } }); | ||
export { id } from "./id.js"; | ||
export { isValidName, namehash, dnsEncode } from "./namehash.js"; | ||
export { messagePrefix, hashMessage } from "./message.js"; | ||
export { TypedDataEncoder } from "./typed-data.js"; | ||
//# sourceMappingURL=index.js.map |
@@ -1,4 +0,3 @@ | ||
import { Bytes } from "@ethersproject/bytes"; | ||
export declare const messagePrefix = "\u0019Ethereum Signed Message:\n"; | ||
export declare function hashMessage(message: Bytes | string): string; | ||
export declare function hashMessage(message: Uint8Array | string): string; | ||
//# sourceMappingURL=message.d.ts.map |
@@ -1,19 +0,15 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.hashMessage = exports.messagePrefix = void 0; | ||
var bytes_1 = require("@ethersproject/bytes"); | ||
var keccak256_1 = require("@ethersproject/keccak256"); | ||
var strings_1 = require("@ethersproject/strings"); | ||
exports.messagePrefix = "\x19Ethereum Signed Message:\n"; | ||
function hashMessage(message) { | ||
import { concat } from "@ethersproject/bytes"; | ||
import { keccak256 } from "@ethersproject/crypto"; | ||
import { toUtf8Bytes } from "@ethersproject/strings"; | ||
export const messagePrefix = "\x19Ethereum Signed Message:\n"; | ||
export function hashMessage(message) { | ||
if (typeof (message) === "string") { | ||
message = (0, strings_1.toUtf8Bytes)(message); | ||
message = toUtf8Bytes(message); | ||
} | ||
return (0, keccak256_1.keccak256)((0, bytes_1.concat)([ | ||
(0, strings_1.toUtf8Bytes)(exports.messagePrefix), | ||
(0, strings_1.toUtf8Bytes)(String(message.length)), | ||
return keccak256(concat([ | ||
toUtf8Bytes(messagePrefix), | ||
toUtf8Bytes(String(message.length)), | ||
message | ||
])); | ||
} | ||
exports.hashMessage = hashMessage; | ||
//# sourceMappingURL=message.js.map |
@@ -1,18 +0,13 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.dnsEncode = exports.namehash = exports.isValidName = void 0; | ||
var bytes_1 = require("@ethersproject/bytes"); | ||
var strings_1 = require("@ethersproject/strings"); | ||
var keccak256_1 = require("@ethersproject/keccak256"); | ||
var logger_1 = require("@ethersproject/logger"); | ||
var _version_1 = require("./_version"); | ||
var logger = new logger_1.Logger(_version_1.version); | ||
var Zeros = new Uint8Array(32); | ||
import { concat, hexlify } from "@ethersproject/bytes"; | ||
import { keccak256 } from "@ethersproject/crypto"; | ||
import { nameprep, toUtf8Bytes } from "@ethersproject/strings"; | ||
import { logger } from "./logger.js"; | ||
const Zeros = new Uint8Array(32); | ||
Zeros.fill(0); | ||
var Partition = new RegExp("^((.*)\\.)?([^.]+)$"); | ||
function isValidName(name) { | ||
const Partition = new RegExp("^((.*)\\.)?([^.]+)$"); | ||
export function isValidName(name) { | ||
try { | ||
var comps = name.split("."); | ||
for (var i = 0; i < comps.length; i++) { | ||
if ((0, strings_1.nameprep)(comps[i]).length === 0) { | ||
const comps = name.split("."); | ||
for (let i = 0; i < comps.length; i++) { | ||
if (nameprep(comps[i]).length === 0) { | ||
throw new Error("empty"); | ||
@@ -26,32 +21,38 @@ } | ||
} | ||
exports.isValidName = isValidName; | ||
function namehash(name) { | ||
/* istanbul ignore if */ | ||
export function namehash(name) { | ||
if (typeof (name) !== "string") { | ||
logger.throwArgumentError("invalid ENS name; not a string", "name", name); | ||
} | ||
var current = name; | ||
var result = Zeros; | ||
let current = name; | ||
let result = Zeros; | ||
while (current.length) { | ||
var partition = current.match(Partition); | ||
const partition = current.match(Partition); | ||
if (partition == null || partition[2] === "") { | ||
logger.throwArgumentError("invalid ENS address; missing component", "name", name); | ||
return logger.throwArgumentError("invalid ENS name; missing component", "name", name); | ||
} | ||
var label = (0, strings_1.toUtf8Bytes)((0, strings_1.nameprep)(partition[3])); | ||
result = (0, keccak256_1.keccak256)((0, bytes_1.concat)([result, (0, keccak256_1.keccak256)(label)])); | ||
const label = toUtf8Bytes(nameprep(partition[3])); | ||
result = keccak256(concat([result, keccak256(label)])); | ||
current = partition[2] || ""; | ||
} | ||
return (0, bytes_1.hexlify)(result); | ||
return hexlify(result); | ||
} | ||
exports.namehash = namehash; | ||
function dnsEncode(name) { | ||
return (0, bytes_1.hexlify)((0, bytes_1.concat)(name.split(".").map(function (comp) { | ||
export function dnsEncode(name) { | ||
if (typeof (name) !== "string") { | ||
logger.throwArgumentError("invalid DNS name; not a string", "name", name); | ||
} | ||
if (name === "") { | ||
return "0x00"; | ||
} | ||
// @TODO: should we enforce the 255 octet limit? | ||
return concat(name.split(".").map((comp) => { | ||
if (comp === "") { | ||
logger.throwArgumentError("invalid DNS name; missing component", "name", name); | ||
} | ||
// We jam in an _ prefix to fill in with the length later | ||
// Note: Nameprep throws if the component is over 63 bytes | ||
var bytes = (0, strings_1.toUtf8Bytes)("_" + (0, strings_1.nameprep)(comp)); | ||
const bytes = toUtf8Bytes("_" + nameprep(comp)); | ||
bytes[0] = bytes.length - 1; | ||
return bytes; | ||
}))) + "00"; | ||
})) + "00"; | ||
} | ||
exports.dnsEncode = dnsEncode; | ||
//# sourceMappingURL=namehash.js.map |
@@ -1,10 +0,19 @@ | ||
import { TypedDataDomain, TypedDataField } from "@ethersproject/abstract-signer"; | ||
import type { BigNumberish, BytesLike } from "@ethersproject/logger"; | ||
export interface TypedDataDomain { | ||
name?: string; | ||
version?: string; | ||
chainId?: BigNumberish; | ||
verifyingContract?: string; | ||
salt?: BytesLike; | ||
} | ||
export interface TypedDataField { | ||
name: string; | ||
type: string; | ||
} | ||
export declare class TypedDataEncoder { | ||
#private; | ||
readonly primaryType: string; | ||
readonly types: Record<string, Array<TypedDataField>>; | ||
readonly _encoderCache: Record<string, (value: any) => string>; | ||
readonly _types: Record<string, string>; | ||
get types(): Record<string, Array<TypedDataField>>; | ||
constructor(types: Record<string, Array<TypedDataField>>); | ||
getEncoder(type: string): (value: any) => string; | ||
_getEncoder(type: string): (value: any) => string; | ||
encodeType(name: string): string; | ||
@@ -11,0 +20,0 @@ encodeData(type: string, value: any): string; |
@@ -1,66 +0,40 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TypedDataEncoder = void 0; | ||
var address_1 = require("@ethersproject/address"); | ||
var bignumber_1 = require("@ethersproject/bignumber"); | ||
var bytes_1 = require("@ethersproject/bytes"); | ||
var keccak256_1 = require("@ethersproject/keccak256"); | ||
var properties_1 = require("@ethersproject/properties"); | ||
var logger_1 = require("@ethersproject/logger"); | ||
var _version_1 = require("./_version"); | ||
var logger = new logger_1.Logger(_version_1.version); | ||
var id_1 = require("./id"); | ||
var padding = new Uint8Array(32); | ||
var _TypedDataEncoder_instances, _TypedDataEncoder_types, _TypedDataEncoder_fullTypes, _TypedDataEncoder_encoderCache, _TypedDataEncoder_getEncoder; | ||
//import { TypedDataDomain, TypedDataField } from "@ethersproject/providerabstract-signer"; | ||
import { getAddress } from "@ethersproject/address"; | ||
import { arrayify, concat, hexlify, zeroPadLeft, isHexString } from "@ethersproject/bytes"; | ||
import { keccak256 } from "@ethersproject/crypto"; | ||
import { defineProperties } from "@ethersproject/properties"; | ||
import { mask, toHex, toTwos } from "@ethersproject/math"; | ||
import { id } from "./id.js"; | ||
import { logger } from "./logger.js"; | ||
const padding = new Uint8Array(32); | ||
padding.fill(0); | ||
var NegativeOne = bignumber_1.BigNumber.from(-1); | ||
var Zero = bignumber_1.BigNumber.from(0); | ||
var One = bignumber_1.BigNumber.from(1); | ||
var MaxUint256 = bignumber_1.BigNumber.from("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); | ||
const BN__1 = BigInt(-1); | ||
const BN_0 = BigInt(0); | ||
const BN_1 = BigInt(1); | ||
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); | ||
; | ||
; | ||
function hexPadRight(value) { | ||
var bytes = (0, bytes_1.arrayify)(value); | ||
var padOffset = bytes.length % 32; | ||
const bytes = arrayify(value); | ||
const padOffset = bytes.length % 32; | ||
if (padOffset) { | ||
return (0, bytes_1.hexConcat)([bytes, padding.slice(padOffset)]); | ||
return concat([bytes, padding.slice(padOffset)]); | ||
} | ||
return (0, bytes_1.hexlify)(bytes); | ||
return hexlify(bytes); | ||
} | ||
var hexTrue = (0, bytes_1.hexZeroPad)(One.toHexString(), 32); | ||
var hexFalse = (0, bytes_1.hexZeroPad)(Zero.toHexString(), 32); | ||
var domainFieldTypes = { | ||
const hexTrue = toHex(BN_1, 32); | ||
const hexFalse = toHex(BN_0, 32); | ||
const domainFieldTypes = { | ||
name: "string", | ||
@@ -72,3 +46,3 @@ version: "string", | ||
}; | ||
var domainFieldNames = [ | ||
const domainFieldNames = [ | ||
"name", "version", "chainId", "verifyingContract", "salt" | ||
@@ -79,3 +53,3 @@ ]; | ||
if (typeof (value) !== "string") { | ||
logger.throwArgumentError("invalid domain value for " + JSON.stringify(key), "domain." + key, value); | ||
logger.throwArgumentError(`invalid domain value for ${JSON.stringify(key)}`, `domain.${key}`, value); | ||
} | ||
@@ -85,29 +59,21 @@ return value; | ||
} | ||
var domainChecks = { | ||
const domainChecks = { | ||
name: checkString("name"), | ||
version: checkString("version"), | ||
chainId: function (value) { | ||
try { | ||
return bignumber_1.BigNumber.from(value).toString(); | ||
} | ||
catch (error) { } | ||
return logger.throwArgumentError("invalid domain value for \"chainId\"", "domain.chainId", value); | ||
return logger.getBigInt(value, "domain.chainId"); | ||
}, | ||
verifyingContract: function (value) { | ||
try { | ||
return (0, address_1.getAddress)(value).toLowerCase(); | ||
return getAddress(value).toLowerCase(); | ||
} | ||
catch (error) { } | ||
return logger.throwArgumentError("invalid domain value \"verifyingContract\"", "domain.verifyingContract", value); | ||
return logger.throwArgumentError(`invalid domain value "verifyingContract"`, "domain.verifyingContract", value); | ||
}, | ||
salt: function (value) { | ||
try { | ||
var bytes = (0, bytes_1.arrayify)(value); | ||
if (bytes.length !== 32) { | ||
throw new Error("bad length"); | ||
} | ||
return (0, bytes_1.hexlify)(bytes); | ||
const bytes = logger.getBytes(value, "domain.salt"); | ||
if (bytes.length !== 32) { | ||
logger.throwArgumentError(`invalid domain value "salt"`, "domain.salt", value); | ||
} | ||
catch (error) { } | ||
return logger.throwArgumentError("invalid domain value \"salt\"", "domain.salt", value); | ||
return hexlify(bytes); | ||
} | ||
@@ -118,17 +84,17 @@ }; | ||
{ | ||
var match = type.match(/^(u?)int(\d*)$/); | ||
const match = type.match(/^(u?)int(\d*)$/); | ||
if (match) { | ||
var signed = (match[1] === ""); | ||
var width = parseInt(match[2] || "256"); | ||
const signed = (match[1] === ""); | ||
const width = parseInt(match[2] || "256"); | ||
if (width % 8 !== 0 || width > 256 || (match[2] && match[2] !== String(width))) { | ||
logger.throwArgumentError("invalid numeric width", "type", type); | ||
} | ||
var boundsUpper_1 = MaxUint256.mask(signed ? (width - 1) : width); | ||
var boundsLower_1 = signed ? boundsUpper_1.add(One).mul(NegativeOne) : Zero; | ||
return function (value) { | ||
var v = bignumber_1.BigNumber.from(value); | ||
if (v.lt(boundsLower_1) || v.gt(boundsUpper_1)) { | ||
logger.throwArgumentError("value out-of-bounds for " + type, "value", value); | ||
const boundsUpper = mask(BN_MAX_UINT256, signed ? (width - 1) : width); | ||
const boundsLower = signed ? ((boundsUpper + BN_1) * BN__1) : BN_0; | ||
return function (_value) { | ||
const value = logger.getBigInt(_value, "value"); | ||
if (value < boundsLower || value > boundsUpper) { | ||
logger.throwArgumentError(`value out-of-bounds for ${type}`, "value", value); | ||
} | ||
return (0, bytes_1.hexZeroPad)(v.toTwos(256).toHexString(), 32); | ||
return toHex(toTwos(value, 256), 32); | ||
}; | ||
@@ -139,12 +105,12 @@ } | ||
{ | ||
var match = type.match(/^bytes(\d+)$/); | ||
const match = type.match(/^bytes(\d+)$/); | ||
if (match) { | ||
var width_1 = parseInt(match[1]); | ||
if (width_1 === 0 || width_1 > 32 || match[1] !== String(width_1)) { | ||
const width = parseInt(match[1]); | ||
if (width === 0 || width > 32 || match[1] !== String(width)) { | ||
logger.throwArgumentError("invalid bytes width", "type", type); | ||
} | ||
return function (value) { | ||
var bytes = (0, bytes_1.arrayify)(value); | ||
if (bytes.length !== width_1) { | ||
logger.throwArgumentError("invalid length for " + type, "value", value); | ||
const bytes = arrayify(value); | ||
if (bytes.length !== width) { | ||
logger.throwArgumentError(`invalid length for ${type}`, "value", value); | ||
} | ||
@@ -157,3 +123,3 @@ return hexPadRight(value); | ||
case "address": return function (value) { | ||
return (0, bytes_1.hexZeroPad)((0, address_1.getAddress)(value), 32); | ||
return zeroPadLeft(getAddress(value), 32); | ||
}; | ||
@@ -164,6 +130,6 @@ case "bool": return function (value) { | ||
case "bytes": return function (value) { | ||
return (0, keccak256_1.keccak256)(value); | ||
return keccak256(value); | ||
}; | ||
case "string": return function (value) { | ||
return (0, id_1.id)(value); | ||
return id(value); | ||
}; | ||
@@ -174,54 +140,52 @@ } | ||
function encodeType(name, fields) { | ||
return name + "(" + fields.map(function (_a) { | ||
var name = _a.name, type = _a.type; | ||
return (type + " " + name); | ||
}).join(",") + ")"; | ||
return `${name}(${fields.map(({ name, type }) => (type + " " + name)).join(",")})`; | ||
} | ||
var TypedDataEncoder = /** @class */ (function () { | ||
function TypedDataEncoder(types) { | ||
(0, properties_1.defineReadOnly)(this, "types", Object.freeze((0, properties_1.deepCopy)(types))); | ||
(0, properties_1.defineReadOnly)(this, "_encoderCache", {}); | ||
(0, properties_1.defineReadOnly)(this, "_types", {}); | ||
export class TypedDataEncoder { | ||
constructor(types) { | ||
_TypedDataEncoder_instances.add(this); | ||
_TypedDataEncoder_types.set(this, void 0); | ||
_TypedDataEncoder_fullTypes.set(this, void 0); | ||
_TypedDataEncoder_encoderCache.set(this, void 0); | ||
__classPrivateFieldSet(this, _TypedDataEncoder_types, JSON.stringify(types), "f"); | ||
__classPrivateFieldSet(this, _TypedDataEncoder_fullTypes, new Map(), "f"); | ||
__classPrivateFieldSet(this, _TypedDataEncoder_encoderCache, new Map(), "f"); | ||
// Link struct types to their direct child structs | ||
var links = {}; | ||
const links = new Map(); | ||
// Link structs to structs which contain them as a child | ||
var parents = {}; | ||
const parents = new Map(); | ||
// Link all subtypes within a given struct | ||
var subtypes = {}; | ||
Object.keys(types).forEach(function (type) { | ||
links[type] = {}; | ||
parents[type] = []; | ||
subtypes[type] = {}; | ||
const subtypes = new Map(); | ||
Object.keys(types).forEach((type) => { | ||
links.set(type, new Set()); | ||
parents.set(type, []); | ||
subtypes.set(type, new Set()); | ||
}); | ||
var _loop_1 = function (name_1) { | ||
var uniqueNames = {}; | ||
types[name_1].forEach(function (field) { | ||
for (const name in types) { | ||
const uniqueNames = new Set(); | ||
for (const field of types[name]) { | ||
// Check each field has a unique name | ||
if (uniqueNames[field.name]) { | ||
logger.throwArgumentError("duplicate variable name " + JSON.stringify(field.name) + " in " + JSON.stringify(name_1), "types", types); | ||
if (uniqueNames.has(field.name)) { | ||
logger.throwArgumentError(`duplicate variable name ${JSON.stringify(field.name)} in ${JSON.stringify(name)}`, "types", types); | ||
} | ||
uniqueNames[field.name] = true; | ||
uniqueNames.add(field.name); | ||
// Get the base type (drop any array specifiers) | ||
var baseType = field.type.match(/^([^\x5b]*)(\x5b|$)/)[1]; | ||
if (baseType === name_1) { | ||
logger.throwArgumentError("circular type reference to " + JSON.stringify(baseType), "types", types); | ||
const baseType = (field.type.match(/^([^\x5b]*)(\x5b|$)/))[1] || null; | ||
if (baseType === name) { | ||
logger.throwArgumentError(`circular type reference to ${JSON.stringify(baseType)}`, "types", types); | ||
} | ||
// Is this a base encoding type? | ||
var encoder = getBaseEncoder(baseType); | ||
const encoder = getBaseEncoder(baseType); | ||
if (encoder) { | ||
return; | ||
continue; | ||
} | ||
if (!parents[baseType]) { | ||
logger.throwArgumentError("unknown type " + JSON.stringify(baseType), "types", types); | ||
if (!parents.has(baseType)) { | ||
logger.throwArgumentError(`unknown type ${JSON.stringify(baseType)}`, "types", types); | ||
} | ||
// Add linkage | ||
parents[baseType].push(name_1); | ||
links[name_1][baseType] = true; | ||
}); | ||
}; | ||
for (var name_1 in types) { | ||
_loop_1(name_1); | ||
parents.get(baseType).push(name); | ||
links.get(name).add(baseType); | ||
} | ||
} | ||
// Deduce the primary type | ||
var primaryTypes = Object.keys(parents).filter(function (n) { return (parents[n].length === 0); }); | ||
const primaryTypes = Array.from(parents.keys()).filter((n) => (parents.get(n).length === 0)); | ||
if (primaryTypes.length === 0) { | ||
@@ -231,14 +195,14 @@ logger.throwArgumentError("missing primary type", "types", types); | ||
else if (primaryTypes.length > 1) { | ||
logger.throwArgumentError("ambiguous primary types or unused types: " + primaryTypes.map(function (t) { return (JSON.stringify(t)); }).join(", "), "types", types); | ||
logger.throwArgumentError(`ambiguous primary types or unused types: ${primaryTypes.map((t) => (JSON.stringify(t))).join(", ")}`, "types", types); | ||
} | ||
(0, properties_1.defineReadOnly)(this, "primaryType", primaryTypes[0]); | ||
defineProperties(this, { primaryType: primaryTypes[0] }); | ||
// Check for circular type references | ||
function checkCircular(type, found) { | ||
if (found[type]) { | ||
logger.throwArgumentError("circular type reference to " + JSON.stringify(type), "types", types); | ||
if (found.has(type)) { | ||
logger.throwArgumentError(`circular type reference to ${JSON.stringify(type)}`, "types", types); | ||
} | ||
found[type] = true; | ||
Object.keys(links[type]).forEach(function (child) { | ||
if (!parents[child]) { | ||
return; | ||
found.add(type); | ||
for (const child of links.get(type)) { | ||
if (!parents.has(child)) { | ||
continue; | ||
} | ||
@@ -248,92 +212,50 @@ // Recursively check children | ||
// Mark all ancestors as having this decendant | ||
Object.keys(found).forEach(function (subtype) { | ||
subtypes[subtype][child] = true; | ||
}); | ||
}); | ||
delete found[type]; | ||
for (const subtype of found) { | ||
subtypes.get(subtype).add(child); | ||
} | ||
} | ||
found.delete(type); | ||
} | ||
checkCircular(this.primaryType, {}); | ||
checkCircular(this.primaryType, new Set()); | ||
// Compute each fully describe type | ||
for (var name_2 in subtypes) { | ||
var st = Object.keys(subtypes[name_2]); | ||
for (const [name, set] of subtypes) { | ||
const st = Array.from(set); | ||
st.sort(); | ||
this._types[name_2] = encodeType(name_2, types[name_2]) + st.map(function (t) { return encodeType(t, types[t]); }).join(""); | ||
__classPrivateFieldGet(this, _TypedDataEncoder_fullTypes, "f").set(name, encodeType(name, types[name]) + st.map((t) => encodeType(t, types[t])).join("")); | ||
} | ||
} | ||
TypedDataEncoder.prototype.getEncoder = function (type) { | ||
var encoder = this._encoderCache[type]; | ||
get types() { | ||
return JSON.parse(__classPrivateFieldGet(this, _TypedDataEncoder_types, "f")); | ||
} | ||
getEncoder(type) { | ||
let encoder = __classPrivateFieldGet(this, _TypedDataEncoder_encoderCache, "f").get(type); | ||
if (!encoder) { | ||
encoder = this._encoderCache[type] = this._getEncoder(type); | ||
encoder = __classPrivateFieldGet(this, _TypedDataEncoder_instances, "m", _TypedDataEncoder_getEncoder).call(this, type); | ||
__classPrivateFieldGet(this, _TypedDataEncoder_encoderCache, "f").set(type, encoder); | ||
} | ||
return encoder; | ||
}; | ||
TypedDataEncoder.prototype._getEncoder = function (type) { | ||
var _this = this; | ||
// Basic encoder type (address, bool, uint256, etc) | ||
{ | ||
var encoder = getBaseEncoder(type); | ||
if (encoder) { | ||
return encoder; | ||
} | ||
} | ||
// Array | ||
var match = type.match(/^(.*)(\x5b(\d*)\x5d)$/); | ||
if (match) { | ||
var subtype_1 = match[1]; | ||
var subEncoder_1 = this.getEncoder(subtype_1); | ||
var length_1 = parseInt(match[3]); | ||
return function (value) { | ||
if (length_1 >= 0 && value.length !== length_1) { | ||
logger.throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value); | ||
} | ||
var result = value.map(subEncoder_1); | ||
if (_this._types[subtype_1]) { | ||
result = result.map(keccak256_1.keccak256); | ||
} | ||
return (0, keccak256_1.keccak256)((0, bytes_1.hexConcat)(result)); | ||
}; | ||
} | ||
// Struct | ||
var fields = this.types[type]; | ||
if (fields) { | ||
var encodedType_1 = (0, id_1.id)(this._types[type]); | ||
return function (value) { | ||
var values = fields.map(function (_a) { | ||
var name = _a.name, type = _a.type; | ||
var result = _this.getEncoder(type)(value[name]); | ||
if (_this._types[type]) { | ||
return (0, keccak256_1.keccak256)(result); | ||
} | ||
return result; | ||
}); | ||
values.unshift(encodedType_1); | ||
return (0, bytes_1.hexConcat)(values); | ||
}; | ||
} | ||
return logger.throwArgumentError("unknown type: " + type, "type", type); | ||
}; | ||
TypedDataEncoder.prototype.encodeType = function (name) { | ||
var result = this._types[name]; | ||
} | ||
encodeType(name) { | ||
const result = __classPrivateFieldGet(this, _TypedDataEncoder_fullTypes, "f").get(name); | ||
if (!result) { | ||
logger.throwArgumentError("unknown type: " + JSON.stringify(name), "name", name); | ||
return logger.throwArgumentError(`unknown type: ${JSON.stringify(name)}`, "name", name); | ||
} | ||
return result; | ||
}; | ||
TypedDataEncoder.prototype.encodeData = function (type, value) { | ||
} | ||
encodeData(type, value) { | ||
return this.getEncoder(type)(value); | ||
}; | ||
TypedDataEncoder.prototype.hashStruct = function (name, value) { | ||
return (0, keccak256_1.keccak256)(this.encodeData(name, value)); | ||
}; | ||
TypedDataEncoder.prototype.encode = function (value) { | ||
} | ||
hashStruct(name, value) { | ||
return keccak256(this.encodeData(name, value)); | ||
} | ||
encode(value) { | ||
return this.encodeData(this.primaryType, value); | ||
}; | ||
TypedDataEncoder.prototype.hash = function (value) { | ||
} | ||
hash(value) { | ||
return this.hashStruct(this.primaryType, value); | ||
}; | ||
TypedDataEncoder.prototype._visit = function (type, value, callback) { | ||
var _this = this; | ||
} | ||
_visit(type, value, callback) { | ||
// Basic encoder type (address, bool, uint256, etc) | ||
{ | ||
var encoder = getBaseEncoder(type); | ||
const encoder = getBaseEncoder(type); | ||
if (encoder) { | ||
@@ -344,50 +266,49 @@ return callback(type, value); | ||
// Array | ||
var match = type.match(/^(.*)(\x5b(\d*)\x5d)$/); | ||
const match = type.match(/^(.*)(\x5b(\d*)\x5d)$/); | ||
if (match) { | ||
var subtype_2 = match[1]; | ||
var length_2 = parseInt(match[3]); | ||
if (length_2 >= 0 && value.length !== length_2) { | ||
const subtype = match[1]; | ||
const length = parseInt(match[3]); | ||
if (length >= 0 && value.length !== length) { | ||
logger.throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value); | ||
} | ||
return value.map(function (v) { return _this._visit(subtype_2, v, callback); }); | ||
return value.map((v) => this._visit(subtype, v, callback)); | ||
} | ||
// Struct | ||
var fields = this.types[type]; | ||
const fields = this.types[type]; | ||
if (fields) { | ||
return fields.reduce(function (accum, _a) { | ||
var name = _a.name, type = _a.type; | ||
accum[name] = _this._visit(type, value[name], callback); | ||
return fields.reduce((accum, { name, type }) => { | ||
accum[name] = this._visit(type, value[name], callback); | ||
return accum; | ||
}, {}); | ||
} | ||
return logger.throwArgumentError("unknown type: " + type, "type", type); | ||
}; | ||
TypedDataEncoder.prototype.visit = function (value, callback) { | ||
return logger.throwArgumentError(`unknown type: ${type}`, "type", type); | ||
} | ||
visit(value, callback) { | ||
return this._visit(this.primaryType, value, callback); | ||
}; | ||
TypedDataEncoder.from = function (types) { | ||
} | ||
static from(types) { | ||
return new TypedDataEncoder(types); | ||
}; | ||
TypedDataEncoder.getPrimaryType = function (types) { | ||
} | ||
static getPrimaryType(types) { | ||
return TypedDataEncoder.from(types).primaryType; | ||
}; | ||
TypedDataEncoder.hashStruct = function (name, types, value) { | ||
} | ||
static hashStruct(name, types, value) { | ||
return TypedDataEncoder.from(types).hashStruct(name, value); | ||
}; | ||
TypedDataEncoder.hashDomain = function (domain) { | ||
var domainFields = []; | ||
for (var name_3 in domain) { | ||
var type = domainFieldTypes[name_3]; | ||
} | ||
static hashDomain(domain) { | ||
const domainFields = []; | ||
for (const name in domain) { | ||
const type = domainFieldTypes[name]; | ||
if (!type) { | ||
logger.throwArgumentError("invalid typed-data domain key: " + JSON.stringify(name_3), "domain", domain); | ||
logger.throwArgumentError(`invalid typed-data domain key: ${JSON.stringify(name)}`, "domain", domain); | ||
} | ||
domainFields.push({ name: name_3, type: type }); | ||
domainFields.push({ name, type }); | ||
} | ||
domainFields.sort(function (a, b) { | ||
domainFields.sort((a, b) => { | ||
return domainFieldNames.indexOf(a.name) - domainFieldNames.indexOf(b.name); | ||
}); | ||
return TypedDataEncoder.hashStruct("EIP712Domain", { EIP712Domain: domainFields }, domain); | ||
}; | ||
TypedDataEncoder.encode = function (domain, types, value) { | ||
return (0, bytes_1.hexConcat)([ | ||
} | ||
static encode(domain, types, value) { | ||
return concat([ | ||
"0x1901", | ||
@@ -397,70 +318,50 @@ TypedDataEncoder.hashDomain(domain), | ||
]); | ||
}; | ||
TypedDataEncoder.hash = function (domain, types, value) { | ||
return (0, keccak256_1.keccak256)(TypedDataEncoder.encode(domain, types, value)); | ||
}; | ||
} | ||
static hash(domain, types, value) { | ||
return keccak256(TypedDataEncoder.encode(domain, types, value)); | ||
} | ||
// Replaces all address types with ENS names with their looked up address | ||
TypedDataEncoder.resolveNames = function (domain, types, value, resolveName) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var ensCache, encoder, _a, _b, _i, name_4, _c, _d; | ||
return __generator(this, function (_e) { | ||
switch (_e.label) { | ||
case 0: | ||
// Make a copy to isolate it from the object passed in | ||
domain = (0, properties_1.shallowCopy)(domain); | ||
ensCache = {}; | ||
// Do we need to look up the domain's verifyingContract? | ||
if (domain.verifyingContract && !(0, bytes_1.isHexString)(domain.verifyingContract, 20)) { | ||
ensCache[domain.verifyingContract] = "0x"; | ||
} | ||
encoder = TypedDataEncoder.from(types); | ||
// Get a list of all the addresses | ||
encoder.visit(value, function (type, value) { | ||
if (type === "address" && !(0, bytes_1.isHexString)(value, 20)) { | ||
ensCache[value] = "0x"; | ||
} | ||
return value; | ||
}); | ||
_a = []; | ||
for (_b in ensCache) | ||
_a.push(_b); | ||
_i = 0; | ||
_e.label = 1; | ||
case 1: | ||
if (!(_i < _a.length)) return [3 /*break*/, 4]; | ||
name_4 = _a[_i]; | ||
_c = ensCache; | ||
_d = name_4; | ||
return [4 /*yield*/, resolveName(name_4)]; | ||
case 2: | ||
_c[_d] = _e.sent(); | ||
_e.label = 3; | ||
case 3: | ||
_i++; | ||
return [3 /*break*/, 1]; | ||
case 4: | ||
// Replace the domain verifyingContract if needed | ||
if (domain.verifyingContract && ensCache[domain.verifyingContract]) { | ||
domain.verifyingContract = ensCache[domain.verifyingContract]; | ||
} | ||
// Replace all ENS names with their address | ||
value = encoder.visit(value, function (type, value) { | ||
if (type === "address" && ensCache[value]) { | ||
return ensCache[value]; | ||
} | ||
return value; | ||
}); | ||
return [2 /*return*/, { domain: domain, value: value }]; | ||
} | ||
}); | ||
static async resolveNames(domain, types, value, resolveName) { | ||
// Make a copy to isolate it from the object passed in | ||
domain = Object.assign({}, domain); | ||
// Look up all ENS names | ||
const ensCache = {}; | ||
// Do we need to look up the domain's verifyingContract? | ||
if (domain.verifyingContract && !isHexString(domain.verifyingContract, 20)) { | ||
ensCache[domain.verifyingContract] = "0x"; | ||
} | ||
// We are going to use the encoder to visit all the base values | ||
const encoder = TypedDataEncoder.from(types); | ||
// Get a list of all the addresses | ||
encoder.visit(value, (type, value) => { | ||
if (type === "address" && !isHexString(value, 20)) { | ||
ensCache[value] = "0x"; | ||
} | ||
return value; | ||
}); | ||
}; | ||
TypedDataEncoder.getPayload = function (domain, types, value) { | ||
// Lookup each name | ||
for (const name in ensCache) { | ||
ensCache[name] = await resolveName(name); | ||
} | ||
// Replace the domain verifyingContract if needed | ||
if (domain.verifyingContract && ensCache[domain.verifyingContract]) { | ||
domain.verifyingContract = ensCache[domain.verifyingContract]; | ||
} | ||
// Replace all ENS names with their address | ||
value = encoder.visit(value, (type, value) => { | ||
if (type === "address" && ensCache[value]) { | ||
return ensCache[value]; | ||
} | ||
return value; | ||
}); | ||
return { domain, value }; | ||
} | ||
static getPayload(domain, types, value) { | ||
// Validate the domain fields | ||
TypedDataEncoder.hashDomain(domain); | ||
// Derive the EIP712Domain Struct reference type | ||
var domainValues = {}; | ||
var domainTypes = []; | ||
domainFieldNames.forEach(function (name) { | ||
var value = domain[name]; | ||
const domainValues = {}; | ||
const domainTypes = []; | ||
domainFieldNames.forEach((name) => { | ||
const value = domain[name]; | ||
if (value == null) { | ||
@@ -470,6 +371,6 @@ return; | ||
domainValues[name] = domainChecks[name](value); | ||
domainTypes.push({ name: name, type: domainFieldTypes[name] }); | ||
domainTypes.push({ name, type: domainFieldTypes[name] }); | ||
}); | ||
var encoder = TypedDataEncoder.from(types); | ||
var typesWithDomain = (0, properties_1.shallowCopy)(types); | ||
const encoder = TypedDataEncoder.from(types); | ||
const typesWithDomain = Object.assign({}, types); | ||
if (typesWithDomain.EIP712Domain) { | ||
@@ -487,10 +388,10 @@ logger.throwArgumentError("types must not contain EIP712Domain type", "types.EIP712Domain", types); | ||
primaryType: encoder.primaryType, | ||
message: encoder.visit(value, function (type, value) { | ||
message: encoder.visit(value, (type, value) => { | ||
// bytes | ||
if (type.match(/^bytes(\d*)/)) { | ||
return (0, bytes_1.hexlify)((0, bytes_1.arrayify)(value)); | ||
return hexlify(logger.getBytes(value)); | ||
} | ||
// uint or int | ||
if (type.match(/^u?int/)) { | ||
return bignumber_1.BigNumber.from(value).toString(); | ||
return logger.getBigInt(value).toString(); | ||
} | ||
@@ -504,3 +405,3 @@ switch (type) { | ||
if (typeof (value) !== "string") { | ||
logger.throwArgumentError("invalid string", "value", value); | ||
logger.throwArgumentError(`invalid string`, "value", value); | ||
} | ||
@@ -512,6 +413,47 @@ return value; | ||
}; | ||
}; | ||
return TypedDataEncoder; | ||
}()); | ||
exports.TypedDataEncoder = TypedDataEncoder; | ||
} | ||
} | ||
_TypedDataEncoder_types = new WeakMap(), _TypedDataEncoder_fullTypes = new WeakMap(), _TypedDataEncoder_encoderCache = new WeakMap(), _TypedDataEncoder_instances = new WeakSet(), _TypedDataEncoder_getEncoder = function _TypedDataEncoder_getEncoder(type) { | ||
// Basic encoder type (address, bool, uint256, etc) | ||
{ | ||
const encoder = getBaseEncoder(type); | ||
if (encoder) { | ||
return encoder; | ||
} | ||
} | ||
// Array | ||
const match = type.match(/^(.*)(\x5b(\d*)\x5d)$/); | ||
if (match) { | ||
const subtype = match[1]; | ||
const subEncoder = this.getEncoder(subtype); | ||
const length = parseInt(match[3]); | ||
return (value) => { | ||
if (length >= 0 && value.length !== length) { | ||
logger.throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value); | ||
} | ||
let result = value.map(subEncoder); | ||
if (__classPrivateFieldGet(this, _TypedDataEncoder_fullTypes, "f").has(subtype)) { | ||
result = result.map(keccak256); | ||
} | ||
return keccak256(concat(result)); | ||
}; | ||
} | ||
// Struct | ||
const fields = this.types[type]; | ||
if (fields) { | ||
const encodedType = id(__classPrivateFieldGet(this, _TypedDataEncoder_fullTypes, "f").get(type)); | ||
return (value) => { | ||
const values = fields.map(({ name, type }) => { | ||
const result = this.getEncoder(type)(value[name]); | ||
if (__classPrivateFieldGet(this, _TypedDataEncoder_fullTypes, "f").has(type)) { | ||
return keccak256(result); | ||
} | ||
return result; | ||
}); | ||
values.unshift(encodedType); | ||
return concat(values); | ||
}; | ||
} | ||
return logger.throwArgumentError(`unknown type: ${type}`, "type", type); | ||
}; | ||
//# sourceMappingURL=typed-data.js.map |
MIT License | ||
Copyright (c) 2019 Richard Moore | ||
Copyright (c) 2022 Richard Moore | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
{ | ||
"author": "Richard Moore <me@ricmoo.com>", | ||
"dependencies": { | ||
"@ethersproject/abstract-signer": "^5.6.0", | ||
"@ethersproject/address": "^5.6.0", | ||
"@ethersproject/bignumber": "^5.6.0", | ||
"@ethersproject/bytes": "^5.6.0", | ||
"@ethersproject/keccak256": "^5.6.0", | ||
"@ethersproject/logger": "^5.6.0", | ||
"@ethersproject/properties": "^5.6.0", | ||
"@ethersproject/strings": "^5.6.0" | ||
"@ethersproject/address": "^6.0.0-beta.1", | ||
"@ethersproject/bytes": "^6.0.0-beta.1", | ||
"@ethersproject/crypto": "^6.0.0-beta.1", | ||
"@ethersproject/logger": "^6.0.0-beta.1", | ||
"@ethersproject/math": "^6.0.0-beta.1", | ||
"@ethersproject/properties": "^6.0.0-beta.1", | ||
"@ethersproject/strings": "^6.0.0-beta.1" | ||
}, | ||
"description": "Hash utility functions for Ethereum.", | ||
"description": "Hash utilities for ethers.", | ||
"engines": { | ||
"node": ">=12.17.0" | ||
}, | ||
"ethereum": "donations.ethers.eth", | ||
"funding": [ | ||
{ | ||
"type": "individual", | ||
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" | ||
}, | ||
{ | ||
"type": "individual", | ||
"url": "https://www.buymeacoffee.com/ricmoo" | ||
} | ||
], | ||
"gitHead": "b8cda5dffdcb688e38d7c6a0aec4c7b8b59c1af5", | ||
"gitHead": "77f691b3bc3a6387a5184ec9b1779faab4bcb30d", | ||
"keywords": [ | ||
@@ -32,6 +24,6 @@ "Ethereum", | ||
"main": "./lib/index.js", | ||
"module": "./lib.esm/index.js", | ||
"name": "@ethersproject/hash", | ||
"publishConfig": { | ||
"access": "public" | ||
"access": "public", | ||
"tag": "beta" | ||
}, | ||
@@ -47,5 +39,6 @@ "repository": { | ||
"sideEffects": false, | ||
"tarballHash": "0x23b00b87b17191eace6450fd824e0f816a3c3dfbdbacd0a904f67b5be5b43984", | ||
"tarballHash": "0xf8ec4639eeaaf31db5783f32bfc52196513ee91f31f26841186f84aa70ff73c8", | ||
"type": "module", | ||
"types": "./lib/index.d.ts", | ||
"version": "5.6.0" | ||
"version": "6.0.0-beta.1" | ||
} |
@@ -1,1 +0,1 @@ | ||
export const version = "hash/5.6.0"; | ||
export const version = "@ethersproject/hash@6.0.0-beta.1"; |
@@ -1,6 +0,6 @@ | ||
import { keccak256 } from "@ethersproject/keccak256"; | ||
import { keccak256 } from "@ethersproject/crypto"; | ||
import { toUtf8Bytes } from "@ethersproject/strings"; | ||
export function id(text: string): string { | ||
return keccak256(toUtf8Bytes(text)); | ||
export function id(value: string): string { | ||
return keccak256(toUtf8Bytes(value)); | ||
} |
@@ -1,20 +0,6 @@ | ||
"use strict"; | ||
export { id } from "./id.js" | ||
export { isValidName, namehash, dnsEncode } from "./namehash.js"; | ||
export { messagePrefix, hashMessage } from "./message.js"; | ||
export { TypedDataEncoder } from "./typed-data.js"; | ||
import { id } from "./id"; | ||
import { dnsEncode, isValidName, namehash } from "./namehash"; | ||
import { hashMessage, messagePrefix } from "./message"; | ||
import { TypedDataEncoder as _TypedDataEncoder } from "./typed-data"; | ||
export { | ||
id, | ||
dnsEncode, | ||
namehash, | ||
isValidName, | ||
messagePrefix, | ||
hashMessage, | ||
_TypedDataEncoder, | ||
} | ||
export type { TypedDataDomain, TypedDataField } from "./typed-data.js"; |
@@ -1,8 +0,9 @@ | ||
import { Bytes, concat } from "@ethersproject/bytes"; | ||
import { keccak256 } from "@ethersproject/keccak256"; | ||
import { concat } from "@ethersproject/bytes"; | ||
import { keccak256 } from "@ethersproject/crypto"; | ||
import { toUtf8Bytes } from "@ethersproject/strings"; | ||
export const messagePrefix = "\x19Ethereum Signed Message:\n"; | ||
export function hashMessage(message: Bytes | string): string { | ||
export function hashMessage(message: Uint8Array | string): string { | ||
if (typeof(message) === "string") { message = toUtf8Bytes(message); } | ||
@@ -15,2 +16,1 @@ return keccak256(concat([ | ||
} | ||
import { concat, hexlify } from "@ethersproject/bytes"; | ||
import { keccak256 } from "@ethersproject/crypto"; | ||
import { nameprep, toUtf8Bytes } from "@ethersproject/strings"; | ||
import { keccak256 } from "@ethersproject/keccak256"; | ||
import { Logger } from "@ethersproject/logger"; | ||
import { version } from "./_version"; | ||
const logger = new Logger(version); | ||
import { logger } from "./logger.js"; | ||
const Zeros = new Uint8Array(32); | ||
@@ -28,3 +27,2 @@ Zeros.fill(0); | ||
export function namehash(name: string): string { | ||
/* istanbul ignore if */ | ||
if (typeof(name) !== "string") { | ||
@@ -39,3 +37,3 @@ logger.throwArgumentError("invalid ENS name; not a string", "name", name); | ||
if (partition == null || partition[2] === "") { | ||
logger.throwArgumentError("invalid ENS address; missing component", "name", name); | ||
return logger.throwArgumentError("invalid ENS name; missing component", "name", name); | ||
} | ||
@@ -52,9 +50,22 @@ const label = toUtf8Bytes(nameprep(partition[3])); | ||
export function dnsEncode(name: string): string { | ||
return hexlify(concat(name.split(".").map((comp) => { | ||
if (typeof(name) !== "string") { | ||
logger.throwArgumentError("invalid DNS name; not a string", "name", name); | ||
} | ||
if (name === "") { return "0x00"; } | ||
// @TODO: should we enforce the 255 octet limit? | ||
return concat(name.split(".").map((comp) => { | ||
if (comp === "") { | ||
logger.throwArgumentError("invalid DNS name; missing component", "name", name); | ||
} | ||
// We jam in an _ prefix to fill in with the length later | ||
// Note: Nameprep throws if the component is over 63 bytes | ||
const bytes = toUtf8Bytes("_" + nameprep(comp)); | ||
bytes[0] = bytes.length - 1; | ||
return bytes; | ||
}))) + "00"; | ||
})) + "00"; | ||
} |
@@ -1,22 +0,35 @@ | ||
import { TypedDataDomain, TypedDataField } from "@ethersproject/abstract-signer"; | ||
//import { TypedDataDomain, TypedDataField } from "@ethersproject/providerabstract-signer"; | ||
import { getAddress } from "@ethersproject/address"; | ||
import { BigNumber, BigNumberish } from "@ethersproject/bignumber"; | ||
import { arrayify, BytesLike, hexConcat, hexlify, hexZeroPad, isHexString } from "@ethersproject/bytes"; | ||
import { keccak256 } from "@ethersproject/keccak256"; | ||
import { deepCopy, defineReadOnly, shallowCopy } from "@ethersproject/properties"; | ||
import { arrayify, concat, hexlify, zeroPadLeft, isHexString } from "@ethersproject/bytes"; | ||
import { keccak256 } from "@ethersproject/crypto"; | ||
import { defineProperties } from "@ethersproject/properties"; | ||
import { mask, toHex, toTwos } from "@ethersproject/math"; | ||
import { Logger } from "@ethersproject/logger"; | ||
import { version } from "./_version"; | ||
const logger = new Logger(version); | ||
import { id } from "./id.js"; | ||
import { logger } from "./logger.js"; | ||
import { id } from "./id"; | ||
import type { BigNumberish, BytesLike } from "@ethersproject/logger"; | ||
const padding = new Uint8Array(32); | ||
padding.fill(0); | ||
const NegativeOne: BigNumber = BigNumber.from(-1); | ||
const Zero: BigNumber = BigNumber.from(0); | ||
const One: BigNumber = BigNumber.from(1); | ||
const MaxUint256: BigNumber = BigNumber.from("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); | ||
const BN__1 = BigInt(-1); | ||
const BN_0 = BigInt(0); | ||
const BN_1 = BigInt(1); | ||
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); | ||
export interface TypedDataDomain { | ||
name?: string; | ||
version?: string; | ||
chainId?: BigNumberish; | ||
verifyingContract?: string; | ||
salt?: BytesLike; | ||
}; | ||
export interface TypedDataField { | ||
name: string; | ||
type: string; | ||
}; | ||
function hexPadRight(value: BytesLike) { | ||
@@ -26,3 +39,3 @@ const bytes = arrayify(value); | ||
if (padOffset) { | ||
return hexConcat([ bytes, padding.slice(padOffset) ]); | ||
return concat([ bytes, padding.slice(padOffset) ]); | ||
} | ||
@@ -32,4 +45,4 @@ return hexlify(bytes); | ||
const hexTrue = hexZeroPad(One.toHexString(), 32); | ||
const hexFalse = hexZeroPad(Zero.toHexString(), 32); | ||
const hexTrue = toHex(BN_1, 32); | ||
const hexFalse = toHex(BN_0, 32); | ||
@@ -61,6 +74,3 @@ const domainFieldTypes: Record<string, string> = { | ||
chainId: function(value: any) { | ||
try { | ||
return BigNumber.from(value).toString() | ||
} catch (error) { } | ||
return logger.throwArgumentError(`invalid domain value for "chainId"`, "domain.chainId", value); | ||
return logger.getBigInt(value, "domain.chainId"); | ||
}, | ||
@@ -74,12 +84,11 @@ verifyingContract: function(value: any) { | ||
salt: function(value: any) { | ||
try { | ||
const bytes = arrayify(value); | ||
if (bytes.length !== 32) { throw new Error("bad length"); } | ||
return hexlify(bytes); | ||
} catch (error) { } | ||
return logger.throwArgumentError(`invalid domain value "salt"`, "domain.salt", value); | ||
const bytes = logger.getBytes(value, "domain.salt"); | ||
if (bytes.length !== 32) { | ||
logger.throwArgumentError(`invalid domain value "salt"`, "domain.salt", value); | ||
} | ||
return hexlify(bytes); | ||
} | ||
} | ||
function getBaseEncoder(type: string): (value: any) => string { | ||
function getBaseEncoder(type: string): null | ((value: any) => string) { | ||
// intXX and uintXX | ||
@@ -96,13 +105,13 @@ { | ||
const boundsUpper = MaxUint256.mask(signed ? (width - 1): width); | ||
const boundsLower = signed ? boundsUpper.add(One).mul(NegativeOne): Zero; | ||
const boundsUpper = mask(BN_MAX_UINT256, signed ? (width - 1): width); | ||
const boundsLower = signed ? ((boundsUpper + BN_1) * BN__1): BN_0; | ||
return function(value: BigNumberish) { | ||
const v = BigNumber.from(value); | ||
return function(_value: BigNumberish) { | ||
const value = logger.getBigInt(_value, "value"); | ||
if (v.lt(boundsLower) || v.gt(boundsUpper)) { | ||
if (value < boundsLower || value > boundsUpper) { | ||
logger.throwArgumentError(`value out-of-bounds for ${ type }`, "value", value); | ||
} | ||
return hexZeroPad(v.toTwos(256).toHexString(), 32); | ||
return toHex(toTwos(value, 256), 32); | ||
}; | ||
@@ -133,3 +142,3 @@ } | ||
case "address": return function(value: string) { | ||
return hexZeroPad(getAddress(value), 32); | ||
return zeroPadLeft(getAddress(value), 32); | ||
}; | ||
@@ -155,43 +164,46 @@ case "bool": return function(value: boolean) { | ||
export class TypedDataEncoder { | ||
readonly primaryType: string; | ||
readonly types: Record<string, Array<TypedDataField>>; | ||
readonly primaryType!: string; | ||
readonly _encoderCache: Record<string, (value: any) => string>; | ||
readonly _types: Record<string, string>; | ||
readonly #types: string; | ||
get types(): Record<string, Array<TypedDataField>> { | ||
return JSON.parse(this.#types); | ||
} | ||
readonly #fullTypes: Map<string, string> | ||
readonly #encoderCache: Map<string, (value: any) => string>; | ||
constructor(types: Record<string, Array<TypedDataField>>) { | ||
defineReadOnly(this, "types", Object.freeze(deepCopy(types))); | ||
this.#types = JSON.stringify(types); | ||
this.#fullTypes = new Map(); | ||
this.#encoderCache = new Map(); | ||
defineReadOnly(this, "_encoderCache", { }); | ||
defineReadOnly(this, "_types", { }); | ||
// Link struct types to their direct child structs | ||
const links: Record<string, Record<string, boolean>> = { }; | ||
const links: Map<string, Set<string>> = new Map(); | ||
// Link structs to structs which contain them as a child | ||
const parents: Record<string, Array<string>> = { }; | ||
const parents: Map<string, Array<string>> = new Map(); | ||
// Link all subtypes within a given struct | ||
const subtypes: Record<string, Record<string, boolean>> = { }; | ||
const subtypes: Map<string, Set<string>> = new Map(); | ||
Object.keys(types).forEach((type) => { | ||
links[type] = { }; | ||
parents[type] = [ ]; | ||
subtypes[type] = { } | ||
links.set(type, new Set()); | ||
parents.set(type, [ ]); | ||
subtypes.set(type, new Set()); | ||
}); | ||
for (const name in types) { | ||
const uniqueNames: Set<string> = new Set(); | ||
const uniqueNames: Record<string, boolean> = { }; | ||
for (const field of types[name]) { | ||
types[name].forEach((field) => { | ||
// Check each field has a unique name | ||
if (uniqueNames[field.name]) { | ||
if (uniqueNames.has(field.name)) { | ||
logger.throwArgumentError(`duplicate variable name ${ JSON.stringify(field.name) } in ${ JSON.stringify(name) }`, "types", types); | ||
} | ||
uniqueNames[field.name] = true; | ||
uniqueNames.add(field.name); | ||
// Get the base type (drop any array specifiers) | ||
const baseType = field.type.match(/^([^\x5b]*)(\x5b|$)/)[1]; | ||
const baseType = (<any>(field.type.match(/^([^\x5b]*)(\x5b|$)/)))[1] || null; | ||
if (baseType === name) { | ||
@@ -203,5 +215,5 @@ logger.throwArgumentError(`circular type reference to ${ JSON.stringify(baseType) }`, "types", types); | ||
const encoder = getBaseEncoder(baseType); | ||
if (encoder) { return ;} | ||
if (encoder) { continue; } | ||
if (!parents[baseType]) { | ||
if (!parents.has(baseType)) { | ||
logger.throwArgumentError(`unknown type ${ JSON.stringify(baseType) }`, "types", types); | ||
@@ -211,9 +223,9 @@ } | ||
// Add linkage | ||
parents[baseType].push(name); | ||
links[name][baseType] = true; | ||
}); | ||
(parents.get(baseType) as Array<string>).push(name); | ||
(links.get(name) as Set<string>).add(baseType); | ||
} | ||
} | ||
// Deduce the primary type | ||
const primaryTypes = Object.keys(parents).filter((n) => (parents[n].length === 0)); | ||
const primaryTypes = Array.from(parents.keys()).filter((n) => ((parents.get(n) as Array<string>).length === 0)); | ||
@@ -226,14 +238,14 @@ if (primaryTypes.length === 0) { | ||
defineReadOnly(this, "primaryType", primaryTypes[0]); | ||
defineProperties<TypedDataEncoder>(this, { primaryType: primaryTypes[0] }); | ||
// Check for circular type references | ||
function checkCircular(type: string, found: Record<string, boolean>) { | ||
if (found[type]) { | ||
function checkCircular(type: string, found: Set<string>) { | ||
if (found.has(type)) { | ||
logger.throwArgumentError(`circular type reference to ${ JSON.stringify(type) }`, "types", types); | ||
} | ||
found[type] = true; | ||
found.add(type); | ||
Object.keys(links[type]).forEach((child) => { | ||
if (!parents[child]) { return; } | ||
for (const child of (links.get(type) as Set<string>)) { | ||
if (!parents.has(child)) { continue; } | ||
@@ -244,16 +256,16 @@ // Recursively check children | ||
// Mark all ancestors as having this decendant | ||
Object.keys(found).forEach((subtype) => { | ||
subtypes[subtype][child] = true; | ||
}); | ||
}); | ||
for (const subtype of found) { | ||
(subtypes.get(subtype) as Set<string>).add(child); | ||
} | ||
} | ||
delete found[type]; | ||
found.delete(type); | ||
} | ||
checkCircular(this.primaryType, { }); | ||
checkCircular(this.primaryType, new Set()); | ||
// Compute each fully describe type | ||
for (const name in subtypes) { | ||
const st = Object.keys(subtypes[name]); | ||
for (const [ name, set ] of subtypes) { | ||
const st = Array.from(set); | ||
st.sort(); | ||
this._types[name] = encodeType(name, types[name]) + st.map((t) => encodeType(t, types[t])).join(""); | ||
this.#fullTypes.set(name, encodeType(name, types[name]) + st.map((t) => encodeType(t, types[t])).join("")); | ||
} | ||
@@ -263,5 +275,6 @@ } | ||
getEncoder(type: string): (value: any) => string { | ||
let encoder = this._encoderCache[type]; | ||
let encoder = this.#encoderCache.get(type); | ||
if (!encoder) { | ||
encoder = this._encoderCache[type] = this._getEncoder(type); | ||
encoder = this.#getEncoder(type); | ||
this.#encoderCache.set(type, encoder); | ||
} | ||
@@ -271,3 +284,3 @@ return encoder; | ||
_getEncoder(type: string): (value: any) => string { | ||
#getEncoder(type: string): (value: any) => string { | ||
@@ -292,7 +305,7 @@ // Basic encoder type (address, bool, uint256, etc) | ||
let result = value.map(subEncoder); | ||
if (this._types[subtype]) { | ||
if (this.#fullTypes.has(subtype)) { | ||
result = result.map(keccak256); | ||
} | ||
return keccak256(hexConcat(result)); | ||
return keccak256(concat(result)); | ||
}; | ||
@@ -304,11 +317,11 @@ } | ||
if (fields) { | ||
const encodedType = id(this._types[type]); | ||
const encodedType = id(this.#fullTypes.get(type) as string); | ||
return (value: Record<string, any>) => { | ||
const values = fields.map(({ name, type }) => { | ||
const result = this.getEncoder(type)(value[name]); | ||
if (this._types[type]) { return keccak256(result); } | ||
if (this.#fullTypes.has(type)) { return keccak256(result); } | ||
return result; | ||
}); | ||
values.unshift(encodedType); | ||
return hexConcat(values); | ||
return concat(values); | ||
} | ||
@@ -321,5 +334,5 @@ } | ||
encodeType(name: string): string { | ||
const result = this._types[name]; | ||
const result = this.#fullTypes.get(name); | ||
if (!result) { | ||
logger.throwArgumentError(`unknown type: ${ JSON.stringify(name) }`, "name", name); | ||
return logger.throwArgumentError(`unknown type: ${ JSON.stringify(name) }`, "name", name); | ||
} | ||
@@ -409,3 +422,3 @@ return result; | ||
static encode(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): string { | ||
return hexConcat([ | ||
return concat([ | ||
"0x1901", | ||
@@ -424,3 +437,3 @@ TypedDataEncoder.hashDomain(domain), | ||
// Make a copy to isolate it from the object passed in | ||
domain = shallowCopy(domain); | ||
domain = Object.assign({ }, domain); | ||
@@ -482,3 +495,3 @@ // Look up all ENS names | ||
const typesWithDomain = shallowCopy(types); | ||
const typesWithDomain = Object.assign({ }, types); | ||
if (typesWithDomain.EIP712Domain) { | ||
@@ -501,3 +514,3 @@ logger.throwArgumentError("types must not contain EIP712Domain type", "types.EIP712Domain", types); | ||
if (type.match(/^bytes(\d*)/)) { | ||
return hexlify(arrayify(value)); | ||
return hexlify(logger.getBytes(value)); | ||
} | ||
@@ -507,3 +520,3 @@ | ||
if (type.match(/^u?int/)) { | ||
return BigNumber.from(value).toString(); | ||
return logger.getBigInt(value).toString(); | ||
} | ||
@@ -510,0 +523,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
7
59
Yes
114254
1472
2
1
0
1
1
+ Added@ethersproject/address@6.0.0-beta.2(transitive)
+ Added@ethersproject/bytes@6.0.0-beta.3(transitive)
+ Added@ethersproject/crypto@6.0.0-beta.2(transitive)
+ Added@ethersproject/logger@6.0.0-beta.7(transitive)
+ Added@ethersproject/math@6.0.0-beta.3(transitive)
+ Added@ethersproject/properties@6.0.0-beta.6(transitive)
+ Added@ethersproject/rlp@6.0.0-beta.2(transitive)
+ Added@ethersproject/strings@6.0.0-beta.2(transitive)
+ Added@noble/hashes@1.0.0(transitive)
- Removed@ethersproject/bignumber@^5.6.0
- Removed@ethersproject/keccak256@^5.6.0
- Removed@ethersproject/abstract-provider@5.7.0(transitive)
- Removed@ethersproject/abstract-signer@5.7.0(transitive)
- Removed@ethersproject/address@5.7.0(transitive)
- Removed@ethersproject/base64@5.7.0(transitive)
- Removed@ethersproject/bignumber@5.7.0(transitive)
- Removed@ethersproject/bytes@5.7.0(transitive)
- Removed@ethersproject/constants@5.7.0(transitive)
- Removed@ethersproject/keccak256@5.7.0(transitive)
- Removed@ethersproject/logger@5.7.0(transitive)
- Removed@ethersproject/networks@5.7.1(transitive)
- Removed@ethersproject/properties@5.7.0(transitive)
- Removed@ethersproject/rlp@5.7.0(transitive)
- Removed@ethersproject/signing-key@5.7.0(transitive)
- Removed@ethersproject/strings@5.7.0(transitive)
- Removed@ethersproject/transactions@5.7.0(transitive)
- Removed@ethersproject/web@5.7.1(transitive)
- Removedbn.js@4.12.05.2.1(transitive)
- Removedbrorand@1.1.0(transitive)
- Removedelliptic@6.5.4(transitive)
- Removedhash.js@1.1.7(transitive)
- Removedhmac-drbg@1.0.1(transitive)
- Removedinherits@2.0.4(transitive)
- Removedjs-sha3@0.8.0(transitive)
- Removedminimalistic-assert@1.0.1(transitive)
- Removedminimalistic-crypto-utils@1.0.1(transitive)