UNPKG

@taquito/utils

Version:

converts michelson data and types into convenient JS/TS objects

484 lines (483 loc) 16.5 kB
"use strict"; /** * @packageDocumentation * @module @taquito/utils */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getPkhfromPk = exports.buf2hex = exports.mic2arr = exports.mergebuf = exports.hex2buf = exports.b58cdecode = exports.format = exports.validatePkAndExtractPrefix = exports.verifySignature = exports.prefixLength = exports.Prefix = exports.prefix = exports.VERSION = void 0; exports.encodeExpr = encodeExpr; exports.encodeOpHash = encodeOpHash; exports.b58cencode = b58cencode; exports.b58decode = b58decode; exports.b58decodeL2Address = b58decodeL2Address; exports.encodePubKey = encodePubKey; exports.encodeAddress = encodeAddress; exports.encodeL2Address = encodeL2Address; exports.encodeKey = encodeKey; exports.encodeKeyHash = encodeKeyHash; exports.char2Bytes = char2Bytes; exports.stringToBytes = stringToBytes; exports.bytes2Char = bytes2Char; exports.bytesToString = bytesToString; exports.hex2Bytes = hex2Bytes; exports.toHexBuf = toHexBuf; exports.numToHexBuffer = numToHexBuffer; exports.num2PaddedHex = num2PaddedHex; exports.stripHexPrefix = stripHexPrefix; /* * Some code in this file is originally from sotez and eztz * Copyright (c) 2018 Andrew Kishino * Copyright (c) 2017 Stephen Andrews */ const buffer_1 = require("buffer"); const constants_1 = require("./constants"); const verify_signature_1 = require("./verify-signature"); const blake2b_1 = require("@stablelib/blake2b"); const blakejs_1 = require("blakejs"); const bs58check_1 = require("bs58check"); const errors_1 = require("./errors"); const bignumber_js_1 = require("bignumber.js"); const core_1 = require("@taquito/core"); __exportStar(require("./validators"), exports); var version_1 = require("./version"); Object.defineProperty(exports, "VERSION", { enumerable: true, get: function () { return version_1.VERSION; } }); var constants_2 = require("./constants"); Object.defineProperty(exports, "prefix", { enumerable: true, get: function () { return constants_2.prefix; } }); Object.defineProperty(exports, "Prefix", { enumerable: true, get: function () { return constants_2.Prefix; } }); Object.defineProperty(exports, "prefixLength", { enumerable: true, get: function () { return constants_2.prefixLength; } }); var verify_signature_2 = require("./verify-signature"); Object.defineProperty(exports, "verifySignature", { enumerable: true, get: function () { return verify_signature_2.verifySignature; } }); Object.defineProperty(exports, "validatePkAndExtractPrefix", { enumerable: true, get: function () { return verify_signature_2.validatePkAndExtractPrefix; } }); __exportStar(require("./errors"), exports); var format_1 = require("./format"); Object.defineProperty(exports, "format", { enumerable: true, get: function () { return format_1.format; } }); /** * * @description Hash a string using the BLAKE2b algorithm, base58 encode the hash obtained and appends the prefix 'expr' to it * * @param value Value in hex */ function encodeExpr(value) { const blakeHash = blakejs_1.default.blake2b((0, exports.hex2buf)(value), undefined, 32); return b58cencode(blakeHash, constants_1.prefix['expr']); } /** * * @description Return the operation hash of a signed operation * @param value Value in hex of a signed operation */ function encodeOpHash(value) { const blakeHash = blakejs_1.default.blake2b((0, exports.hex2buf)(value), undefined, 32); return b58cencode(blakeHash, constants_1.prefix.o); } /** * * @description Base58 encode a string or a Uint8Array and append a prefix to it * * @param value Value to base58 encode * @param prefix prefix to append to the encoded string */ function b58cencode(value, prefix) { const payloadAr = typeof value === 'string' ? Uint8Array.from(buffer_1.Buffer.from(value, 'hex')) : value; const n = new Uint8Array(prefix.length + payloadAr.length); n.set(prefix); n.set(payloadAr, prefix.length); return bs58check_1.default.encode(buffer_1.Buffer.from(n.buffer)); } /** * * @description Base58 decode a string and remove the prefix from it * * @param value Value to base58 decode * @param prefix prefix to remove from the decoded string */ const b58cdecode = (enc, prefixArg) => bs58check_1.default.decode(enc).slice(prefixArg.length); exports.b58cdecode = b58cdecode; /** * * @description Base58 decode a string with predefined prefix * * @param value Value to base58 decode */ function b58decode(payload) { const buf = bs58check_1.default.decode(payload); const prefixMap = { [constants_1.prefix.tz1.toString()]: '0000', [constants_1.prefix.tz2.toString()]: '0001', [constants_1.prefix.tz3.toString()]: '0002', [constants_1.prefix.tz4.toString()]: '0003', }; const pref = prefixMap[new Uint8Array(buf.slice(0, 3)).toString()]; if (pref) { // tz addresses const hex = (0, exports.buf2hex)(buf.slice(3)); return pref + hex; } else { // other (kt addresses) return '01' + (0, exports.buf2hex)(buf.slice(3, 42)) + '00'; } } /** * * @description b58 decode a string without predefined prefix * @param value * @returns string of bytes * @deprecated use b58decode instead */ function b58decodeL2Address(payload) { const buf = bs58check_1.default.decode(payload); // tz4 address currently return (0, exports.buf2hex)(buf.slice(3, 42)); } /** * * @description Base58 encode an address using predefined prefix * * @param value Address to base58 encode (tz1, tz2, tz3 or KT1) * @deprecated use encodeAddress instead, same functionality with a more descriptive name */ function encodePubKey(value) { if (value.substring(0, 2) === '00') { const pref = { '0000': constants_1.prefix.tz1, '0001': constants_1.prefix.tz2, '0002': constants_1.prefix.tz3, '0003': constants_1.prefix.tz4, }; return b58cencode(value.substring(4), pref[value.substring(0, 4)]); } return b58cencode(value.substring(2, 42), constants_1.prefix.KT); } /** * * @description Base58 encode an address using predefined prefix (tz1, tz2, tz3, or KT1 without annotation) * * @param value Address to base58 encode (tz1, tz2, tz3 or KT1). Supports value with or without '0x' prefix */ function encodeAddress(value) { if (value.substring(0, 2) === '0x') { value = value.slice(2); } if (value.substring(0, 2) === '00') { const pref = { '0000': constants_1.prefix.tz1, '0001': constants_1.prefix.tz2, '0002': constants_1.prefix.tz3, '0003': constants_1.prefix.tz4, }; return b58cencode(value.substring(4), pref[value.substring(0, 4)]); } return b58cencode(value.substring(2, 42), constants_1.prefix.KT); } /** * * @description Base58 encode an address without predefined prefix * @param value Address to base58 encode (tz4) hex dec * @returns return address * @deprecated use encodeAddress instead */ function encodeL2Address(value) { return b58cencode(value, constants_1.prefix.tz4); } /** * * @description Base58 encode a key according to its prefix * * @param value Key to base58 encode */ function encodeKey(value) { if (value[0] === '0') { const pref = { '00': new Uint8Array([13, 15, 37, 217]), '01': new Uint8Array([3, 254, 226, 86]), '02': new Uint8Array([3, 178, 139, 127]), }; return b58cencode(value.substring(2), pref[value.substring(0, 2)]); } } /** * * @description Base58 encode a key hash according to its prefix * * @param value Key hash to base58 encode */ function encodeKeyHash(value) { if (value[0] === '0') { const pref = { '00': new Uint8Array([6, 161, 159]), '01': new Uint8Array([6, 161, 161]), '02': new Uint8Array([6, 161, 164]), '03': new Uint8Array([6, 161, 167]), }; return b58cencode(value.substring(2), pref[value.substring(0, 2)]); } } /** * * @description Convert an hex string to a Uint8Array * * @param hex Hex string to convert * @throws {@link ValueConversionError} */ const hex2buf = (hex) => { if (hex.length % 2 !== 0) { throw new core_1.InvalidHexStringError(hex, `: Expecting even number of characters`); } const hexDigits = stripHexPrefix(hex); if (!hexDigits.match(/^([\da-f]{2})*$/gi)) { throw new core_1.InvalidHexStringError(hex, `: Only characters 0-9, a-f and A-F are expected. Optionally, it can be prefixed with '0x'`); } const out = new Uint8Array(hexDigits.length / 2); let j = 0; for (let i = 0; i < hexDigits.length; i += 2) { const v = parseInt(hexDigits.slice(i, i + 2), 16); if (Number.isNaN(v)) { throw new errors_1.ValueConversionError(hex, 'Uint8Array'); } out[j++] = v; } return out; }; exports.hex2buf = hex2buf; /** * * @description Merge 2 buffers together * * @param b1 First buffer * @param b2 Second buffer */ const mergebuf = (b1, b2) => { const r = new Uint8Array(b1.length + b2.length); r.set(b1); r.set(b2, b1.length); return r; }; exports.mergebuf = mergebuf; /** * * @description Flatten a michelson json representation to an array * * @param s michelson json */ const mic2arr = function me2(s) { let ret = []; if (Object.prototype.hasOwnProperty.call(s, 'prim')) { if (s.prim === 'Pair') { ret.push(me2(s.args[0])); ret = ret.concat(me2(s.args[1])); } else if (s.prim === 'Elt') { ret = { key: me2(s.args[0]), val: me2(s.args[1]), }; } else if (s.prim === 'True') { ret = true; } else if (s.prim === 'False') { ret = false; } } else if (Array.isArray(s)) { const sc = s.length; for (let i = 0; i < sc; i++) { const n = me2(s[i]); if (typeof n.key !== 'undefined') { if (Array.isArray(ret)) { ret = { keys: [], vals: [], }; } ret.keys.push(n.key); ret.vals.push(n.val); } else { ret.push(n); } } } else if (Object.prototype.hasOwnProperty.call(s, 'string')) { ret = s.string; } else if (Object.prototype.hasOwnProperty.call(s, 'int')) { ret = parseInt(s.int, 10); } else { ret = s; } return ret; }; exports.mic2arr = mic2arr; /** * * @description Convert a Uint8Array to an hex string * * @param buffer Uint8Array to convert */ const buf2hex = (buffer) => { const hexParts = []; buffer.forEach((byte) => { const hex = byte.toString(16); const paddedHex = `00${hex}`.slice(-2); hexParts.push(paddedHex); }); return hexParts.join(''); }; exports.buf2hex = buf2hex; /** * * @description Gets Tezos address (PKH) from Public Key * * @param publicKey Public Key * @returns A string of the Tezos address (PKH) that was derived from the given Public Key */ const getPkhfromPk = (publicKey) => { let encodingPrefix; let prefixLen; const keyPrefix = (0, verify_signature_1.validatePkAndExtractPrefix)(publicKey); const decoded = (0, exports.b58cdecode)(publicKey, constants_1.prefix[keyPrefix]); switch (keyPrefix) { case constants_1.Prefix.EDPK: encodingPrefix = constants_1.prefix[constants_1.Prefix.TZ1]; prefixLen = constants_1.prefixLength[constants_1.Prefix.TZ1]; break; case constants_1.Prefix.SPPK: encodingPrefix = constants_1.prefix[constants_1.Prefix.TZ2]; prefixLen = constants_1.prefixLength[constants_1.Prefix.TZ2]; break; case constants_1.Prefix.P2PK: encodingPrefix = constants_1.prefix[constants_1.Prefix.TZ3]; prefixLen = constants_1.prefixLength[constants_1.Prefix.TZ3]; break; case constants_1.Prefix.BLPK: encodingPrefix = constants_1.prefix[constants_1.Prefix.TZ4]; prefixLen = constants_1.prefixLength[constants_1.Prefix.TZ4]; } const hashed = (0, blake2b_1.hash)(decoded, prefixLen); const result = b58cencode(hashed, encodingPrefix); return result; }; exports.getPkhfromPk = getPkhfromPk; /** * * @description Convert a string to bytes * * @param str String to convert * @deprecated use stringToBytes instead, same functionality with a more descriptive name */ function char2Bytes(str) { return buffer_1.Buffer.from(str, 'utf8').toString('hex'); } /** * * @description Convert a string to a byte string representation * * @param str String to convert */ function stringToBytes(str) { return buffer_1.Buffer.from(str, 'utf8').toString('hex'); } /** * * @description Convert bytes to a string * * @param str Bytes to convert * @deprecated use hexStringToBytes instead, same functionality with a more descriptive name */ function bytes2Char(hex) { return buffer_1.Buffer.from((0, exports.hex2buf)(hex)).toString('utf8'); } /** * * @description Convert byte string representation to string * * @param str byte string to convert */ function bytesToString(hex) { return buffer_1.Buffer.from((0, exports.hex2buf)(hex)).toString('utf8'); } /** * * @description Convert hex string/UintArray/Buffer to bytes * * @param hex String value to convert to bytes */ function hex2Bytes(hex) { const hexDigits = stripHexPrefix(hex); if (!hexDigits.match(/^(0x)?([\da-f]{2})*$/gi)) { throw new core_1.InvalidHexStringError(hex, `: Expecting even number of characters: 0-9, a-z, A-Z, optionally prefixed with 0x`); } return buffer_1.Buffer.from(hexDigits, 'hex'); } /** * * @description Converts a number or Bignumber to hexadecimal string * * @param val The value that will be converted to a hexadecimal string value */ function toHexBuf(val, bitLength = 8) { return buffer_1.Buffer.from(num2PaddedHex(val, bitLength), 'hex'); } function numToHexBuffer(val, bitLength = 8) { return buffer_1.Buffer.from(num2PaddedHex(val, bitLength), 'hex'); } /** * * @description Converts a number or BigNumber to a padded hexadecimal string * @param val The value that will be converted into a padded hexadecimal string value * @param bitLength The length of bits * */ function num2PaddedHex(val, bitLength = 8) { if (new bignumber_js_1.default(val).isPositive()) { const nibbleLength = Math.ceil(bitLength / 4); const hex = val.toString(16); // check whether nibble (4 bits) length is higher or lower than the current hex string length let targetLength = hex.length >= nibbleLength ? hex.length : nibbleLength; // make sure the hex string target length is even targetLength = targetLength % 2 == 0 ? targetLength : targetLength + 1; return padHexWithZero(hex, targetLength); } else { const twosCompliment = new bignumber_js_1.default(2) .pow(bitLength) .minus(new bignumber_js_1.default(val).abs()); return twosCompliment.toString(16); } } function padHexWithZero(hex, targetLength) { const padString = '0'; if (hex.length >= targetLength) { return hex; } else { const padLength = targetLength - hex.length; return padString.repeat(padLength) + hex; } } /** * * @description Strips the first 2 characters of a hex string (0x) * * @param hex string to strip prefix from */ function stripHexPrefix(hex) { return hex.startsWith('0x') ? hex.slice(2) : hex; }