@mavrykdynamics/taquito-michel-codec
Version:
Michelson parser/validator/formatter
322 lines (321 loc) • 10.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hexBytes = exports.parseHex = exports.parseDate = exports.isPairData = exports.isPairType = exports.unpackComb = exports.encodeMavrykID = exports.checkDecodeMavrykID = exports.mavrykPrefix = exports.unpackAnnotations = exports.isNatural = exports.isDecimal = exports.compareBytes = exports.parseBytes = exports.LongInteger = exports.MichelsonTypeError = exports.isMichelsonError = exports.MichelsonError = void 0;
const base58_1 = require("./base58");
const errors_1 = require("./errors");
const taquito_core_1 = require("@mavrykdynamics/taquito-core");
/**
* @category Error
* @description Error that indicates a Michelson failure occurring
*/
class MichelsonError extends taquito_core_1.TaquitoError {
/**
* @param val Value of a AST node caused the error
* @param path Path to a node caused the error
* @param message An error message
*/
constructor(val, message) {
super();
this.val = val;
this.message = message;
this.name = 'MichelsonError';
}
}
exports.MichelsonError = MichelsonError;
function isMichelsonError(err) {
return err instanceof MichelsonError;
}
exports.isMichelsonError = isMichelsonError;
class MichelsonTypeError extends MichelsonError {
/**
* @param val Value of a type node caused the error
* @param data Value of a data node caused the error
* @param message An error message
*/
constructor(val, message, data) {
super(val, message);
this.val = val;
this.message = message;
this.name = 'MichelsonTypeError';
if (data !== undefined) {
this.data = data;
}
}
}
exports.MichelsonTypeError = MichelsonTypeError;
// Ad hoc big integer parser
class LongInteger {
append(c) {
let i = 0;
while (c !== 0 || i < this.buf.length) {
const m = (this.buf[i] || 0) * 10 + c;
this.buf[i++] = m % 256;
c = Math.floor(m / 256);
}
}
constructor(arg) {
this.neg = false;
this.buf = [];
if (arg === undefined) {
return;
}
if (typeof arg === 'string') {
for (let i = 0; i < arg.length; i++) {
const c = arg.charCodeAt(i);
if (i === 0 && c === 0x2d) {
this.neg = true;
}
else {
if (c < 0x30 || c > 0x39) {
throw new errors_1.LongIntegerError(`unexpected character in integer constant "${arg[i]}"`);
}
this.append(c - 0x30);
}
}
}
else if (arg < 0) {
this.neg = true;
this.append(-arg);
}
else {
this.append(arg);
}
}
cmp(arg) {
if (this.neg !== arg.neg) {
return (arg.neg ? 1 : 0) - (this.neg ? 1 : 0);
}
else {
let ret = 0;
if (this.buf.length !== arg.buf.length) {
ret = this.buf.length < arg.buf.length ? -1 : 1;
}
else if (this.buf.length !== 0) {
let i = arg.buf.length - 1;
while (i >= 0 && this.buf[i] === arg.buf[i]) {
i--;
}
ret = i < 0 ? 0 : this.buf[i] < arg.buf[i] ? -1 : 1;
}
return !this.neg ? ret : ret === 0 ? 0 : -ret;
}
}
get sign() {
return this.buf.length === 0 ? 0 : this.neg ? -1 : 1;
}
}
exports.LongInteger = LongInteger;
function parseBytes(s) {
const ret = [];
for (let i = 0; i < s.length; i += 2) {
const x = parseInt(s.slice(i, i + 2), 16);
if (Number.isNaN(x)) {
return null;
}
ret.push(x);
}
return ret;
}
exports.parseBytes = parseBytes;
function compareBytes(a, b) {
if (a.length !== b.length) {
return a.length < b.length ? -1 : 1;
}
else if (a.length !== 0) {
let i = 0;
while (i < a.length && a[i] === b[i]) {
i++;
}
return i === a.length ? 0 : a[i] < b[i] ? -1 : 1;
}
else {
return 0;
}
}
exports.compareBytes = compareBytes;
function isDecimal(x) {
try {
new LongInteger(x);
return true;
}
catch (_a) {
return false;
}
}
exports.isDecimal = isDecimal;
function isNatural(x) {
try {
return new LongInteger(x).sign >= 0;
}
catch (_a) {
return false;
}
}
exports.isNatural = isNatural;
const annRe = /^(@%|@%%|%@|[@:%]([_0-9a-zA-Z][_0-9a-zA-Z.%@]*)?)$/;
function unpackAnnotations(p, opt) {
if (Array.isArray(p)) {
return {};
}
let field;
let type;
let vars;
if (p.annots !== undefined) {
for (const v of p.annots) {
if (v.length !== 0) {
if (!annRe.test(v) ||
(!(opt === null || opt === void 0 ? void 0 : opt.specialVar) && (v === '@%' || v === '@%%')) ||
(!(opt === null || opt === void 0 ? void 0 : opt.specialFields) && v === '%@')) {
throw new MichelsonError(p, `${p.prim}: unexpected annotation: ${v}`);
}
switch (v[0]) {
case '%':
if ((opt === null || opt === void 0 ? void 0 : opt.emptyFields) || v.length > 1) {
field = field || [];
field.push(v);
}
break;
case ':':
if (v.length > 1) {
type = type || [];
type.push(v);
}
break;
case '@':
if ((opt === null || opt === void 0 ? void 0 : opt.emptyVar) || v.length > 1) {
vars = vars || [];
vars.push(v);
}
break;
}
}
}
}
return { f: field, t: type, v: vars };
}
exports.unpackAnnotations = unpackAnnotations;
exports.mavrykPrefix = {
BlockHash: [32, [1, 52]],
OperationHash: [32, [5, 116]],
OperationListHash: [32, [133, 233]],
OperationListListHash: [32, [29, 159, 109]],
ProtocolHash: [32, [2, 170]],
ContextHash: [32, [79, 199]],
ED25519PublicKeyHash: [20, [5, 186, 196]],
SECP256K1PublicKeyHash: [20, [5, 186, 199]],
P256PublicKeyHash: [20, [5, 186, 201]],
ContractHash: [20, [2, 90, 121]],
CryptoboxPublicKeyHash: [16, [153, 103]],
ED25519Seed: [32, [13, 15, 58, 7]],
ED25519PublicKey: [32, [13, 15, 37, 217]],
SECP256K1SecretKey: [32, [17, 162, 224, 201]],
P256SecretKey: [32, [16, 81, 238, 189]],
ED25519EncryptedSeed: [56, [7, 90, 60, 179, 41]],
SECP256K1EncryptedSecretKey: [56, [9, 237, 241, 174, 150]],
P256EncryptedSecretKey: [56, [9, 48, 57, 115, 171]],
SECP256K1PublicKey: [33, [3, 254, 226, 86]],
P256PublicKey: [33, [3, 178, 139, 127]],
SECP256K1Scalar: [33, [38, 248, 136]],
SECP256K1Element: [33, [5, 92, 0]],
ED25519SecretKey: [64, [43, 246, 78, 7]],
ED25519Signature: [64, [9, 245, 205, 134, 18]],
SECP256K1Signature: [64, [13, 115, 101, 19, 63]],
P256Signature: [64, [54, 240, 44, 52]],
GenericSignature: [64, [4, 130, 43]],
ChainID: [4, [87, 82, 0]],
RollupAddress: [20, [1, 128, 120, 31]],
};
function checkDecodeMavrykID(id, ...types) {
const buf = (0, base58_1.decodeBase58Check)(id);
for (const t of types) {
const [plen, p] = exports.mavrykPrefix[t];
if (buf.length === plen + p.length) {
let i = 0;
while (i < p.length && buf[i] === p[i]) {
i++;
}
if (i === p.length) {
return [t, buf.slice(p.length)];
}
}
}
return null;
}
exports.checkDecodeMavrykID = checkDecodeMavrykID;
function encodeMavrykID(id, data) {
const [plen, p] = exports.mavrykPrefix[id];
if (data.length !== plen) {
throw new errors_1.MavrykIdEncodeError(`Incorrect data length for ${id}: ${data.length}`);
}
return (0, base58_1.encodeBase58Check)([...p, ...data]);
}
exports.encodeMavrykID = encodeMavrykID;
function unpackComb(id, v) {
const vv = v;
const args = Array.isArray(vv) ? vv : vv.args;
if (args.length === 2) {
// it's a way to make a union of two interfaces not an interface with two independent properties of union types
const ret = id === 'pair'
? {
prim: 'pair',
args,
}
: {
prim: 'Pair',
args,
};
return ret;
}
return Object.assign(Object.assign({}, (Array.isArray(vv) ? { prim: id } : vv)), { args: [
args[0],
{
prim: id,
args: args.slice(1),
},
] });
}
exports.unpackComb = unpackComb;
function isPairType(t) {
return Array.isArray(t) || t.prim === 'pair';
}
exports.isPairType = isPairType;
function isPairData(d) {
return Array.isArray(d) || ('prim' in d && d.prim === 'Pair');
}
exports.isPairData = isPairData;
const rfc3339Re = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])[T ]([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|[+-]([01][0-9]|2[0-3]):([0-5][0-9]))$/;
function parseDate(a) {
if ('string' in a) {
if (isNatural(a.string)) {
return new Date(parseInt(a.string, 10));
}
else if (rfc3339Re.test(a.string)) {
const x = new Date(a.string);
if (!Number.isNaN(x.valueOf)) {
return x;
}
}
}
else if (isDecimal(a.int)) {
return new Date(parseInt(a.int, 10));
}
return null;
}
exports.parseDate = parseDate;
function parseHex(s) {
const res = [];
for (let i = 0; i < s.length; i += 2) {
const ss = s.slice(i, i + 2);
const x = parseInt(ss, 16);
if (Number.isNaN(x)) {
throw new errors_1.HexParseError(ss);
}
res.push(x);
}
return res;
}
exports.parseHex = parseHex;
function hexBytes(bytes) {
return bytes.map((x) => ((x >> 4) & 0xf).toString(16) + (x & 0xf).toString(16)).join('');
}
exports.hexBytes = hexBytes;