@taquito/utils
Version:
converts michelson data and types into convenient JS/TS objects
484 lines (483 loc) • 16.5 kB
JavaScript
"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;
}