@mavrykdynamics/taquito-michel-codec
Version:
Michelson parser/validator/formatter
5,784 lines • 219 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@mavrykdynamics/taquito-core')) :
typeof define === 'function' && define.amd ? define(['exports', '@mavrykdynamics/taquito-core'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.taquitoMichelCodec = {}, global.taquitoCore));
})(this, (function (exports, taquitoCore) { 'use strict';
// Michelson abstract syntax tree types https://protocol.mavryk.org/whitedoc/michelson.html#concrete-syntax
const sourceReference = Symbol('source_reference');
/**
* @category Error
* @description Error that indicates a failure when performing the scan step when parsing Michelson
*/
class ScanError extends taquitoCore.TaquitoError {
constructor(src, idx, message) {
super();
this.src = src;
this.idx = idx;
this.message = message;
this.name = 'ScanError';
}
}
var Literal;
(function (Literal) {
Literal[Literal["Comment"] = 0] = "Comment";
Literal[Literal["Number"] = 1] = "Number";
Literal[Literal["String"] = 2] = "String";
Literal[Literal["Bytes"] = 3] = "Bytes";
Literal[Literal["Ident"] = 4] = "Ident";
})(Literal || (Literal = {}));
const isSpace = new RegExp('\\s');
const isIdentStart = new RegExp('[:@%_A-Za-z]');
const isIdent = new RegExp('[@%_\\.A-Za-z0-9]');
const isDigit = new RegExp('[0-9]');
const isHex = new RegExp('[0-9a-fA-F]');
function* scan(src, scanComments = false) {
let i = 0;
while (i < src.length) {
// Skip space
while (i < src.length && isSpace.test(src[i])) {
i++;
}
if (i === src.length) {
return;
}
const s = src[i];
const start = i;
if (isIdentStart.test(s)) {
// Identifier
i++;
while (i < src.length && isIdent.test(src[i])) {
i++;
}
yield { t: Literal.Ident, v: src.slice(start, i), first: start, last: i };
}
else if (src.length - i > 1 && src.substring(i, i + 2) === '0x') {
// Bytes
i += 2;
while (i < src.length && isHex.test(src[i])) {
i++;
}
if (((i - start) & 1) !== 0) {
throw new ScanError(src, i, 'Bytes literal length is expected to be power of two');
}
yield { t: Literal.Bytes, v: src.slice(start, i), first: start, last: i };
}
else if (isDigit.test(s) || s === '-') {
// Number
if (s === '-') {
i++;
}
const ii = i;
while (i < src.length && isDigit.test(src[i])) {
i++;
}
if (ii === i) {
throw new ScanError(src, i, 'Number literal is too short');
}
yield { t: Literal.Number, v: src.slice(start, i), first: start, last: i };
}
else if (s === '"') {
// String
i++;
let esc = false;
for (; i < src.length && (esc || src[i] !== '"'); i++) {
if (!esc && src[i] === '\\') {
esc = true;
}
else {
esc = false;
}
}
if (i === src.length) {
throw new ScanError(src, i, 'Unterminated string literal');
}
i++;
yield { t: Literal.String, v: src.slice(start, i), first: start, last: i };
}
else if (s === '#') {
// Comment
i++;
while (i < src.length && src[i] !== '\n') {
i++;
}
if (scanComments) {
yield { t: Literal.Comment, v: src.slice(start, i), first: start, last: i };
}
}
else if (src.length - i > 1 && src.substring(i, i + 2) === '/*') {
// C style comment
i += 2;
while (i < src.length && !(src.length - i > 1 && src.substring(i, i + 2) === '*/')) {
i++;
}
if (i === src.length) {
throw new ScanError(src, i, 'Unterminated C style comment');
}
i += 2;
if (scanComments) {
yield { t: Literal.Comment, v: src.slice(start, i), first: start, last: i };
}
}
else if (s === '(' || s === ')' || s === '{' || s === '}' || s === ';') {
i++;
yield { t: s, v: s, first: start, last: i };
}
else {
throw new ScanError(src, i, `Invalid character at offset ${i}: \`${s}'`);
}
}
}
// Michelson types
const refContract = Symbol('ref_contract');
exports.Protocol = void 0;
(function (Protocol) {
Protocol["Ps9mPmXa"] = "Ps9mPmXaRzmzk35gbAYNCAw6UXdE2qoABTHbN2oEEc1qM7CwT9P";
Protocol["PtAtLas"] = "PtAtLasomUEW99aVhVTrqjCHjJSpFUa8uHNEAEamx9v2SNeTaNp";
Protocol["PtBoreas"] = "PtBzwViMCC1gfm98y5TDKqz2e3vjBXPAUoWu7jfEcN6yj2ZhCyT";
Protocol["ProtoALpha"] = "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK";
})(exports.Protocol || (exports.Protocol = {}));
const DefaultProtocol = exports.Protocol.PtAtLas;
const protoLevel = {
Ps9mPmXaRzmzk35gbAYNCAw6UXdE2qoABTHbN2oEEc1qM7CwT9P: 0,
PtAtLasomUEW99aVhVTrqjCHjJSpFUa8uHNEAEamx9v2SNeTaNp: 19,
PtBzwViMCC1gfm98y5TDKqz2e3vjBXPAUoWu7jfEcN6yj2ZhCyT: 20,
ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK: 21,
};
function ProtoGreaterOrEqual(a, b) {
return protoLevel[a] >= protoLevel[b];
}
function ProtoInferiorTo(a, b) {
return protoLevel[a] < protoLevel[b];
}
/**
* @category Error
* @description Error that indicates macros failed to be expanded
*/
class MacroError extends taquitoCore.TaquitoError {
constructor(prim, message) {
super();
this.prim = prim;
this.message = message;
this.name = 'MacroError';
}
}
function assertArgs$1(ex, n) {
var _a, _b;
if ((n === 0 && ex.args === undefined) || ((_a = ex.args) === null || _a === void 0 ? void 0 : _a.length) === n) {
return true;
}
throw new MacroError(ex, `macro ${ex.prim} expects ${n} arguments, was given ${(_b = ex.args) === null || _b === void 0 ? void 0 : _b.length}`);
}
function assertNoAnnots(ex) {
if (ex.annots === undefined) {
return true;
}
throw new MacroError(ex, `unexpected annotation on macro ${ex.prim}: ${ex.annots}`);
}
function assertIntArg(ex, arg) {
if ('int' in arg) {
return true;
}
throw new MacroError(ex, `macro ${ex.prim} expects int argument`);
}
function parsePairUnpairExpr(p, expr, annotations, agg) {
let i = 0;
let ai = 0;
const ann = [null, null];
// Left expression
let lexpr;
if (i === expr.length) {
throw new MacroError(p, `unexpected end: ${p.prim}`);
}
let c = expr[i++];
switch (c) {
case 'P': {
const { r, n, an } = parsePairUnpairExpr(p, expr.slice(i), annotations.slice(ai), agg);
lexpr = r;
i += n;
ai += an;
break;
}
case 'A':
if (ai !== annotations.length) {
ann[0] = annotations[ai++];
}
break;
default:
throw new MacroError(p, `${p.prim}: unexpected character: ${c}`);
}
// Right expression
let rexpr;
if (i === expr.length) {
throw new MacroError(p, `unexpected end: ${p.prim}`);
}
c = expr[i++];
switch (c) {
case 'P': {
const { r, n, an } = parsePairUnpairExpr(p, expr.slice(i), annotations.slice(ai), agg);
rexpr = r.map(([v, a]) => [v + 1, a]);
i += n;
ai += an;
break;
}
case 'I':
if (ai !== annotations.length) {
ann[1] = annotations[ai++];
}
break;
default:
throw new MacroError(p, `${p.prim}: unexpected character: ${c}`);
}
return { r: agg(lexpr, rexpr, [0, ann]), n: i, an: ai };
}
function parseSetMapCadr(p, expr, vann, term) {
const c = expr[0];
switch (c) {
case 'A':
return expr.length > 1
? [
{ prim: 'DUP' },
{
prim: 'DIP',
args: [
[{ prim: 'CAR', annots: ['@%%'] }, parseSetMapCadr(p, expr.slice(1), [], term)],
],
},
{ prim: 'CDR', annots: ['@%%'] },
{ prim: 'SWAP' },
{ prim: 'PAIR', annots: ['%@', '%@', ...vann] },
]
: term.a;
case 'D':
return expr.length > 1
? [
{ prim: 'DUP' },
{
prim: 'DIP',
args: [
[{ prim: 'CDR', annots: ['@%%'] }, parseSetMapCadr(p, expr.slice(1), [], term)],
],
},
{ prim: 'CAR', annots: ['@%%'] },
{ prim: 'PAIR', annots: ['%@', '%@', ...vann] },
]
: term.d;
default:
throw new MacroError(p, `${p.prim}: unexpected character: ${c}`);
}
}
function trimLast(a, v) {
let l = a.length;
while (l > 0 && a[l - 1] === v) {
l--;
}
return a.slice(0, l);
}
function filterAnnotations(a) {
const fields = [];
const rest = [];
if (a !== undefined) {
for (const v of a) {
(v.length !== 0 && v[0] === '%' ? fields : rest).push(v);
}
}
return { fields, rest };
}
function mkPrim({ prim, annots, args }) {
return Object.assign(Object.assign({ prim }, (annots && { annots })), (args && { args }));
}
const pairRe = /^P[PAI]{3,}R$/;
const unpairRe = /^UNP[PAI]{2,}R$/;
const cadrRe = /^C[AD]{2,}R$/;
const setCadrRe = /^SET_C[AD]+R$/;
const mapCadrRe = /^MAP_C[AD]+R$/;
const diipRe = /^DI{2,}P$/;
const duupRe = /^DU+P$/;
function expandMacros(ex, opt) {
const proto = (opt === null || opt === void 0 ? void 0 : opt.protocol) || DefaultProtocol;
function mayRename(annots) {
return annots !== undefined ? [{ prim: 'RENAME', annots }] : [];
}
switch (ex.prim) {
// Compare
case 'CMPEQ':
case 'CMPNEQ':
case 'CMPLT':
case 'CMPGT':
case 'CMPLE':
case 'CMPGE':
if (assertArgs$1(ex, 0)) {
return [{ prim: 'COMPARE' }, mkPrim({ prim: ex.prim.slice(3), annots: ex.annots })];
}
break;
case 'IFEQ':
case 'IFNEQ':
case 'IFLT':
case 'IFGT':
case 'IFLE':
case 'IFGE':
if (assertArgs$1(ex, 2)) {
return [
{ prim: ex.prim.slice(2) },
mkPrim({ prim: 'IF', annots: ex.annots, args: ex.args }),
];
}
break;
case 'IFCMPEQ':
case 'IFCMPNEQ':
case 'IFCMPLT':
case 'IFCMPGT':
case 'IFCMPLE':
case 'IFCMPGE':
if (assertArgs$1(ex, 2)) {
return [
{ prim: 'COMPARE' },
{ prim: ex.prim.slice(5) },
mkPrim({ prim: 'IF', annots: ex.annots, args: ex.args }),
];
}
break;
// Fail
case 'FAIL':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [{ prim: 'UNIT' }, { prim: 'FAILWITH' }];
}
break;
// Assertion macros
case 'ASSERT':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [
{
prim: 'IF',
args: [[], [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_EQ':
case 'ASSERT_NEQ':
case 'ASSERT_LT':
case 'ASSERT_GT':
case 'ASSERT_LE':
case 'ASSERT_GE':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [
{ prim: ex.prim.slice(7) },
{
prim: 'IF',
args: [[], [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_CMPEQ':
case 'ASSERT_CMPNEQ':
case 'ASSERT_CMPLT':
case 'ASSERT_CMPGT':
case 'ASSERT_CMPLE':
case 'ASSERT_CMPGE':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [
[{ prim: 'COMPARE' }, { prim: ex.prim.slice(10) }],
{
prim: 'IF',
args: [[], [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_NONE':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [
{
prim: 'IF_NONE',
args: [[], [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_SOME':
if (assertArgs$1(ex, 0)) {
return [
{
prim: 'IF_NONE',
args: [[[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]], mayRename(ex.annots)],
},
];
}
break;
case 'ASSERT_LEFT':
if (assertArgs$1(ex, 0)) {
return [
{
prim: 'IF_LEFT',
args: [mayRename(ex.annots), [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_RIGHT':
if (assertArgs$1(ex, 0)) {
return [
{
prim: 'IF_LEFT',
args: [[[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]], mayRename(ex.annots)],
},
];
}
break;
// Syntactic conveniences
case 'IF_SOME':
if (assertArgs$1(ex, 2)) {
return [mkPrim({ prim: 'IF_NONE', annots: ex.annots, args: [ex.args[1], ex.args[0]] })];
}
break;
case 'IF_RIGHT':
if (assertArgs$1(ex, 2)) {
return [mkPrim({ prim: 'IF_LEFT', annots: ex.annots, args: [ex.args[1], ex.args[0]] })];
}
break;
// CAR/CDR n
case 'CAR':
case 'CDR':
if (ex.args !== undefined) {
if (assertArgs$1(ex, 1) && assertIntArg(ex, ex.args[0])) {
const n = parseInt(ex.args[0].int, 10);
return mkPrim({
prim: 'GET',
args: [{ int: ex.prim === 'CAR' ? String(n * 2 + 1) : String(n * 2) }],
annots: ex.annots,
});
}
}
else {
return ex;
}
}
// More syntactic conveniences
// PAPPAIIR macro
if (pairRe.test(ex.prim)) {
if (assertArgs$1(ex, 0)) {
const { fields, rest } = filterAnnotations(ex.annots);
const { r } = parsePairUnpairExpr(ex, ex.prim.slice(1), fields, (l, r, top) => [
...(l || []),
...(r || []),
top,
]);
return r.map(([v, a], i) => {
const ann = [
...trimLast(a, null).map((v) => (v === null ? '%' : v)),
...(v === 0 && i === r.length - 1 ? rest : []),
];
const leaf = mkPrim({ prim: 'PAIR', annots: ann.length !== 0 ? ann : undefined });
return v === 0
? leaf
: {
prim: 'DIP',
args: v === 1 ? [[leaf]] : [{ int: String(v) }, [leaf]],
};
});
}
}
// UNPAPPAIIR macro
if (unpairRe.test(ex.prim)) {
if (ProtoInferiorTo(proto, exports.Protocol.PtAtLas) && assertArgs$1(ex, 0)) {
const { r } = parsePairUnpairExpr(ex, ex.prim.slice(3), ex.annots || [], (l, r, top) => [
top,
...(r || []),
...(l || []),
]);
return r.map(([v, a]) => {
const leaf = [
{ prim: 'DUP' },
mkPrim({ prim: 'CAR', annots: a[0] !== null ? [a[0]] : undefined }),
{
prim: 'DIP',
args: [[mkPrim({ prim: 'CDR', annots: a[1] !== null ? [a[1]] : undefined })]],
},
];
return v === 0
? leaf
: {
prim: 'DIP',
args: v === 1 ? [[leaf]] : [{ int: String(v) }, [leaf]],
};
});
}
else {
if (ex.prim === 'UNPAIR') {
return ex;
}
if (assertArgs$1(ex, 0)) {
// 008_edo: annotations are deprecated
const { r } = parsePairUnpairExpr(ex, ex.prim.slice(3), [], (l, r, top) => [
top,
...(r || []),
...(l || []),
]);
return r.map(([v]) => {
const leaf = mkPrim({
prim: 'UNPAIR',
});
return v === 0
? leaf
: {
prim: 'DIP',
args: v === 1 ? [[leaf]] : [{ int: String(v) }, [leaf]],
};
});
}
}
}
// C[AD]+R macro
if (cadrRe.test(ex.prim)) {
if (assertArgs$1(ex, 0)) {
const ch = [...ex.prim.slice(1, ex.prim.length - 1)];
return ch.map((c, i) => {
const ann = i === ch.length - 1 ? ex.annots : undefined;
switch (c) {
case 'A':
return mkPrim({ prim: 'CAR', annots: ann });
case 'D':
return mkPrim({ prim: 'CDR', annots: ann });
default:
throw new MacroError(ex, `unexpected character: ${c}`);
}
});
}
}
// SET_C[AD]+R macro
if (setCadrRe.test(ex.prim)) {
if (assertArgs$1(ex, 0)) {
const { fields, rest } = filterAnnotations(ex.annots);
if (fields.length > 1) {
throw new MacroError(ex, `unexpected annotation on macro ${ex.prim}: ${fields}`);
}
const term = fields.length !== 0
? {
a: [
{ prim: 'DUP' },
{ prim: 'CAR', annots: fields },
{ prim: 'DROP' },
{ prim: 'CDR', annots: ['@%%'] },
{ prim: 'SWAP' },
{ prim: 'PAIR', annots: [fields[0], '%@'] },
],
d: [
{ prim: 'DUP' },
{ prim: 'CDR', annots: fields },
{ prim: 'DROP' },
{ prim: 'CAR', annots: ['@%%'] },
{ prim: 'PAIR', annots: ['%@', fields[0]] },
],
}
: {
a: [
{ prim: 'CDR', annots: ['@%%'] },
{ prim: 'SWAP' },
{ prim: 'PAIR', annots: ['%', '%@'] },
],
d: [
{ prim: 'CAR', annots: ['@%%'] },
{ prim: 'PAIR', annots: ['%@', '%'] },
],
};
return parseSetMapCadr(ex, ex.prim.slice(5, ex.prim.length - 1), rest, term);
}
}
// MAP_C[AD]+R macro
if (mapCadrRe.test(ex.prim)) {
if (assertArgs$1(ex, 1)) {
const { fields } = filterAnnotations(ex.annots);
if (fields.length > 1) {
throw new MacroError(ex, `unexpected annotation on macro ${ex.prim}: ${fields}`);
}
const term = {
a: [
{ prim: 'DUP' },
{ prim: 'CDR', annots: ['@%%'] },
{
prim: 'DIP',
args: [
[
mkPrim({
prim: 'CAR',
annots: fields.length !== 0 ? ['@' + fields[0].slice(1)] : undefined,
}),
ex.args[0],
],
],
},
{ prim: 'SWAP' },
{ prim: 'PAIR', annots: [fields.length !== 0 ? fields[0] : '%', '%@'] },
],
d: [
{ prim: 'DUP' },
mkPrim({
prim: 'CDR',
annots: fields.length !== 0 ? ['@' + fields[0].slice(1)] : undefined,
}),
ex.args[0],
{ prim: 'SWAP' },
{ prim: 'CAR', annots: ['@%%'] },
{ prim: 'PAIR', annots: ['%@', fields.length !== 0 ? fields[0] : '%'] },
],
};
return parseSetMapCadr(ex, ex.prim.slice(5, ex.prim.length - 1), [], term);
}
}
// Expand deprecated DI...IP to [DIP n]
if (diipRe.test(ex.prim)) {
if (assertArgs$1(ex, 1)) {
let n = 0;
while (ex.prim[1 + n] === 'I') {
n++;
}
return mkPrim({ prim: 'DIP', args: [{ int: String(n) }, ex.args[0]] });
}
}
// Expand DU...UP and DUP n
if (duupRe.test(ex.prim)) {
let n = 0;
while (ex.prim[1 + n] === 'U') {
n++;
}
if (ProtoInferiorTo(proto, exports.Protocol.PtAtLas)) {
if (n === 1) {
if (ex.args === undefined) {
return ex; // skip
}
if (assertArgs$1(ex, 1) && assertIntArg(ex, ex.args[0])) {
n = parseInt(ex.args[0].int, 10);
}
}
else {
assertArgs$1(ex, 0);
}
if (n === 1) {
return [mkPrim({ prim: 'DUP', annots: ex.annots })];
}
else if (n === 2) {
return [
{
prim: 'DIP',
args: [[mkPrim({ prim: 'DUP', annots: ex.annots })]],
},
{ prim: 'SWAP' },
];
}
else {
return [
{
prim: 'DIP',
args: [{ int: String(n - 1) }, [mkPrim({ prim: 'DUP', annots: ex.annots })]],
},
{
prim: 'DIG',
args: [{ int: String(n) }],
},
];
}
}
else {
if (n === 1) {
return ex;
}
if (assertArgs$1(ex, 0)) {
return mkPrim({ prim: 'DUP', args: [{ int: String(n) }], annots: ex.annots });
}
}
}
return ex;
}
function expandGlobalConstants(ex, hashAndValue) {
if (ex.args !== undefined &&
ex.args.length === 1 &&
'string' in ex.args[0] &&
ex.args[0].string in hashAndValue) {
return hashAndValue[ex.args[0].string];
}
return ex;
}
/**
* @category Error
* @description Error that indicates a failure when parsing Micheline expressions
*/
class MichelineParseError extends taquitoCore.TaquitoError {
/**
* @param token A token caused the error
* @param message An error message
*/
constructor(token, message) {
super();
this.token = token;
this.message = message;
this.name = 'MichelineParseError';
}
}
/**
* @category Error
* @description Error indicates a failure when parsing Micheline JSON
*/
class JSONParseError extends taquitoCore.TaquitoError {
/**
* @param node A node caused the error
* @param message An error message
*/
constructor(node, message) {
super();
this.node = node;
this.message = message;
this.name = 'JSONParseError';
}
}
const errEOF = new MichelineParseError(null, 'Unexpected EOF');
function isAnnotation(tok) {
return tok.t === Literal.Ident && (tok.v[0] === '@' || tok.v[0] === '%' || tok.v[0] === ':');
}
const intRe = new RegExp('^-?[0-9]+$');
const bytesRe = new RegExp('^([0-9a-fA-F]{2})*$');
/**
* Converts and validates Michelson expressions between JSON-based Michelson and Micheline
*
* Pretty Print a Michelson Smart Contract:
* ```
* const contract = await Mavryk.contract.at("KT1Vsw3kh9638gqWoHTjvHCoHLPKvCbMVbCg");
* const p = new Parser();
*
* const michelsonCode = p.parseJSON(contract.script.code);
* const storage = p.parseJSON(contract.script.storage);
*
* console.log("Pretty print Michelson smart contract:");
* console.log(emitMicheline(michelsonCode, {indent:" ", newline: "\n",}));
*
* console.log("Pretty print Storage:");
* console.log(emitMicheline(storage, {indent:" ", newline: "\n",}));
* ```
*
* Encode a Michelson expression for initial storage of a smart contract
* ```
* const src = `(Pair (Pair { Elt 1
* (Pair (Pair "mv1JQ19UKK5w264P8SDJmwjHsrXZASegkXrH" "mv18Cw7psUrAAPBpXYd9CtCpHg9EgjHP9KTe")
* 0x0501000000026869) }
* 10000000)
* (Pair 2 333))`;
*
* const p = new Parser();
*
* const exp = p.parseMichelineExpression(src);
* console.log(JSON.stringify(exp));
* ```
*/
class Parser {
constructor(opt) {
this.opt = opt;
}
expand(ex) {
var _a, _b, _c;
if (((_a = this.opt) === null || _a === void 0 ? void 0 : _a.expandGlobalConstant) !== undefined && ex.prim === 'constant') {
const ret = expandGlobalConstants(ex, this.opt.expandGlobalConstant);
if (ret !== ex) {
ret[sourceReference] = Object.assign(Object.assign({}, (ex[sourceReference] || { first: 0, last: 0 })), { globalConstant: ex });
}
return ret;
}
if (((_b = this.opt) === null || _b === void 0 ? void 0 : _b.expandMacros) !== undefined ? (_c = this.opt) === null || _c === void 0 ? void 0 : _c.expandMacros : true) {
const ret = expandMacros(ex, this.opt);
if (ret !== ex) {
ret[sourceReference] = Object.assign(Object.assign({}, (ex[sourceReference] || { first: 0, last: 0 })), { macro: ex });
}
return ret;
}
else {
return ex;
}
}
parseListExpr(scanner, start) {
var _a;
const ref = {
first: start.first,
last: start.last,
};
const expectBracket = start.t === '(';
let tok;
if (expectBracket) {
tok = scanner.next();
if (tok.done) {
throw errEOF;
}
ref.last = tok.value.last;
}
else {
tok = { value: start };
}
if (tok.value.t !== Literal.Ident) {
throw new MichelineParseError(tok.value, `not an identifier: ${tok.value.v}`);
}
const ret = {
prim: tok.value.v,
[sourceReference]: ref,
};
for (;;) {
const tok = scanner.next();
if (tok.done) {
if (expectBracket) {
throw errEOF;
}
break;
}
else if (tok.value.t === ')') {
if (!expectBracket) {
throw new MichelineParseError(tok.value, 'unexpected closing bracket');
}
ref.last = tok.value.last;
break;
}
else if (isAnnotation(tok.value)) {
ret.annots = ret.annots || [];
ret.annots.push(tok.value.v);
ref.last = tok.value.last;
}
else {
ret.args = ret.args || [];
const arg = this.parseExpr(scanner, tok.value);
ref.last = ((_a = arg[sourceReference]) === null || _a === void 0 ? void 0 : _a.last) || ref.last;
ret.args.push(arg);
}
}
return this.expand(ret);
}
parseArgs(scanner, start) {
var _a;
// Identifier with arguments
const ref = {
first: start.first,
last: start.last,
};
const p = {
prim: start.v,
[sourceReference]: ref,
};
for (;;) {
const t = scanner.next();
if (t.done || t.value.t === '}' || t.value.t === ';') {
return [p, t];
}
if (isAnnotation(t.value)) {
ref.last = t.value.last;
p.annots = p.annots || [];
p.annots.push(t.value.v);
}
else {
const arg = this.parseExpr(scanner, t.value);
ref.last = ((_a = arg[sourceReference]) === null || _a === void 0 ? void 0 : _a.last) || ref.last;
p.args = p.args || [];
p.args.push(arg);
}
}
}
parseSequenceExpr(scanner, start) {
var _a, _b;
const ref = {
first: start.first,
last: start.last,
};
const seq = [];
seq[sourceReference] = ref;
const expectBracket = start.t === '{';
let tok = start.t === '{' ? null : { value: start };
for (;;) {
if (tok === null) {
tok = scanner.next();
if (!tok.done) {
ref.last = tok.value.last;
}
}
if (tok.done) {
if (expectBracket) {
throw errEOF;
}
else {
return seq;
}
}
if (tok.value.t === '}') {
if (!expectBracket) {
throw new MichelineParseError(tok.value, 'unexpected closing bracket');
}
else {
return seq;
}
}
else if (tok.value.t === Literal.Ident) {
// Identifier with arguments
const [itm, n] = this.parseArgs(scanner, tok.value);
ref.last = ((_a = itm[sourceReference]) === null || _a === void 0 ? void 0 : _a.last) || ref.last;
seq.push(this.expand(itm));
tok = n;
}
else {
// Other
const ex = this.parseExpr(scanner, tok.value);
ref.last = ((_b = ex[sourceReference]) === null || _b === void 0 ? void 0 : _b.last) || ref.last;
seq.push(ex);
tok = null;
}
if (tok === null) {
tok = scanner.next();
if (!tok.done) {
ref.last = tok.value.last;
}
}
if (!tok.done && tok.value.t === ';') {
tok = null;
}
}
}
parseExpr(scanner, tok) {
switch (tok.t) {
case Literal.Ident:
return this.expand({
prim: tok.v,
[sourceReference]: { first: tok.first, last: tok.last },
});
case Literal.Number:
return { int: tok.v, [sourceReference]: { first: tok.first, last: tok.last } };
case Literal.String:
return {
string: JSON.parse(tok.v),
[sourceReference]: { first: tok.first, last: tok.last },
};
case Literal.Bytes:
return { bytes: tok.v.slice(2), [sourceReference]: { first: tok.first, last: tok.last } };
case '{':
return this.parseSequenceExpr(scanner, tok);
default:
return this.parseListExpr(scanner, tok);
}
}
/**
* Parses a Micheline sequence expression, such as smart contract source. Enclosing curly brackets may be omitted.
* @param src A Micheline sequence `{parameter ...; storage int; code { DUP ; ...};}` or `parameter ...; storage int; code { DUP ; ...};`
*/
parseSequence(src) {
if (typeof src !== 'string') {
throw new TypeError(`string type was expected, got ${typeof src} instead`);
}
const scanner = scan(src);
const tok = scanner.next();
if (tok.done) {
return null;
}
return this.parseSequenceExpr(scanner, tok.value);
}
/**
* Parse a Micheline sequence expression. Enclosing curly brackets may be omitted.
* @param src A Michelson list expression such as `(Pair {Elt "0" 0} 0)` or `Pair {Elt "0" 0} 0`
* @returns An AST node or null for empty document.
*/
parseList(src) {
if (typeof src !== 'string') {
throw new TypeError(`string type was expected, got ${typeof src} instead`);
}
const scanner = scan(src);
const tok = scanner.next();
if (tok.done) {
return null;
}
return this.parseListExpr(scanner, tok.value);
}
/**
* Parse any Michelson expression
* @param src A Michelson expression such as `(Pair {Elt "0" 0} 0)` or `{parameter ...; storage int; code { DUP ; ...};}`
* @returns An AST node or null for empty document.
*/
parseMichelineExpression(src) {
if (typeof src !== 'string') {
throw new TypeError(`string type was expected, got ${typeof src} instead`);
}
const scanner = scan(src);
const tok = scanner.next();
if (tok.done) {
return null;
}
return this.parseExpr(scanner, tok.value);
}
/**
* Parse a Micheline sequence expression, such as smart contract source. Enclosing curly brackets may be omitted.
* An alias for `parseSequence`
* @param src A Micheline sequence `{parameter ...; storage int; code { DUP ; ...};}` or `parameter ...; storage int; code { DUP ; ...};`
*/
parseScript(src) {
return this.parseSequence(src);
}
/**
* Parse a Micheline sequence expression. Enclosing curly brackets may be omitted.
* An alias for `parseList`
* @param src A Michelson list expression such as `(Pair {Elt "0" 0} 0)` or `Pair {Elt "0" 0} 0`
* @returns An AST node or null for empty document.
*/
parseData(src) {
return this.parseList(src);
}
/**
* Takes a JSON-encoded Michelson, validates it, strips away unneeded properties and optionally expands macros (See {@link ParserOptions}).
* @param src An object containing JSON-encoded Michelson, usually returned by `JSON.parse()`
*/
parseJSON(src) {
if (typeof src !== 'object') {
throw new TypeError(`object type was expected, got ${typeof src} instead`);
}
if (Array.isArray(src)) {
const ret = [];
for (const n of src) {
if (n === null || typeof n !== 'object') {
throw new JSONParseError(n, `unexpected sequence element: ${n}`);
}
ret.push(this.parseJSON(n));
}
return ret;
}
else if ('prim' in src) {
const p = src;
if (typeof p.prim === 'string' &&
(p.annots === undefined || Array.isArray(p.annots)) &&
(p.args === undefined || Array.isArray(p.args))) {
const ret = {
prim: p.prim,
};
if (p.annots !== undefined) {
for (const a of p.annots) {
if (typeof a !== 'string') {
throw new JSONParseError(a, `string expected: ${a}`);
}
}
ret.annots = p.annots;
}
if (p.args !== undefined) {
ret.args = [];
for (const a of p.args) {
if (a === null || typeof a !== 'object') {
throw new JSONParseError(a, `unexpected argument: ${a}`);
}
ret.args.push(this.parseJSON(a));
}
}
return this.expand(ret);
}
throw new JSONParseError(src, `malformed prim expression: ${src}`);
}
else if ('string' in src) {
if (typeof src.string === 'string') {
return { string: src.string };
}
throw new JSONParseError(src, `malformed string literal: ${src}`);
}
else if ('int' in src) {
if (typeof src.int === 'string' && intRe.test(src.int)) {
return { int: src.int };
}
throw new JSONParseError(src, `malformed int literal: ${src}`);
}
else if ('bytes' in src) {
if (typeof src.bytes === 'string' &&
bytesRe.test(src.bytes)) {
return { bytes: src.bytes };
}
throw new JSONParseError(src, `malformed bytes literal: ${src}`);
}
else {
throw new JSONParseError(src, `unexpected object: ${src}`);
}
}
}
class Formatter {
constructor(opt, lev = 0) {
this.opt = opt;
this.lev = lev;
}
indent(n = 0) {
var _a;
let ret = '';
if (((_a = this.opt) === null || _a === void 0 ? void 0 : _a.indent) !== undefined) {
for (let i = this.lev + n; i > 0; i--) {
ret += this.opt.indent;
}
}
return ret;
}
get lf() {
var _a;
return ((_a = this.opt) === null || _a === void 0 ? void 0 : _a.newline) || '';
}
get lfsp() {
var _a;
return ((_a = this.opt) === null || _a === void 0 ? void 0 : _a.newline) || ' ';
}
down(n) {
return new Formatter(this.opt, this.lev + n);
}
}
function hasArgs(node) {
return ('prim' in node &&
((node.annots !== undefined && node.annots.length !== 0) ||
(node.args !== undefined && node.args.length !== 0)));
}
function isMultiline(node) {
if (node.args !== undefined) {
for (const a of node.args) {
if (Array.isArray(a) || hasArgs(a)) {
return true;
}
}
}
return false;
}
function emitExpr(node, f, foldMacros) {
var _a;
const macro = (_a = node[sourceReference]) === null || _a === void 0 ? void 0 : _a.macro;
if (foldMacros && macro) {
return emitExpr(macro, f, foldMacros);
}
if (Array.isArray(node)) {
return emitSeq(node, f, foldMacros);
}
else if ('string' in node) {
return JSON.stringify(node.string);
}
else if ('int' in node) {
return node.int;
}
else if ('bytes' in node) {
return '0x' + node.bytes;
}
else {
if ((node.annots === undefined || node.annots.length === 0) &&
(node.args === undefined || node.args.length === 0)) {
return node.prim;
}
let ret = '(' + node.prim;
if (node.annots !== undefined) {
for (const a of node.annots) {
ret += ' ' + a;
}
}
if (node.args !== undefined) {
const multiline = isMultiline(node);
for (const a of node.args) {
if (multiline) {
ret += f.lfsp + f.indent(1) + emitExpr(a, f.down(1), foldMacros);
}
else {
ret += ' ' + emitExpr(a, f, foldMacros);
}
}
}
return ret + ')';
}
}
function emitSeq(node, f, foldMacros) {
let ret = '{' + f.lf;
let i = node.length;
for (const el of node) {
ret += f.indent(1);
if ('prim' in el) {
ret += el.prim;
if (el.annots !== undefined) {
for (const a of el.annots) {
ret += ' ' + a;
}
}
if (el.args !== undefined) {
const multiline = isMultiline(el);
for (const a of el.args) {
if (multiline) {
ret += f.lfsp + f.indent(2) + emitExpr(a, f.down(2), foldMacros);
}
else {
ret += ' ' + emitExpr(a, f, foldMacros);
}
}
}
}
else {
ret += emitExpr(el, f.down(1), foldMacros);
}
ret += i > 1 ? ';' + f.lfsp : f.lf;
i--;
}
return ret + f.indent() + '}';
}
/**
* Formats Micheline expression
* @param expr An AST node
* @param opt Options
*/
function emitMicheline(expr, opt, foldMacros = false) {
if (typeof expr !== 'object') {
throw new TypeError(`object type was expected, got ${typeof expr} instead`);
}
return emitExpr(expr, new Formatter(opt), foldMacros);
}
const H = [
0x6a09e667 | 0,
0xbb67ae85 | 0,
0x3c6ef372 | 0,
0xa54ff53a | 0,
0x510e527f | 0,
0x9b05688c | 0,
0x1f83d9ab | 0,
0x5be0cd19 | 0,
];
const K = [
0x428a2f98 | 0,
0x71374491 | 0,
0xb5c0fbcf | 0,
0xe9b5dba5 | 0,
0x3956c25b | 0,
0x59f111f1 | 0,
0x923f82a4 | 0,
0xab1c5ed5 | 0,
0xd807aa98 | 0,
0x12835b01 | 0,
0x243185be | 0,
0x550c7dc3 | 0,
0x72be5d74 | 0,
0x80deb1fe | 0,
0x9bdc06a7 | 0,
0xc19bf174 | 0,
0xe49b69c1 | 0,
0xefbe4786 | 0,
0x0fc19dc6 | 0,
0x240ca1cc | 0,
0x2de92c6f | 0,
0x4a7484aa | 0,
0x5cb0a9dc | 0,
0x76f988da | 0,
0x983e5152 | 0,
0xa831c66d | 0,
0xb00327c8 | 0,
0xbf597fc7 | 0,
0xc6e00bf3 | 0,
0xd5a79147 | 0,
0x06ca6351 | 0,
0x14292967 | 0,
0x27b70a85 | 0,
0x2e1b2138 | 0,
0x4d2c6dfc | 0,
0x53380d13 | 0,
0x650a7354 | 0,
0x766a0abb | 0,
0x81c2c92e | 0,
0x92722c85 | 0,
0xa2bfe8a1 | 0,
0xa81a664b | 0,
0xc24b8b70 | 0,
0xc76c51a3 | 0,
0xd192e819 | 0,
0xd6990624 | 0,
0xf40e3585 | 0,
0x106aa070 | 0,
0x19a4c116 | 0,
0x1e376c08 | 0,
0x2748774c | 0,
0x34b0bcb5 | 0,
0x391c0cb3 | 0,
0x4ed8aa4a | 0,
0x5b9cca4f | 0,
0x682e6ff3 | 0,
0x748f82ee | 0,
0x78a5636f | 0,
0x84c87814 | 0,
0x8cc70208 | 0,
0x90befffa | 0,
0xa4506ceb | 0,
0xbef9a3f7 | 0,
0xc67178f2 | 0,
];
/**
* @category Error
* @description Error that indicates a failure when decoding a base58 encoding
*/
class Base58DecodingError extends taquitoCore.TaquitoError {
constructor(message) {
super();
this.message = message;
this.name = 'Base58DecodingError';
}
}
// https://tools.ietf.org/html/rfc6234
function sha256(msg) {
// pad the message
const r = (msg.length + 9) % 64;
const pad = r === 0 ? 0 : 64 - r;
if (msg.length > 268435455) {
throw new taquitoCore.InvalidMessageError('', `: Invalid length ${msg.length} is too big -- SHA-256.`);
}
const l = msg.length << 3;
const buffer = [
...msg,
0x80,
...new Array(pad).fill(0),
0,
0,
0,
0,
(l >> 24) & 0xff,
(l >> 16) & 0xff,
(l >> 8) & 0xff,
l & 0xff,
];
function ror(x, n) {
return (x >>> n) | (x << (32 - n));
}
const h = [...H];
const w = new Array(64);
const v = new Array(8);
for (let offset = 0; offset < buffer.length; offset += 64) {
let q = offset;
let i = 0;
while (i < 16) {
w[i] = (buffer[q] << 24) | (buffer[q + 1] << 16) | (buffer[q + 2] << 8) | buffer[q + 3];
q += 4;
i++;
}
while (i < 64) {
const s0 = ror(w[i - 15], 7) ^ ror(w[i - 15], 18) ^ (w[i - 15] >>> 3);
const s1 = ror(w[i - 2], 17) ^ ror(w[i - 2], 19) ^ (w[i - 2] >>> 10);
w[i] = ((s1 | 0) + w[i - 7] + s0 + w[i - 16]) | 0;
i++;
}
for (let i = 0; i < 8; i++) {
v[i] = h[i];
}
for (let i = 0; i < 64; i++) {
const b0 = ror(v[0], 2) ^ ror(v[0], 13) ^ ror(v[0], 22);
const b1 = ror(v[4], 6) ^ ror(v[4], 11) ^ ror(v[4], 25);
const t1 = (v[7] + b1 + ((v[4] & v[5]) ^ (~v[4] & v[6])) + K[i] + w[i]) | 0;
const t2 = (b0 + ((v[0] & v[1]) ^ (v[0] & v[2]) ^ (v[1] & v[2]))) | 0;
v[7] = v[6];
v[6] = v[5];
v[5] = v[4];
v[4] = (v[3] + t1) | 0;
v[3] = v[2];
v[2] = v[1];
v[1] = v[0];
v[0] = (t1 + t2) | 0;
}
for (let i = 0; i < 8; i++) {
h[i] = (h[i] + v[i]) | 0;
}
}
const digest = [];
for (const v of h) {
digest.push((v >> 24) & 0xff);
digest.push((v >> 16) & 0xff);
digest.push((v >> 8) & 0xff);
digest.push(v & 0xff);
}
return digest;
}
const base58alphabetFwd = [
0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18,
19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
];
const base58alphabetBwd = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73,
];
function byteAt(src, i) {
const c = src.charCodeAt(i) - 49;
if (c >= base58alphabetFwd.length || base58alphabetFwd[c] === -1) {
throw new Base58DecodingError(`Unexpected character at position ${i}: ${src[i]}`);
}
return base58alphabetFwd[c];
}
function decodeBase58(src) {
const acc = [];
let i = 0;
// count and skip leading zeros
while (i < src.length && byteAt(src, i) === 0) {
i++;
}
let zeros = i;
while (i < src.length) {
let carry = byteAt(src, i++);
/*
for every symbol x
acc = acc * 58 + x
where acc is a little endian arbitrary length integer
*/
let ii = 0;
while (carry !== 0 || ii < acc.length) {
const m = (acc[ii] || 0) * 58 + carry;
acc[ii++] = m % 256;
carry = Math.floor(m / 256);
}
}
while (zeros-- > 0) {
acc.push(0);
}
return acc.reverse();
}
function encodeBase58(src) {
const acc = [];
let i = 0;
// count and skip leading zeros
while (i < src.length && src[i] === 0) {
i++;
}
let zeros = i;
while (i < src.length) {
let carry = src[i++];
let ii = 0;
while (carry !== 0 || ii < acc.length) {
const m = (acc[ii] || 0) * 256 + carry;
acc[ii++] = m % 58;
carry = Math.floor(m / 58);
}
}
while (zeros-- > 0) {
acc.push(0);
}
acc.reverse();
return String.fromCharCode(...acc.map((v) => base58alphabetBwd[v] + 49));
}
function decodeBase58Check(src) {
const buffer = decodeBase58(src);
if (buffer.length < 4) {
throw new Base58DecodingError(`Data is too short ${buffer.length}`);
}
const data = buffer.slice(0, buffer.length - 4);
const sum = buffer.slice(buffer.length - 4);
const computed = sha256(sha256(data));
if (sum[0] !== computed[0] ||
sum[1] !== computed[1] ||
sum[2] !== computed[2] ||
sum[3] !== computed[3]) {
throw new Base58DecodingError('Invalid checksum');
}
return data;
}
function encodeBase58Check(src) {
const sum = sha256(sha256(src));
return encodeBase58([...src, ...sum.slice(0, 4)]);
}
/**
* @category Error
* @description Error that indicates an invalid Michelson being passed or used
*/
class InvalidMichelsonError extends taquitoCore.ParameterValidationError {
constructor(message) {
super();
this.message = message;
this.name = 'InvalidMichelsonError';
}
}
/**
* @category Error
* @description Error that indicates an invalid type expression being passed or used
*/
class InvalidTypeExpressionError extends taquitoCore.ParameterValidationError {
constructor(message) {
super();
this.message = message;
this.name = 'InvalidTypeExpressionError';
}
}
/**
* @category Error
* @description Error that indicates an invalid data expression being passed or used
*/
class InvalidDataExpressionError extends taquitoCore.ParameterValidationError {
constructor(message) {
super();
this.message = message;
this.name = 'InvalidDataExpressionError';
}
}
/**
* @category Error
* @description Error that indicates an invalid contract entrypoint being referenced or passed
*/
class InvalidEntrypointError extends taquitoCore.ParameterValidationError {
constructor(entrypoint) {
super();
this.entrypoint = entrypoint;
this.name = 'InvalidEntrypointError';
this.message = `Contract has no entrypoint named: "${entrypoint}"`;
}
}
/**
* @category Error
* @description Error that indicates a failure happening when trying to encode Mavryk ID
*/
class MavrykIdEncodeError extends taquitoCore.ParameterValidationError {
constructor(message) {
super();
this.message = message;
this.name = 'MavrykIdEncodeError';
}
}
/**
* @category Error
* @description Error that indicates a general error happening when trying to create a LongInteger
*/
class LongIntegerError extends taquitoCore.TaquitoError {
constructor(message) {
super();
this.message = message;
this.name = 'LongIntegerError';
}
}
/**
* @category Error
* @description Error that indicates a failure occurring when trying to parse a hex byte
*/
class HexParseError extends taquitoCore.TaquitoError {
constructor(hexByte) {
super();
this.hexByte = hexByte;
this.name = 'HexParseError';
this.message = `Unable to parse hex byte "${hexByte}"`;
}
}
/**
* @category Error
* @description Error that indicates a Michelson failure occurring
*/
class MichelsonError extends taquitoCore.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';
}
}
function isMichelsonError(err) {
return err instanceof MichelsonError;
}
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;
}
}
}
// 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 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;
}
}
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;
}
function isDecimal(x) {
try {
new LongInteger(x);
return true;
}
catch (_a) {
return false;
}
}
function isNatural(x) {
try {
return new LongInteger(x).sign >= 0;
}
catch (_a) {
return false;
}
}
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 };
}
const 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 = decodeBase58Check(id);
for (const t of types) {
const [plen, p] = 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;
}
function encodeMavrykID(id, data) {
const [plen, p] = mavrykPrefix[id];
if (data.length !== plen) {
throw new MavrykIdEncodeError(`Incorrect data length for ${id}: ${data.length}`);
}
return encodeBase58Check([...p, ...data]);
}
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),
},
] });
}
function isPairType(t) {
return Array.isArray(t) || t.prim === 'pair';
}
function isPairData(d) {
return Array.isArray(d) || ('prim' in d && d.prim === 'Pair');
}
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;
}
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 HexParseError(ss);
}
res.push(x);
}
return res;
}
function hexBytes(bytes) {
return bytes.map((x) => ((x >> 4) & 0xf).toString(16) + (x & 0xf).toString(16)).join('');
}
// Michelson validator
const maxViewNameLength = 31;
const noArgInstructionIDs = {
ABS: true,
ADD: true,
ADDRESS: true,
AMOUNT: true,
AND: true,
APPLY: true,
BALANCE: true,
BLAKE2B: true,
CAR: true,
CDR: true,
CHAIN_ID: true,
CHECK_SIGNATURE: true,
COMPARE: true,
CONCAT: true,
CONS: true,
EDIV: true,
EQ: true,
EXEC: true,
FAILWITH: true,
GE: true,
GET_AND_UPDATE: true,
GT: true,
HASH_KEY: true,
IMPLICIT_ACCOUNT: true,
INT: true,
ISNAT: true,
JOIN_TICKETS: true,
KECCAK: true,
LE: true,
LEVEL: true,
LSL: true,
LSR: true,
LT: true,
MEM: true,
MUL: true,
NEG: true,
NEQ: true,
NEVER: true,
NOT: true,
NOW: true,
OR: true,
PACK: true,
PAIRING_CHECK: true,
READ_TICKET: true,
SAPLING_VERIFY_UPDATE: true,
SELF: true,
SELF_ADDRESS: true,
SENDER: true,
SET_DELEGATE: true,
SHA256: true,
SHA3: true,
SHA512: true,
SIZE: true,
SLICE: true,
SOME: true,
SOURCE: true,
SPLIT_TICKET: true,
SUB: true,
SWAP: true,
TICKET: true,
TICKET_DEPRECATED: true,
TOTAL_VOTING_POWER: true,
TRANSFER_TOKENS: true,
UNIT: true,
VOTING_POWER: true,
XOR: true,
RENAME: true,
OPEN_CHEST: true,
SUB_MUMAV: true,
MIN_BLOCK_TIME: true,
BYTES: true,
NAT: true,
};
const instructionIDs = Object.assign({}, noArgInstructionIDs, {
CONTRACT: true,
CREATE_CONTRACT: true,
DIG: true,
DIP: true,
DROP: true,
DUG: true,
DUP: true,
EMIT: true,
EMPTY_BIG_MAP: true,
EMPTY_MAP: true,
EMPTY_SET: true,
GET: true,
IF: true,
IF_CONS: true,
IF_LEFT: true,
IF_NONE: true,
ITER: true,
LAMBDA: true,
LAMBDA_REC: true,
LEFT: true,
LOOP: true,
LOOP_LEFT: true,
MAP: true,
NIL: true,
NONE: true,
PAIR: true,
PUSH: true,
RIGHT: true,
SAPLING_EMPTY_STATE: true,
UNPACK: true,
UNPAIR: true,
UPDATE: true,
CAST: true,
VIEW: true,
});
const simpleComparableTypeIDs = {
unit: true,
never: true,
bool: true,
int: true,
nat: true,
string: true,
chain_id: true,
bytes: true,
mumav: true,
key_hash: true,
key: true,
signature: true,
timestamp: true,
address: true,
tx_rollup_l2_address: true,
};
const typeIDs = Object.assign({}, simpleComparableTypeIDs, {
or: true,
pair: true,
set: true,
big_map: true,
contract: true,
lambda: true,
list: true,
map: true,
operation: true,
option: true,
bls12_381_g1: true,
bls12_381_g2: true,
bls12_381_fr: true,
sapling_transaction: true,
sapling_transaction_deprecated: true,
sapling_state: true,
ticket: true,
chest_key: true,
chest: true,
});
class MichelsonValidationError extends MichelsonError {
/**
* @param val Value of a node caused the error
* @param message An error message
*/
constructor(val, message) {
super(val, message);
this.val = val;
this.message = message;
this.name = 'MichelsonValidationError';
}
}
function isPrim(ex) {
return 'prim' in ex;
}
function isPrimOrSeq(ex) {
return Array.isArray(ex) || 'prim' in ex;
}
function assertPrim(ex) {
if (isPrim(ex)) {
return true;
}
throw new MichelsonValidationError(ex, 'prim expression expected');
}
function assertSeq(ex) {
if (Array.isArray(ex)) {
return true;
}
throw new MichelsonValidationError(ex, 'sequence expression expected');
}
function assertPrimOrSeq(ex) {
if (isPrimOrSeq(ex)) {
return true;
}
throw new MichelsonValidationError(ex, 'prim or sequence expression expected');
}
function assertNatural(i) {
if (i.int[0] === '-') {
throw new MichelsonValidationError(i, 'natural number expected');
}
}
function assertIntLiteral(ex) {
if ('int' in ex) {
return true;
}
throw new MichelsonValidationError(ex, 'int literal expected');
}
function assertStringLiteral(ex) {
if ('string' in ex) {
return true;
}
throw new MichelsonValidationError(ex, 'string literal expected');
}
// usually an address
function assertStringOrBytes(ex) {
if ('string' in ex || 'bytes' in ex) {
return true;
}
throw new MichelsonValidationError(ex, 'string or bytes literal expected');
}
function assertArgs(ex, n) {
var _a;
if ((n === 0 && ex.args === undefined) || ((_a = ex.args) === null || _a === void 0 ? void 0 : _a.length) === n) {
return true;
}
throw new MichelsonValidationError(ex, `${n} arguments expected`);
}
/**
* Checks if the node is a valid Michelson code (sequence of instructions).
* This is a type guard function which either returns true of throws an exception.
* @param ex An AST node
*/
function assertMichelsonInstruction(ex) {
var _a, _b;
if (Array.isArray(ex)) {
for (const n of ex) {
if (!Array.isArray(n) && !isPrim(n)) {
throw new MichelsonValidationError(ex, 'sequence or prim expected');
}
assertMichelsonInstruction(n);
}
return true;
}
if (assertPrim(ex)) {
if (Object.prototype.hasOwnProperty.call(noArgInstructionIDs, ex.prim)) {
assertArgs(ex, 0);
return true;
}
switch (ex.prim) {
case 'DROP':
case 'PAIR':
case 'UNPAIR':
case 'DUP':
case 'UPDATE':
case 'GET':
if (ex.args !== undefined && assertArgs(ex, 1)) {
/* istanbul ignore else */
if (assertIntLiteral(ex.args[0])) {
assertNatural(ex.args[0]);
}
}
break;
case 'DIG':
case 'DUG':
case 'SAPLING_EMPTY_STATE':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
/* istanbul ignore else */
if (assertIntLiteral(ex.args[0])) {
assertNatural(ex.args[0]);
}
}
break;
case 'NONE':
case 'LEFT':
case 'RIGHT':
case 'NIL':
case 'CAST':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonType(ex.args[0]);
}
break;
case 'UNPACK':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonPackableType(ex.args[0]);
}
break;
case 'CONTRACT':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonPassableType(ex.args[0]);
}
break;
case 'IF_NONE':
case 'IF_LEFT':
case 'IF_CONS':
case 'IF':
/* istanbul ignore else */
if (assertArgs(ex, 2)) {
/* istanbul ignore else */
if (assertSeq(ex.args[0])) {
assertMichelsonInstruction(ex.args[0]);
}
/* istanbul ignore else */
if (assertSeq(ex.args[1])) {
assertMichelsonInstruction(ex.args[1]);
}
}
break;
case 'MAP':
case 'ITER':
case 'LOOP':
case 'LOOP_LEFT':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonInstruction(ex.args[0]);
}
break;
case 'CREATE_CONTRACT':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonContract(ex.args[0]);
}
break;
case 'DIP':
if (((_a = ex.args) === null || _a === void 0 ? void 0 : _a.length) === 2) {
/* istanbul ignore else */
if (assertIntLiteral(ex.args[0])) {
assertNatural(ex.args[0]);
}
/* istanbul ignore else */
if (assertSeq(ex.args[1])) {
assertMichelsonInstruction(ex.args[1]);
}
}
else if (((_b = ex.args) === null || _b === void 0 ? void 0 : _b.length) === 1) {
/* istanbul ignore else */
if (assertSeq(ex.args[0])) {
assertMichelsonInstruction(ex.args[0]);
}
}
else {
throw new MichelsonValidationError(ex, '1 or 2 arguments expected');
}
break;
case 'PUSH':
/* istanbul ignore else */
if (assertArgs(ex, 2)) {
assertMichelsonPushableType(ex.args[0]);
assertMichelsonData(ex.args[1]);
}
break;
case 'EMPTY_SET':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonComparableType(ex.args[0]);
}
break;
case 'EMPTY_MAP':
/* istanbul ignore else */
if (assertArgs(ex, 2)) {
assertMichelsonComparableType(ex.args[0]);
assertMichelsonType(ex.args[1]);
}
break;
case 'EMPTY_BIG_MAP':
/* istanbul ignore else */
if (assertArgs(ex, 2)) {
assertMichelsonComparableType(ex.args[0]);
assertMichelsonBigMapStorableType(ex.args[1]);
}
break;
case 'LAMBDA_REC':
case 'LAMBDA':
/* istanbul ignore else */
if (assertArgs(ex, 3)) {
assertMichelsonType(ex.args[0]);
assertMichelsonType(ex.args[1]);
/* istanbul ignore else */
if (assertSeq(ex.args[2])) {
assertMichelsonInstruction(ex.args[2]);
}
}
break;
case 'VIEW':
/* istanbul ignore else */
if (assertArgs(ex, 2)) {
if (assertStringLiteral(ex.args[0])) {
assertViewNameValid(ex.args[0]);
}
if (assertMichelsonType(ex.args[1])) {
assertMichelsonPushableType(ex.args[1]);
}
}
break;
case 'EMIT':
if (ex.args && ex.args.length > 0) {
assertArgs(ex, 1);
}
else {
assertArgs(ex, 0);
}
break;
default:
throw new MichelsonValidationError(ex, 'instruction expected');
}
}
return true;
}
function assertMichelsonComparableType(ex) {
/* istanbul ignore else */
if (assertPrimOrSeq(ex)) {
if (Array.isArray(ex) || ex.prim === 'pair' || ex.prim === 'or' || ex.prim === 'option') {
traverseType(ex, (ex) => assertMichelsonComparableType(ex));
}
else if (!Object.prototype.hasOwnProperty.call(simpleComparableTypeIDs, ex.prim)) {
throw new MichelsonValidationError(ex, `${ex.prim}: type is not comparable`);
}
}
return true;
}
function assertMichelsonPackableType(ex) {
/* istanbul ignore else */
if (assertPrimOrSeq(ex)) {
if (isPrim(ex)) {
if (!Object.prototype.hasOwnProperty.call(typeIDs, ex.prim) ||
ex.prim === 'big_map' ||
ex.prim === 'operation' ||
ex.prim === 'sapling_state' ||
ex.prim === 'ticket') {
throw new MichelsonValidationError(ex, `${ex.prim}: type can't be used inside PACK/UNPACK instructions`);
}
traverseType(ex, (ex) => assertMichelsonPackableType(ex));
}
}
return true;
}
function assertMichelsonPushableType(ex) {
/* istanbul ignore else */
if (assertPrimOrSeq(ex)) {
if (isPrim(ex)) {
if (!Object.prototype.hasOwnProperty.call(typeIDs, ex.prim) ||
ex.prim === 'big_map' ||
ex.prim === 'operation' ||
ex.prim === 'sapling_state' ||
ex.prim === 'ticket' ||
ex.prim === 'contract') {
throw new MichelsonValidationError(ex, `${ex.prim}: type can't be pushed`);
}
traverseType(ex, (ex) => assertMichelsonPushableType(ex));
}
}
return true;
}
function assertMichelsonStorableType(ex) {
/* istanbul ignore else */
if (assertPrimOrSeq(ex)) {
if (isPrim(ex)) {
if (!Object.prototype.hasOwnProperty.call(typeIDs, ex.prim) ||
ex.prim === 'operation' ||
ex.prim === 'contract') {
throw new MichelsonValidationError(ex, `${ex.prim}: type can't be used as part of a storage`);
}
traverseType(ex, (ex) => assertMichelsonStorableType(ex));
}
}
return true;
}
function assertMichelsonPassableType(ex) {
/* istanbul ignore else */
if (assertPrimOrSeq(ex)) {
if (isPrim(ex)) {
if (!Object.prototype.hasOwnProperty.call(typeIDs, ex.prim) || ex.prim === 'operation') {
throw new MichelsonValidationError(ex, `${ex.prim}: type can't be used as part of a parameter`);
}
traverseType(ex, (ex) => assertMichelsonPassableType(ex));
}
}
return true;
}
function assertMichelsonBigMapStorableType(ex) {
/* istanbul ignore else */
if (assertPrimOrSeq(ex)) {
if (isPrim(ex)) {
if (!Object.prototype.hasOwnProperty.call(typeIDs, ex.prim) ||
ex.prim === 'big_map' ||
ex.prim === 'operation' ||
ex.prim === 'sapling_state') {
throw new MichelsonValidationError(ex, `${ex.prim}: type can't be used inside a big_map`);
}
traverseType(ex, (ex) => assertMichelsonBigMapStorableType(ex));
}
}
return true;
}
const viewRe = new RegExp('^[a-zA-Z0-9_.%@]*$');
function assertViewNameValid(name) {
if (name.string.length > maxViewNameLength) {
throw new MichelsonValidationError(name, `view name too long: ${name.string}`);
}
if (!viewRe.test(name.string)) {
throw new MichelsonValidationError(name, `invalid character(s) in view name: ${name.string}`);
}
}
/**
* Checks if the node is a valid Michelson type expression.
* This is a type guard function which either returns true of throws an exception.
* @param ex An AST node
*/
function assertMichelsonType(ex) {
/* istanbul ignore else */
if (assertPrimOrSeq(ex)) {
if (isPrim(ex)) {
if (!Object.prototype.hasOwnProperty.call(typeIDs, ex.prim)) {
throw new MichelsonValidationError(ex, 'type expected');
}
traverseType(ex, (ex) => assertMichelsonType(ex));
}
}
return true;
}
function traverseType(ex, cb) {
if (Array.isArray(ex) || ex.prim === 'pair') {
const args = Array.isArray(ex) ? ex : ex.args;
if (args === undefined || args.length < 2) {
throw new MichelsonValidationError(ex, 'at least 2 arguments expected');
}
args.forEach((a) => {
if (assertPrimOrSeq(a)) {
cb(a);
}
});
return true;
}
switch (ex.prim) {
case 'option':
case 'list':
/* istanbul ignore else */
if (assertArgs(ex, 1) && assertPrimOrSeq(ex.args[0])) {
cb(ex.args[0]);
}
break;
case 'contract':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonPassableType(ex.args[0]);
}
break;
case 'or':
/* istanbul ignore else */
if (assertArgs(ex, 2) && assertPrimOrSeq(ex.args[0]) && assertPrimOrSeq(ex.args[1])) {
cb(ex.args[0]);
cb(ex.args[1]);
}
break;
case 'lambda':
/* istanbul ignore else */
if (assertArgs(ex, 2)) {
assertMichelsonType(ex.args[0]);
assertMichelsonType(ex.args[1]);
}
break;
case 'set':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonComparableType(ex.args[0]);
}
break;
case 'map':
/* istanbul ignore else */
if (assertArgs(ex, 2) && assertPrimOrSeq(ex.args[0]) && assertPrimOrSeq(ex.args[1])) {
assertMichelsonComparableType(ex.args[0]);
cb(ex.args[1]);
}
break;
case 'big_map':
/* istanbul ignore else */
if (assertArgs(ex, 2) && assertPrimOrSeq(ex.args[0]) && assertPrimOrSeq(ex.args[1])) {
assertMichelsonComparableType(ex.args[0]);
assertMichelsonBigMapStorableType(ex.args[1]);
cb(ex.args[1]);
}
break;
case 'ticket':
/* istanbul ignore else */
if (assertArgs(ex, 1) && assertPrimOrSeq(ex.args[0])) {
assertMichelsonComparableType(ex.args[0]);
}
break;
case 'sapling_state':
case 'sapling_transaction':
if (assertArgs(ex, 1)) {
assertIntLiteral(ex.args[0]);
}
break;
default:
assertArgs(ex, 0);
}
return true;
}
/**
* Checks if the node is a valid Michelson data literal such as `(Pair {Elt "0" 0} 0)`.
* This is a type guard function which either returns true of throws an exception.
* @param ex An AST node
*/
function assertMichelsonData(ex) {
if ('int' in ex || 'string' in ex || 'bytes' in ex) {
return true;
}
if (Array.isArray(ex)) {
let mapElts = 0;
for (const n of ex) {
if (isPrim(n) && n.prim === 'Elt') {
/* istanbul ignore else */
if (assertArgs(n, 2)) {
assertMichelsonData(n.args[0]);
assertMichelsonData(n.args[1]);
}
mapElts++;
}
else {
assertMichelsonData(n);
}
}
if (mapElts !== 0 && mapElts !== ex.length) {
throw new MichelsonValidationError(ex, "data entries and map elements can't be intermixed");
}
return true;
}
if (isPrim(ex)) {
switch (ex.prim) {
case 'Unit':
case 'True':
case 'False':
case 'None':
assertArgs(ex, 0);
break;
case 'Pair':
/* istanbul ignore else */
if (ex.args === undefined || ex.args.length < 2) {
throw new MichelsonValidationError(ex, 'at least 2 arguments expected');
}
for (const a of ex.args) {
assertMichelsonData(a);
}
break;
case 'Left':
case 'Right':
case 'Some':
/* istanbul ignore else */
if (assertArgs(ex, 1)) {
assertMichelsonData(ex.args[0]);
}
break;
case 'Lambda_rec':
if (ex.args) {
assertMichelsonInstruction(ex.args);
}
break;
case 'Ticket':
if (assertArgs(ex, 4)) {
assertStringOrBytes(ex.args[0]);
assertMichelsonType(ex.args[1]);
assertMichelsonData(ex.args[2]);
assertIntLiteral(ex.args[3]);
}
break;
default:
if (Object.prototype.hasOwnProperty.call(instructionIDs, ex.prim)) {
assertMichelsonInstruction(ex);
}
else {
throw new MichelsonValidationError(ex, 'data entry or instruction expected');
}
}
}
else {
throw new MichelsonValidationError(ex, 'data entry expected');
}
return true;
}
/**
* Checks if the node is a valid Michelson smart contract source containing all required and valid properties such as `parameter`, `storage` and `code`.
* This is a type guard function which either returns true of throws an exception.
* @param ex An AST node
*/
function assertMichelsonContract(ex) {
/* istanbul ignore else */
if (assertSeq(ex)) {
const toplevelSec = {};
const views = {};
for (const sec of ex) {
if (assertPrim(sec)) {
if (sec.prim !== 'view') {
if (sec.prim in toplevelSec) {
throw new MichelsonValidationError(ex, `duplicate contract section: ${sec.prim}`);
}
toplevelSec[sec.prim] = true;
}
/* istanbul ignore else */
switch (sec.prim) {
case 'code':
if (assertArgs(sec, 1)) {
/* istanbul ignore else */
if (assertSeq(sec.args[0])) {
assertMichelsonInstruction(sec.args[0]);
}
}
break;
case 'parameter':
if (assertArgs(sec, 1)) {
assertMichelsonPassableType(sec.args[0]);
}
if (sec.annots) {
throw new MichelsonValidationError(sec, 'Annotation must be part of the parameter type');
}
break;
case 'storage':
if (assertArgs(sec, 1)) {
assertMichelsonStorableType(sec.args[0]);
}
break;
case 'view':
if (assertArgs(sec, 4)) {
if (assertStringLiteral(sec.args[0])) {
const name = sec.args[0];
if (name.string in views) {
throw new MichelsonValidationError(ex, `duplicate view name: ${name.string}`);
}
views[name.string] = true;
assertViewNameValid(name);
}
assertMichelsonPushableType(sec.args[1]);
assertMichelsonPushableType(sec.args[2]);
if (assertSeq(sec.args[3])) {
assertMichelsonInstruction(sec.args[3]);
}
}
break;
default:
throw new MichelsonValidationError(ex, `unexpected contract section: ${sec.prim}`);
}
}
}
}
return true;
}
/**
* Checks if the node is a valid Michelson smart contract source containing all required and valid properties such as `parameter`, `storage` and `code`.
* @param ex An AST node
*/
function isMichelsonScript(ex) {
try {
assertMichelsonContract(ex);
return true;
}
catch (_a) {
return false;
}
}
/**
* Checks if the node is a valid Michelson data literal such as `(Pair {Elt "0" 0} 0)`.
* @param ex An AST node
*/
function isMichelsonData(ex) {
try {
assertMichelsonData(ex);
return true;
}
catch (_a) {
return false;
}
}
/**
* Checks if the node is a valid Michelson code (sequence of instructions).
* @param ex An AST node
*/
function isMichelsonCode(ex) {
try {
assertMichelsonInstruction(ex);
return true;
}
catch (_a) {
return false;
}
}
/**
* Checks if the node is a valid Michelson type expression.
* @param ex An AST node
*/
function isMichelsonType(ex) {
try {
assertMichelsonType(ex);
return true;
}
catch (_a) {
return false;
}
}
function isInstruction(p) {
return Object.prototype.hasOwnProperty.call(instructionIDs, p.prim);
}
function assertDataListIfAny(d) {
if (!Array.isArray(d)) {
return false;
}
for (const v of d) {
if ('prim' in v) {
if (isInstruction(v)) {
throw new MichelsonError(d, `Instruction outside of a lambda: ${JSON.stringify(d)}`);
}
else if (v.prim === 'Elt') {
throw new MichelsonError(d, `Elt item outside of a map literal: ${JSON.stringify(d)}`);
}
}
}
return true;
}
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
// The order is important!
// The position represent the encoding value.
const primitives = [
'parameter',
'storage',
'code',
'False',
'Elt',
'Left',
'None',
'Pair',
'Right',
'Some',
'True',
'Unit',
'PACK',
'UNPACK',
'BLAKE2B',
'SHA256',
'SHA512',
'ABS',
'ADD',
'AMOUNT',
'AND',
'BALANCE',
'CAR',
'CDR',
'CHECK_SIGNATURE',
'COMPARE',
'CONCAT',
'CONS',
'CREATE_ACCOUNT',
'CREATE_CONTRACT',
'IMPLICIT_ACCOUNT',
'DIP',
'DROP',
'DUP',
'EDIV',
'EMPTY_MAP',
'EMPTY_SET',
'EQ',
'EXEC',
'FAILWITH',
'GE',
'GET',
'GT',
'HASH_KEY',
'IF',
'IF_CONS',
'IF_LEFT',
'IF_NONE',
'INT',
'LAMBDA',
'LE',
'LEFT',
'LOOP',
'LSL',
'LSR',
'LT',
'MAP',
'MEM',
'MUL',
'NEG',
'NEQ',
'NIL',
'NONE',
'NOT',
'NOW',
'OR',
'PAIR',
'PUSH',
'RIGHT',
'SIZE',
'SOME',
'SOURCE',
'SENDER',
'SELF',
'STEPS_TO_QUOTA',
'SUB',
'SWAP',
'TRANSFER_TOKENS',
'SET_DELEGATE',
'UNIT',
'UPDATE',
'XOR',
'ITER',
'LOOP_LEFT',
'ADDRESS',
'CONTRACT',
'ISNAT',
'CAST',
'RENAME',
'bool',
'contract',
'int',
'key',
'key_hash',
'lambda',
'list',
'map',
'big_map',
'nat',
'option',
'or',
'pair',
'set',
'signature',
'string',
'bytes',
'mumav',
'timestamp',
'unit',
'operation',
'address',
'SLICE',
'DIG',
'DUG',
'EMPTY_BIG_MAP',
'APPLY',
'chain_id',
'CHAIN_ID',
'LEVEL',
'SELF_ADDRESS',
'never',
'NEVER',
'UNPAIR',
'VOTING_POWER',
'TOTAL_VOTING_POWER',
'KECCAK',
'SHA3',
'PAIRING_CHECK',
'bls12_381_g1',
'bls12_381_g2',
'bls12_381_fr',
'sapling_state',
'sapling_transaction_deprecated',
'SAPLING_EMPTY_STATE',
'SAPLING_VERIFY_UPDATE',
'ticket',
'TICKET_DEPRECATED',
'READ_TICKET',
'SPLIT_TICKET',
'JOIN_TICKETS',
'GET_AND_UPDATE',
'chest',
'chest_key',
'OPEN_CHEST',
'VIEW',
'view',
'constant',
'SUB_MUMAV',
'tx_rollup_l2_address',
'MIN_BLOCK_TIME',
'sapling_transaction',
'EMIT',
'Lambda_rec',
'LAMBDA_REC',
'TICKET',
'BYTES',
'NAT',
'Ticket',
];
const primTags = Object.assign({}, ...primitives.map((v, i) => ({ [v]: i })));
var Tag;
(function (Tag) {
Tag[Tag["Int"] = 0] = "Int";
Tag[Tag["String"] = 1] = "String";
Tag[Tag["Sequence"] = 2] = "Sequence";
Tag[Tag["Prim0"] = 3] = "Prim0";
Tag[Tag["Prim0Annot"] = 4] = "Prim0Annot";
Tag[Tag["Prim1"] = 5] = "Prim1";
Tag[Tag["Prim1Annot"] = 6] = "Prim1Annot";
Tag[Tag["Prim2"] = 7] = "Prim2";
Tag[Tag["Prim2Annot"] = 8] = "Prim2Annot";
Tag[Tag["Prim"] = 9] = "Prim";
Tag[Tag["Bytes"] = 10] = "Bytes";
})(Tag || (Tag = {}));
class Writer {
constructor() {
this.buffer = [];
}
get length() {
return this.buffer.length;
}
writeBytes(val) {
this.buffer.push(...val.map((v) => v & 0xff));
}
writeUint8(val) {
const v = val | 0;
this.buffer.push(v & 0xff);
}
writeUint16(val) {
const v = val | 0;
this.buffer.push((v >> 8) & 0xff);
this.buffer.push(v & 0xff);
}
writeUint32(val) {
const v = val | 0;
this.buffer.push((v >> 24) & 0xff);
this.buffer.push((v >> 16) & 0xff);
this.buffer.push((v >> 8) & 0xff);
this.buffer.push(v & 0xff);
}
writeInt8(val) {
this.writeUint8(val);
}
writeInt16(val) {
this.writeUint16(val);
}
writeInt32(val) {
this.writeUint32(val);
}
}
const boundsErr = new Error('bounds out of range');
class Reader {
constructor(buffer, idx = 0, cap = buffer.length) {
this.buffer = buffer;
this.idx = idx;
this.cap = cap;
}
/** Remaining length */
get length() {
return this.cap - this.idx;
}
readBytes(len) {
if (this.cap - this.idx < len) {
throw boundsErr;
}
const ret = this.buffer.slice(this.idx, this.idx + len);
this.idx += len;
return ret;
}
reader(len) {
if (this.cap - this.idx < len) {
throw boundsErr;
}
const ret = new Reader(this.buffer, this.idx, this.idx + len);
this.idx += len;
return ret;
}
copy() {
return new Reader(this.buffer, this.idx, this.cap);
}
readUint8() {
if (this.cap - this.idx < 1) {
throw boundsErr;
}
return this.buffer[this.idx++] >>> 0;
}
readUint16() {
if (this.cap - this.idx < 2) {
throw boundsErr;
}
const x0 = this.buffer[this.idx++];
const x1 = this.buffer[this.idx++];
return ((x0 << 8) | x1) >>> 0;
}
readUint32() {
if (this.cap - this.idx < 4) {
throw boundsErr;
}
const x0 = this.buffer[this.idx++];
const x1 = this.buffer[this.idx++];
const x2 = this.buffer[this.idx++];
const x3 = this.buffer[this.idx++];
return ((x0 << 24) | (x1 << 16) | (x2 << 8) | x3) >>> 0;
}
readInt8() {
if (this.cap - this.idx < 1) {
throw boundsErr;
}
const x = this.buffer[this.idx++];
return (x << 24) >> 24;
}
readInt16() {
if (this.cap - this.idx < 2) {
throw boundsErr;
}
const x0 = this.buffer[this.idx++];
const x1 = this.buffer[this.idx++];
return (((x0 << 8) | x1) << 16) >> 16;
}
readInt32() {
if (this.cap - this.idx < 4) {
throw boundsErr;
}
const x0 = this.buffer[this.idx++];
const x1 = this.buffer[this.idx++];
const x2 = this.buffer[this.idx++];
const x3 = this.buffer[this.idx++];
return (x0 << 24) | (x1 << 16) | (x2 << 8) | x3;
}
}
var ContractID;
(function (ContractID) {
ContractID[ContractID["Implicit"] = 0] = "Implicit";
ContractID[ContractID["Originated"] = 1] = "Originated";
})(ContractID || (ContractID = {}));
var PublicKeyHashID;
(function (PublicKeyHashID) {
PublicKeyHashID[PublicKeyHashID["ED25519"] = 0] = "ED25519";
PublicKeyHashID[PublicKeyHashID["SECP256K1"] = 1] = "SECP256K1";
PublicKeyHashID[PublicKeyHashID["P256"] = 2] = "P256";
})(PublicKeyHashID || (PublicKeyHashID = {}));
function readPublicKeyHash(rd) {
let type;
const tag = rd.readUint8();
switch (tag) {
case PublicKeyHashID.ED25519:
type = 'ED25519PublicKeyHash';
break;
case PublicKeyHashID.SECP256K1:
type = 'SECP256K1PublicKeyHash';
break;
case PublicKeyHashID.P256:
type = 'P256PublicKeyHash';
break;
default:
throw new Error(`unknown public key hash tag: ${tag}`);
}
return { type, hash: rd.readBytes(20) };
}
function readAddress(rd) {
let address;
const tag = rd.readUint8();
switch (tag) {
case ContractID.Implicit:
address = readPublicKeyHash(rd);
break;
case ContractID.Originated:
address = {
type: 'ContractHash',
hash: rd.readBytes(20),
};
rd.readBytes(1);
break;
default:
throw new Error(`unknown address tag: ${tag}`);
}
if (rd.length !== 0) {
// entry point
const dec = new TextDecoder();
address.entryPoint = dec.decode(new Uint8Array(rd.readBytes(rd.length)));
}
return address;
}
function writePublicKeyHash(a, w) {
let tag;
switch (a.type) {
case 'ED25519PublicKeyHash':
tag = PublicKeyHashID.ED25519;
break;
case 'SECP256K1PublicKeyHash':
tag = PublicKeyHashID.SECP256K1;
break;
case 'P256PublicKeyHash':
tag = PublicKeyHashID.P256;
break;
default:
throw new Error(`unexpected address type: ${a.type}`);
}
w.writeUint8(tag);
w.writeBytes(Array.from(a.hash));
}
function writeAddress(a, w) {
if (a.type === 'ContractHash') {
w.writeUint8(ContractID.Originated);
w.writeBytes(Array.from(a.hash));
w.writeUint8(0);
}
else {
w.writeUint8(ContractID.Implicit);
writePublicKeyHash(a, w);
}
if (a.entryPoint !== undefined && a.entryPoint !== '' && a.entryPoint !== 'default') {
const enc = new TextEncoder();
const bytes = enc.encode(a.entryPoint);
w.writeBytes(Array.from(bytes));
}
}
var PublicKeyID;
(function (PublicKeyID) {
PublicKeyID[PublicKeyID["ED25519"] = 0] = "ED25519";
PublicKeyID[PublicKeyID["SECP256K1"] = 1] = "SECP256K1";
PublicKeyID[PublicKeyID["P256"] = 2] = "P256";
})(PublicKeyID || (PublicKeyID = {}));
function readPublicKey(rd) {
let ln;
let type;
const tag = rd.readUint8();
switch (tag) {
case PublicKeyID.ED25519:
type = 'ED25519PublicKey';
ln = 32;
break;
case PublicKeyID.SECP256K1:
type = 'SECP256K1PublicKey';
ln = 33;
break;
case PublicKeyID.P256:
type = 'P256PublicKey';
ln = 33;
break;
default:
throw new Error(`unknown public key tag: ${tag}`);
}
return { type, publicKey: rd.readBytes(ln) };
}
function writePublicKey(pk, w) {
let tag;
switch (pk.type) {
case 'ED25519PublicKey':
tag = PublicKeyID.ED25519;
break;
case 'SECP256K1PublicKey':
tag = PublicKeyID.SECP256K1;
break;
case 'P256PublicKey':
tag = PublicKeyID.P256;
break;
default:
throw new Error(`unexpected public key type: ${pk.type}`);
}
w.writeUint8(tag);
w.writeBytes(Array.from(pk.publicKey));
}
function writeExpr(expr, wr, tf) {
var _a, _b;
const [e, args] = tf(expr);
if (Array.isArray(e)) {
const w = new Writer();
for (const v of e) {
const a = args.next();
if (a.done) {
throw new Error('REPORT ME: iterator is done');
}
writeExpr(v, w, a.value);
}
wr.writeUint8(Tag.Sequence);
wr.writeUint32(w.length);
wr.writeBytes(w.buffer);
return;
}
if ('string' in e) {
const enc = new TextEncoder();
const bytes = enc.encode(e.string);
wr.writeUint8(Tag.String);
wr.writeUint32(bytes.length);
wr.writeBytes(Array.from(bytes));
return;
}
if ('int' in e) {
wr.writeUint8(Tag.Int);
let val = BigInt(e.int);
const sign = val < 0;
if (sign) {
val = -val;
}
let i = 0;
do {
const bits = i === 0 ? BigInt(6) : BigInt(7);
let byte = val & ((BigInt(1) << bits) - BigInt(1));
val >>= bits;
if (val) {
byte |= BigInt(0x80);
}
if (i === 0 && sign) {
byte |= BigInt(0x40);
}
wr.writeUint8(Number(byte));
i++;
} while (val);
return;
}
if ('bytes' in e) {
const bytes = parseHex(e.bytes);
wr.writeUint8(Tag.Bytes);
wr.writeUint32(bytes.length);
wr.writeBytes(bytes);
return;
}
const prim = primTags[e.prim];
if (prim === undefined) {
throw new TypeError(`Can't encode primary: ${e.prim}`);
}
const tag = (((_a = e.args) === null || _a === void 0 ? void 0 : _a.length) || 0) < 3
? Tag.Prim0 +
(((_b = e.args) === null || _b === void 0 ? void 0 : _b.length) || 0) * 2 +
(e.annots === undefined || e.annots.length === 0 ? 0 : 1)
: Tag.Prim;
wr.writeUint8(tag);
wr.writeUint8(prim);
if (e.args !== undefined) {
if (e.args.length < 3) {
for (const v of e.args) {
const a = args.next();
if (a.done) {
throw new Error('REPORT ME: iterator is done');
}
writeExpr(v, wr, a.value);
}
}
else {
const w = new Writer();
for (const v of e.args) {
const a = args.next();
if (a.done) {
throw new Error('REPORT ME: iterator is done');
}
writeExpr(v, w, a.value);
}
wr.writeUint32(w.length);
wr.writeBytes(w.buffer);
}
}
if (e.annots !== undefined && e.annots.length !== 0) {
const enc = new TextEncoder();
const bytes = enc.encode(e.annots.join(' '));
wr.writeUint32(bytes.length);
wr.writeBytes(Array.from(bytes));
}
else if (e.args !== undefined && e.args.length >= 3) {
wr.writeUint32(0);
}
}
function readExpr(rd, tf) {
function* passThrough() {
while (true) {
yield readPassThrough;
}
}
const [args, tr] = tf;
const tag = rd.readUint8();
switch (tag) {
case Tag.Int: {
const buf = [];
let byte;
do {
byte = rd.readInt8();
buf.push(byte);
} while ((byte & 0x80) !== 0);
let val = BigInt(0);
let sign = false;
for (let i = buf.length - 1; i >= 0; i--) {
const bits = i === 0 ? BigInt(6) : BigInt(7);
const byte = BigInt(buf[i]);
val <<= bits;
val |= byte & ((BigInt(1) << bits) - BigInt(1));
if (i === 0) {
sign = !!(byte & BigInt(0x40));
}
}
if (sign) {
val = -val;
}
return tr({ int: String(val) });
}
case Tag.String: {
const length = rd.readUint32();
const bytes = rd.readBytes(length);
const dec = new TextDecoder();
return tr({ string: dec.decode(new Uint8Array(bytes)) });
}
case Tag.Bytes: {
const length = rd.readUint32();
const bytes = rd.readBytes(length);
const hex = hexBytes(Array.from(bytes));
return tr({ bytes: hex });
}
case Tag.Sequence: {
const length = rd.readUint32();
let res = [];
let savedrd = rd.copy();
// make two passes
let it = passThrough();
for (let n = 0; n < 2; n++) {
const r = savedrd.reader(length);
res = [];
while (r.length > 0) {
const a = it.next();
if (a.done) {
throw new Error('REPORT ME: iterator is done');
}
res.push(readExpr(r, a.value));
}
// make a second pass with injected side effects
it = args(res);
savedrd = rd;
}
return tr(res);
}
default: {
if (tag > 9) {
throw new Error(`Unknown tag: ${tag}`);
}
const p = rd.readUint8();
if (p >= primitives.length) {
throw new Error(`Unknown primitive tag: ${p}`);
}
const prim = primitives[p];
const argn = (tag - 3) >> 1;
let res = { prim };
// make two passes
let it = passThrough();
let savedrd = rd.copy();
for (let n = 0; n < 2; n++) {
res = { prim };
if (argn < 3) {
for (let i = 0; i < argn; i++) {
const a = it.next();
if (a.done) {
throw new Error('REPORT ME: iterator is done');
}
res.args = res.args || [];
res.args.push(readExpr(savedrd, a.value));
}
}
else {
res.args = res.args || [];
const length = savedrd.readUint32();
const r = savedrd.reader(length);
while (r.length > 0) {
const a = it.next();
if (a.done) {
throw new Error('REPORT ME: iterator is done');
}
res.args.push(readExpr(r, a.value));
}
}
// make a second pass with injected side effects
it = args(res);
savedrd = rd;
}
if (((tag - 3) & 1) === 1 || argn === 3) {
// read annotations
const length = rd.readUint32();
if (length !== 0) {
const bytes = rd.readBytes(length);
const dec = new TextDecoder();
res.annots = dec.decode(new Uint8Array(bytes)).split(' ');
}
}
return tr(res);
}
}
}
const isOrData = (e) => 'prim' in e && (e.prim === 'Left' || e.prim === 'Right');
const isOptionData = (e) => 'prim' in e && (e.prim === 'Some' || e.prim === 'None');
const getWriteTransformFunc = (t) => {
if (isPairType(t)) {
return (d) => {
if (!isPairData(d)) {
throw new MichelsonTypeError(t, `pair expected: ${JSON.stringify(d)}`, d);
}
assertDataListIfAny(d);
// combs aren't used in pack format
const tc = unpackComb('pair', t);
const dc = unpackComb('Pair', d);
return [
dc,
(function* () {
for (const a of tc.args) {
yield getWriteTransformFunc(a);
}
})(),
];
};
}
switch (t.prim) {
case 'or':
return (d) => {
if (!isOrData(d)) {
throw new MichelsonTypeError(t, `or expected: ${JSON.stringify(d)}`, d);
}
return [
d,
(function* () {
yield getWriteTransformFunc(t.args[d.prim === 'Left' ? 0 : 1]);
})(),
];
};
case 'option':
return (d) => {
if (!isOptionData(d)) {
throw new MichelsonTypeError(t, `option expected: ${JSON.stringify(d)}`, d);
}
return [
d,
(function* () {
const dd = d;
// TODO: refactor and remove ts-ignore
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (dd.prim === 'Some') {
yield getWriteTransformFunc(t.args[0]);
}
})(),
];
};
case 'list':
case 'set':
return (d) => {
if (!Array.isArray(d)) {
throw new MichelsonTypeError(t, `${t.prim} expected: ${JSON.stringify(d)}`, d);
}
return [
d,
(function* () {
for (const _v of d) {
yield getWriteTransformFunc(t.args[0]);
}
})(),
];
};
case 'map':
return (d) => {
if (!Array.isArray(d)) {
throw new MichelsonTypeError(t, `map expected: ${JSON.stringify(d)}`, d);
}
return [
d,
(function* () {
for (const _elt of d) {
yield (elt) => {
if (!('prim' in elt) || elt.prim !== 'Elt') {
throw new MichelsonTypeError(t, `map element expected: ${JSON.stringify(elt)}`, elt);
}
return [
elt,
(function* () {
for (const a of t.args) {
yield getWriteTransformFunc(a);
}
})(),
];
};
}
})(),
];
};
case 'chain_id':
return (d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `chain id expected: ${JSON.stringify(d)}`, d);
}
let bytes;
if ('string' in d) {
const id = checkDecodeMavrykID(d.string, 'ChainID');
if (id === null) {
throw new MichelsonTypeError(t, `chain id base58 expected: ${d.string}`, d);
}
bytes = { bytes: hexBytes(id[1]) };
}
else {
bytes = d;
}
return [bytes, [][Symbol.iterator]()];
};
case 'signature':
return (d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `signature expected: ${JSON.stringify(d)}`, d);
}
let bytes;
if ('string' in d) {
const sig = checkDecodeMavrykID(d.string, 'ED25519Signature', 'SECP256K1Signature', 'P256Signature', 'GenericSignature');
if (sig === null) {
throw new MichelsonTypeError(t, `signature base58 expected: ${d.string}`, d);
}
bytes = { bytes: hexBytes(sig[1]) };
}
else {
bytes = d;
}
return [bytes, [][Symbol.iterator]()];
};
case 'key_hash':
return (d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `key hash expected: ${JSON.stringify(d)}`, d);
}
let bytes;
if ('string' in d) {
const pkh = checkDecodeMavrykID(d.string, 'ED25519PublicKeyHash', 'SECP256K1PublicKeyHash', 'P256PublicKeyHash');
if (pkh === null) {
throw new MichelsonTypeError(t, `key hash base58 expected: ${d.string}`, d);
}
const w = new Writer();
writePublicKeyHash({ type: pkh[0], hash: pkh[1] }, w);
bytes = { bytes: hexBytes(w.buffer) };
}
else {
bytes = d;
}
return [bytes, [][Symbol.iterator]()];
};
case 'key':
return (d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `public key expected: ${JSON.stringify(d)}`, d);
}
let bytes;
if ('string' in d) {
const key = checkDecodeMavrykID(d.string, 'ED25519PublicKey', 'SECP256K1PublicKey', 'P256PublicKey');
if (key === null) {
throw new MichelsonTypeError(t, `public key base58 expected: ${d.string}`, d);
}
const w = new Writer();
writePublicKey({ type: key[0], publicKey: key[1] }, w);
bytes = { bytes: hexBytes(w.buffer) };
}
else {
bytes = d;
}
return [bytes, [][Symbol.iterator]()];
};
case 'address':
return (d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `address expected: ${JSON.stringify(d)}`, d);
}
let bytes;
if ('string' in d) {
const s = d.string.split('%');
const address = checkDecodeMavrykID(s[0], 'ED25519PublicKeyHash', 'SECP256K1PublicKeyHash', 'P256PublicKeyHash', 'ContractHash');
if (address === null) {
throw new MichelsonTypeError(t, `address base58 expected: ${d.string}`, d);
}
const w = new Writer();
writeAddress({ type: address[0], hash: address[1], entryPoint: s.length > 1 ? s[1] : undefined }, w);
bytes = { bytes: hexBytes(w.buffer) };
}
else {
bytes = d;
}
return [bytes, [][Symbol.iterator]()];
};
case 'timestamp':
return (d) => {
if (!('string' in d) && !('int' in d)) {
throw new MichelsonTypeError(t, `timestamp expected: ${JSON.stringify(d)}`, d);
}
let int;
if ('string' in d) {
const p = parseDate(d);
if (p === null) {
throw new MichelsonTypeError(t, `can't parse date: ${d.string}`, d);
}
int = { int: String(Math.floor(p.getTime() / 1000)) };
}
else {
int = d;
}
return [int, [][Symbol.iterator]()];
};
default:
return writePassThrough;
}
};
const isPushInstruction = (e) => 'prim' in e && e.prim === 'PUSH';
const writePassThrough = (e) => {
if (isPushInstruction(e)) {
assertMichelsonInstruction(e);
// capture inlined type definition
return [
e,
(function* () {
yield writePassThrough;
yield getWriteTransformFunc(e.args[0]);
})(),
];
}
return [
e,
(function* () {
while (true) {
yield writePassThrough;
}
})(),
];
};
/**
* Serializes any value of packable type to its optimized binary representation
* identical to the one used by PACK and UNPACK Michelson instructions.
* Without a type definition (not recommended) the data will be encoded as a binary form of a generic Michelson expression.
* Type definition allows some types like `timestamp` and `address` and other base58 representable types to be encoded to
* corresponding optimized binary forms borrowed from the Mavryk protocol
*
* ```typescript
* const data: MichelsonData = {
* string: "KT1RvkwF4F7pz1gCoxkyZrG1RkrxQy3gmFTv%foo"
* };
*
* const typ: MichelsonType = {
* prim: "address"
* };
*
* const packed = packData(data, typ);
*
* // 050a0000001901be41ee922ddd2cf33201e49d32da0afec571dce300666f6f
* ```
*
* Without a type definition the base58 encoded address will be treated as a string
* ```typescript
* const data: MichelsonData = {
* string: "KT1RvkwF4F7pz1gCoxkyZrG1RkrxQy3gmFTv%foo"
* };
*
* const packed = packData(data);
*
* // 0501000000284b543152766b7746344637707a3167436f786b795a724731526b7278517933676d46547625666f6f
* ```
* @param d Data object
* @param t Optional type definition
* @returns Binary representation as numeric array
*/
function packData(d, t) {
const w = new Writer();
w.writeUint8(5);
writeExpr(d, w, t !== undefined ? getWriteTransformFunc(t) : writePassThrough);
return w.buffer;
}
/**
* Serializes any value of packable type to its optimized binary representation
* identical to the one used by PACK and UNPACK Michelson instructions.
* Same as {@link packData} but returns a `bytes` Michelson data literal instead of an array
*
* ```typescript
* const data: MichelsonData = {
* string: "2019-09-26T10:59:51Z"
* };
*
* const typ: MichelsonType = {
* prim: "timestamp"
* };
*
* const packed = packDataBytes(data, typ);
*
* // { bytes: "0500a7e8e4d80b" }
* ```
* @param d Data object
* @param t Optional type definition
* @returns Binary representation as a bytes literal
*/
function packDataBytes(d, t) {
return { bytes: hexBytes(packData(d, t)) };
}
const getReadTransformFuncs = (t) => {
if (isPairType(t)) {
return [
(d) => {
if (!isPairData(d)) {
throw new MichelsonTypeError(t, `pair expected: ${JSON.stringify(d)}`, d);
}
const tc = unpackComb('pair', t);
return (function* () {
for (const a of tc.args) {
yield getReadTransformFuncs(a);
}
})();
},
(d) => d,
];
}
switch (t.prim) {
case 'or':
return [
(d) => {
if (!isOrData(d)) {
throw new MichelsonTypeError(t, `or expected: ${JSON.stringify(d)}`, d);
}
return (function* () {
yield getReadTransformFuncs(t.args[d.prim === 'Left' ? 0 : 1]);
})();
},
(d) => d,
];
case 'option':
return [
(d) => {
if (!isOptionData(d)) {
throw new MichelsonTypeError(t, `option expected: ${JSON.stringify(d)}`, d);
}
return (function* () {
// TODO: refactor and remove ts-ignore
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (d.prim === 'Some') {
yield getReadTransformFuncs(t.args[0]);
}
})();
},
(d) => d,
];
case 'list':
case 'set':
return [
(d) => {
if (!Array.isArray(d)) {
throw new MichelsonTypeError(t, `${t.prim} expected: ${JSON.stringify(d)}`, d);
}
return (function* () {
while (true) {
yield getReadTransformFuncs(t.args[0]);
}
})();
},
(d) => d,
];
case 'map':
return [
(d) => {
if (!Array.isArray(d)) {
throw new MichelsonTypeError(t, `map expected: ${JSON.stringify(d)}`, d);
}
return (function* () {
while (true) {
yield [
(elt) => {
if (!('prim' in elt) || elt.prim !== 'Elt') {
throw new MichelsonTypeError(t, `map element expected: ${JSON.stringify(elt)}`, elt);
}
return (function* () {
for (const a of t.args) {
yield getReadTransformFuncs(a);
}
})();
},
(elt) => elt,
];
}
})();
},
(d) => d,
];
case 'chain_id':
return [
() => [][Symbol.iterator](),
(d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `chain id expected: ${JSON.stringify(d)}`, d);
}
if ('string' in d) {
return d;
}
const bytes = parseBytes(d.bytes);
if (bytes === null) {
throw new MichelsonTypeError(t, `can't parse bytes: ${d.bytes}`, d);
}
return { string: encodeMavrykID('ChainID', bytes) };
},
];
case 'signature':
return [
() => [][Symbol.iterator](),
(d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `signature expected: ${JSON.stringify(d)}`, d);
}
if ('string' in d) {
return d;
}
const bytes = parseBytes(d.bytes);
if (bytes === null) {
throw new MichelsonTypeError(t, `can't parse bytes: ${d.bytes}`, d);
}
return { string: encodeMavrykID('GenericSignature', bytes) };
},
];
case 'key_hash':
return [
() => [][Symbol.iterator](),
(d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `key hash expected: ${JSON.stringify(d)}`, d);
}
if ('string' in d) {
return d;
}
const bytes = parseBytes(d.bytes);
if (bytes === null) {
throw new MichelsonTypeError(t, `can't parse bytes: ${d.bytes}`, d);
}
const rd = new Reader(new Uint8Array(bytes));
const addr = readPublicKeyHash(rd);
return {
string: encodeMavrykID(addr.type, addr.hash) + (addr.entryPoint ? '%' + addr.entryPoint : ''),
};
},
];
case 'key':
return [
() => [][Symbol.iterator](),
(d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `public key expected: ${JSON.stringify(d)}`, d);
}
if ('string' in d) {
return d;
}
const bytes = parseBytes(d.bytes);
if (bytes === null) {
throw new MichelsonTypeError(t, `can't parse bytes: ${d.bytes}`, d);
}
const rd = new Reader(new Uint8Array(bytes));
const pk = readPublicKey(rd);
return { string: encodeMavrykID(pk.type, pk.publicKey) };
},
];
case 'address':
return [
() => [][Symbol.iterator](),
(d) => {
if (!('bytes' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `address expected: ${JSON.stringify(d)}`, d);
}
if ('string' in d) {
return d;
}
const bytes = parseBytes(d.bytes);
if (bytes === null) {
throw new MichelsonTypeError(t, `can't parse bytes: ${d.bytes}`, d);
}
const rd = new Reader(new Uint8Array(bytes));
const addr = readAddress(rd);
return {
string: encodeMavrykID(addr.type, addr.hash) + (addr.entryPoint ? '%' + addr.entryPoint : ''),
};
},
];
case 'timestamp':
return [
() => [][Symbol.iterator](),
(d) => {
if (!('int' in d) && !('string' in d)) {
throw new MichelsonTypeError(t, `address expected: ${JSON.stringify(d)}`, d);
}
if ('string' in d) {
return d;
}
const date = new Date(parseInt(d.int, 10) * 1000);
return { string: date.toISOString().slice(0, 19) + 'Z' };
},
];
default:
return readPassThrough;
}
};
const readPassThrough = [
(e) => {
if (isPushInstruction(e)) {
assertMichelsonInstruction(e);
// capture inlined type definition
return (function* () {
yield readPassThrough;
yield getReadTransformFuncs(e.args[0]);
})();
}
return (function* () {
while (true) {
yield readPassThrough;
}
})();
},
(e) => e,
];
/**
* Deserialize a byte array into the corresponding Michelson value.
* Without a type definition (not recommended) the binary data will be treated as a binary form of a generic Michelson expression and returned as is.
* Type definition allows some types like `timestamp` and `address` and other types usually encoded in optimized binary forms to be transformed
* back to their string representations like base58 and ISO timestamps.
*
* ```typescript
* const src = [0x05, 0x00, 0xa7, 0xe8, 0xe4, 0xd8, 0x0b];
*
* const typ: MichelsonType = {
* prim: "timestamp"
* };
*
* const data = unpackData(src, typ);
*
* // { string: "2019-09-26T10:59:51Z" }
* ```
*
* Same binary data without a type definition
* ```typescript
* const src = [0x05, 0x00, 0xa7, 0xe8, 0xe4, 0xd8, 0x0b];
*
* const data = unpackData(src);
*
* // { int: "1569495591" }
* ```
* @param src Byte array
* @param t Optional type definition
* @returns Deserialized data
*/
function unpackData(src, t) {
const r = new Reader(src);
if (r.readUint8() !== 5) {
throw new Error('incorrect packed data magic number');
}
const ex = readExpr(r, t !== undefined ? getReadTransformFuncs(t) : readPassThrough);
if (assertMichelsonData(ex)) {
return ex;
}
throw new Error(); // never
}
/**
* Deserialize a byte array into the corresponding Michelson value.
* Same as {@link unpackData} but takes a `bytes` Michelson data literal instead of an array
*
* ```typescript
* const src = { bytes: "0500a7e8e4d80b" };
*
* const typ: MichelsonType = {
* prim: "timestamp"
* };
*
* const data = unpackDataBytes(src, typ);
*
* // { string: "2019-09-26T10:59:51Z" }
* ```
* @param src Bytes object
* @param t Optional type definition
* @returns Deserialized data
*/
function unpackDataBytes(src, t) {
const bytes = parseBytes(src.bytes);
if (bytes === null) {
throw new Error(`can't parse bytes: "${src.bytes}"`);
}
return unpackData(bytes, t);
}
// helper functions also used by validator
function decodeAddressBytes(b) {
const bytes = parseBytes(b.bytes);
if (bytes === null) {
throw new Error(`can't parse bytes: "${b.bytes}"`);
}
const rd = new Reader(new Uint8Array(bytes));
return readAddress(rd);
}
function decodePublicKeyHashBytes(b) {
const bytes = parseBytes(b.bytes);
if (bytes === null) {
throw new Error(`can't parse bytes: "${b.bytes}"`);
}
const rd = new Reader(new Uint8Array(bytes));
return readPublicKeyHash(rd);
}
function decodePublicKeyBytes(b) {
const bytes = parseBytes(b.bytes);
if (bytes === null) {
throw new Error(`can't parse bytes: "${b.bytes}"`);
}
const rd = new Reader(new Uint8Array(bytes));
return readPublicKey(rd);
}
class MichelsonInstructionError extends MichelsonError {
/**
* @param val Value of a type node caused the error
* @param stackState Current stack state
* @param message An error message
*/
constructor(val, stackState, message) {
super(val, message);
this.val = val;
this.stackState = stackState;
this.message = message;
this.name = 'MichelsonInstructionError';
}
}
// 'sequence as a pair' edo syntax helpers
function typeID(t) {
return Array.isArray(t) ? 'pair' : t.prim;
}
function typeArgs(t) {
return ('prim' in t ? t.args : t);
}
function assertScalarTypesEqual(a, b, field = false) {
if (typeID(a) !== typeID(b)) {
throw new MichelsonTypeError(a, `types mismatch: ${typeID(a)} != ${typeID(b)}`, undefined);
}
const ann = [unpackAnnotations(a), unpackAnnotations(b)];
if (ann[0].t && ann[1].t && ann[0].t[0] !== ann[1].t[0]) {
throw new MichelsonTypeError(a, `${typeID(a)}: type names mismatch: ${ann[0].t[0]} != ${ann[1].t[0]}`, undefined);
}
if (field && ann[0].f && ann[1].f && ann[0].f[0] !== ann[1].f[0]) {
throw new MichelsonTypeError(a, `${typeID(a)}: field names mismatch: ${ann[0].f[0]} != ${ann[1].f}`, undefined);
}
if (isPairType(a)) {
const aArgs = unpackComb('pair', a);
const bArgs = unpackComb('pair', b);
assertScalarTypesEqual(aArgs.args[0], bArgs.args[0], true);
assertScalarTypesEqual(aArgs.args[1], bArgs.args[1], true);
return;
}
switch (a.prim) {
case 'option':
case 'list':
case 'contract':
case 'set':
case 'ticket':
assertScalarTypesEqual(a.args[0], b.args[0]);
break;
case 'or':
assertScalarTypesEqual(a.args[0], b.args[0], true);
assertScalarTypesEqual(a.args[1], b.args[1], true);
break;
case 'lambda':
case 'map':
case 'big_map':
assertScalarTypesEqual(a.args[0], b.args[0]);
assertScalarTypesEqual(a.args[1], b.args[1]);
break;
case 'sapling_state':
case 'sapling_transaction':
if (parseInt(a.args[0].int, 10) !== parseInt(b.args[0].int, 10)) {
throw new MichelsonTypeError(a, `${typeID(a)}: type argument mismatch: ${a.args[0].int} != ${b.args[0].int}`, undefined);
}
}
}
function assertStacksEqual(a, b) {
if (a.length !== b.length) {
throw new MichelsonTypeError(a, `stack length mismatch: ${a.length} != ${b.length}`, undefined);
}
for (let i = 0; i < a.length; i++) {
assertScalarTypesEqual(a[i], b[i]);
}
}
function assertTypeAnnotationsValid(t, field = false) {
var _a, _b, _c;
if (!Array.isArray(t)) {
const ann = unpackAnnotations(t);
if ((((_a = ann.t) === null || _a === void 0 ? void 0 : _a.length) || 0) > 1) {
throw new MichelsonTypeError(t, `${t.prim}: at most one type annotation allowed: ${t.annots}`, undefined);
}
if (field) {
if ((((_b = ann.f) === null || _b === void 0 ? void 0 : _b.length) || 0) > 1) {
throw new MichelsonTypeError(t, `${t.prim}: at most one field annotation allowed: ${t.annots}`, undefined);
}
}
else {
if ((((_c = ann.f) === null || _c === void 0 ? void 0 : _c.length) || 0) > 0) {
throw new MichelsonTypeError(t, `${t.prim}: field annotations aren't allowed: ${t.annots}`, undefined);
}
}
}
if (isPairType(t)) {
const args = typeArgs(t);
for (const a of args) {
assertTypeAnnotationsValid(a, true);
}
return;
}
switch (t.prim) {
case 'option':
case 'list':
case 'contract':
case 'set':
assertTypeAnnotationsValid(t.args[0]);
break;
case 'or':
for (const a of t.args) {
assertTypeAnnotationsValid(a, true);
}
break;
case 'lambda':
case 'map':
case 'big_map':
assertTypeAnnotationsValid(t.args[0]);
assertTypeAnnotationsValid(t.args[1]);
}
}
// Simplified version of assertMichelsonInstruction() for previously validated data
function isFunction(d) {
if (!Array.isArray(d)) {
return false;
}
for (const v of d) {
if (!((Array.isArray(v) && isFunction(v)) || ('prim' in v && isInstruction(v)))) {
return false;
}
}
return true;
}
function assertDataValidInternal(d, t, ctx) {
if (isPairType(t)) {
if (isPairData(d)) {
assertDataListIfAny(d);
const dc = unpackComb('Pair', d);
const tc = unpackComb('pair', t);
assertDataValidInternal(dc.args[0], tc.args[0], ctx);
assertDataValidInternal(dc.args[1], tc.args[1], ctx);
return;
}
throw new MichelsonTypeError(t, `pair expected: ${JSON.stringify(d)}`, d);
}
switch (t.prim) {
// Atomic literals
case 'int':
if ('int' in d && isDecimal(d.int)) {
return;
}
throw new MichelsonTypeError(t, `integer value expected: ${JSON.stringify(d)}`, d);
case 'nat':
case 'mumav':
if ('int' in d && isNatural(d.int)) {
return;
}
throw new MichelsonTypeError(t, `natural value expected: ${JSON.stringify(d)}`, d);
case 'string':
if ('string' in d) {
return;
}
throw new MichelsonTypeError(t, `string value expected: ${JSON.stringify(d)}`, d);
case 'bytes':
case 'bls12_381_g1':
case 'bls12_381_g2':
if ('bytes' in d && parseBytes(d.bytes) !== null) {
return;
}
throw new MichelsonTypeError(t, `bytes value expected: ${JSON.stringify(d)}`, d);
case 'bool':
if ('prim' in d && (d.prim === 'True' || d.prim === 'False')) {
return;
}
throw new MichelsonTypeError(t, `boolean value expected: ${JSON.stringify(d)}`, d);
case 'key_hash':
if ('string' in d &&
checkDecodeMavrykID(d.string, 'ED25519PublicKeyHash', 'SECP256K1PublicKeyHash', 'P256PublicKeyHash') !== null) {
return;
}
else if ('bytes' in d) {
try {
decodePublicKeyHashBytes(d);
return;
}
catch (err) {
// ignore message
}
}
throw new MichelsonTypeError(t, `key hash expected: ${JSON.stringify(d)}`, d);
case 'timestamp':
if (('string' in d || 'int' in d) && parseDate(d) !== null) {
return;
}
throw new MichelsonTypeError(t, `timestamp expected: ${JSON.stringify(d)}`, d);
case 'address':
if ('string' in d) {
let address = d.string;
const ep = d.string.indexOf('%');
if (ep >= 0) {
// trim entry point
address = d.string.slice(0, ep);
}
if (checkDecodeMavrykID(address, 'ED25519PublicKeyHash', 'SECP256K1PublicKeyHash', 'P256PublicKeyHash', 'ContractHash', 'RollupAddress') !== null) {
return;
}
}
else if ('bytes' in d) {
try {
decodeAddressBytes(d);
return;
}
catch (err) {
// ignore message
}
}
throw new MichelsonTypeError(t, `address expected: ${JSON.stringify(d)}`, d);
case 'key':
if ('string' in d &&
checkDecodeMavrykID(d.string, 'ED25519PublicKey', 'SECP256K1PublicKey', 'P256PublicKey') !==
null) {
return;
}
else if ('bytes' in d) {
try {
decodePublicKeyBytes(d);
return;
}
catch (err) {
// ignore message
}
}
throw new MichelsonTypeError(t, `public key expected: ${JSON.stringify(d)}`, d);
case 'unit':
if ('prim' in d && d.prim === 'Unit') {
return;
}
throw new MichelsonTypeError(t, `unit value expected: ${JSON.stringify(d)}`, d);
case 'signature':
if ('bytes' in d ||
('string' in d &&
checkDecodeMavrykID(d.string, 'ED25519Signature', 'SECP256K1Signature', 'P256Signature', 'GenericSignature') !== null)) {
return;
}
throw new MichelsonTypeError(t, `signature expected: ${JSON.stringify(d)}`, d);
case 'chain_id':
if ('bytes' in d || 'string' in d) {
const x = 'string' in d ? decodeBase58Check(d.string) : parseBytes(d.bytes);
if (x !== null) {
return;
}
}
throw new MichelsonTypeError(t, `chain id expected: ${JSON.stringify(d)}`, d);
// Complex types
case 'option':
if ('prim' in d) {
if (d.prim === 'None') {
return;
}
else if (d.prim === 'Some') {
assertDataValidInternal(d.args[0], t.args[0], ctx);
return;
}
}
throw new MichelsonTypeError(t, `option expected: ${JSON.stringify(d)}`, d);
case 'list':
case 'set':
if (assertDataListIfAny(d)) {
//let prev: MichelsonData | undefined;
for (const v of d) {
assertDataValidInternal(v, t.args[0], ctx);
}
return;
}
throw new MichelsonTypeError(t, `${t.prim} expected: ${JSON.stringify(d)}`, d);
case 'or':
if ('prim' in d) {
if (d.prim === 'Left') {
assertDataValidInternal(d.args[0], t.args[0], ctx);
return;
}
else if (d.prim === 'Right') {
assertDataValidInternal(d.args[0], t.args[1], ctx);
return;
}
}
throw new MichelsonTypeError(t, `union (or) expected: ${JSON.stringify(d)}`, d);
case 'lambda':
if (isFunction(d)) {
const ret = functionTypeInternal(d, [t.args[0]], ctx);
if ('failed' in ret) {
throw new MichelsonTypeError(t, `function is failed with error type: ${ret.failed}`, d);
}
if (ret.length !== 1) {
throw new MichelsonTypeError(t, 'function must return a value', d);
}
assertScalarTypesEqual(t.args[1], ret[0]);
return;
}
throw new MichelsonTypeError(t, `function expected: ${JSON.stringify(d)}`, d);
case 'map':
case 'big_map':
if (Array.isArray(d)) {
//let prev: MichelsonMapElt | undefined;
for (const v of d) {
if (!('prim' in v) || v.prim !== 'Elt') {
throw new MichelsonTypeError(t, `map elements expected: ${JSON.stringify(d)}`, d);
}
assertDataValidInternal(v.args[0], t.args[0], ctx);
assertDataValidInternal(v.args[1], t.args[1], ctx);
}
return;
}
throw new MichelsonTypeError(t, `${t.prim} expected: ${JSON.stringify(d)}`, d);
case 'bls12_381_fr':
if (('int' in d && isDecimal(d.int)) || ('bytes' in d && parseBytes(d.bytes) !== null)) {
return;
}
throw new MichelsonTypeError(t, `BLS12-381 element expected: ${JSON.stringify(d)}`, d);
case 'sapling_state':
if (Array.isArray(d)) {
return;
}
throw new MichelsonTypeError(t, `sapling state expected: ${JSON.stringify(d)}`, d);
case 'ticket':
if ('prim' in d && d.prim === 'Ticket') {
assertDataValidInternal(d.args[0], { prim: 'address' }, ctx);
assertTypesEqual(d.args[1], t.args[0]);
assertDataValidInternal(d.args[2], t.args[0], ctx);
assertDataValidInternal(d.args[3], { prim: 'nat' }, ctx);
return;
}
else if (isPairData(d)) {
// backward compatibility
assertDataValidInternal(d, {
prim: 'pair',
args: [{ prim: 'address' }, t.args[0], { prim: 'nat' }],
}, ctx);
return;
}
throw new MichelsonTypeError(t, `ticket expected: ${JSON.stringify(d)}`, d);
default:
throw new MichelsonTypeError(t, `type ${typeID(t)} don't have Michelson literal representation`, d);
}
}
function instructionListType(inst, stack, ctx) {
let ret = stack;
let s = stack;
let i = 0;
for (const op of inst) {
const ft = functionTypeInternal(op, s, ctx);
ret = ft;
if ('failed' in ft) {
break;
}
s = ft;
i++;
}
if ('failed' in ret &&
ret.level == 0 &&
(!('prim' in ret.failed) || ret.failed.prim !== 'never') &&
i !== inst.length - 1) {
throw new MichelsonInstructionError(inst, ret, 'FAIL must appear in a tail position');
}
if ((ctx === null || ctx === void 0 ? void 0 : ctx.traceCallback) !== undefined) {
const trace = {
op: inst,
in: stack,
out: ret,
};
ctx.traceCallback(trace);
}
return 'failed' in ret ? { failed: ret.failed, level: ret.level + 1 } : ret;
}
function functionTypeInternal(inst, stack, ctx) {
const proto = (ctx === null || ctx === void 0 ? void 0 : ctx.protocol) || DefaultProtocol;
if (Array.isArray(inst)) {
return instructionListType(inst, stack, ctx);
}
const instruction = inst; // Make it const for type guarding
// make sure the stack has enough number of arguments of specific types
function args(n, ...typeIds) {
if (stack.length < typeIds.length + n) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: stack must have at least ${typeIds.length} element(s)`);
}
let i = n;
for (const ids of typeIds) {
if (ids !== null && ids.length !== 0) {
let ii = 0;
while (ii < ids.length && ids[ii] !== typeID(stack[i])) {
ii++;
}
if (ii === ids.length) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: stack type mismatch: [${i}] expected to be ${ids}, got ${typeID(stack[i])} instead`);
}
}
i++;
}
return stack.slice(n, typeIds.length + n);
}
function rethrow(fn) {
return (...args) => {
try {
return fn(...args);
}
catch (err) {
if (err instanceof MichelsonError) {
throw new MichelsonInstructionError(instruction, stack, err.message);
}
else {
throw err;
}
}
};
}
function rethrowTypeGuard(fn) {
return (arg) => {
try {
return fn(arg);
}
catch (err) {
if (err instanceof MichelsonError) {
throw new MichelsonInstructionError(instruction, stack, err.message);
}
else {
throw err;
}
}
};
}
const argAnn = rethrow(unpackAnnotations);
const ensureStacksEqual = rethrow(assertStacksEqual);
const ensureTypesEqual = rethrow(assertScalarTypesEqual);
const ensureComparableType = rethrowTypeGuard(assertMichelsonComparableType);
const ensurePackableType = rethrowTypeGuard(assertMichelsonPackableType);
const ensureStorableType = rethrowTypeGuard(assertMichelsonStorableType);
const ensurePushableType = rethrowTypeGuard(assertMichelsonPushableType);
const ensureBigMapStorableType = rethrowTypeGuard(assertMichelsonBigMapStorableType);
// unpack instruction annotations and assert their maximum number
function instructionAnn(num, opt) {
const a = argAnn(instruction, Object.assign(Object.assign({}, opt), { emptyFields: num.f !== undefined && num.f > 1, emptyVar: num.v !== undefined && num.v > 1 }));
const assertNum = (a, n, type) => {
if (a && a.length > (n || 0)) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: at most ${n || 0} ${type} annotations allowed`);
}
};
assertNum(a.f, num.f, 'field');
assertNum(a.t, num.t, 'type');
assertNum(a.v, num.v, 'variable');
return a;
}
// also keeps annotation class if null is provided
function annotate(tt, a) {
const tx = tt;
const t = Array.isArray(tx) ? { prim: 'pair', args: tx } : tx;
const src = argAnn(t);
const ann = a.v !== undefined || a.t !== undefined || a.f !== undefined
? [
...((a.v === null ? src.v : a.v) || []),
...((a.t === null ? src.t : a.t) || []),
...((a.f === null ? src.f : a.f) || []),
]
: undefined;
const rest = __rest(t, ["annots"]);
return Object.assign(Object.assign({}, rest), (ann && ann.length !== 0 && { annots: ann }));
}
// shortcut to copy at most one variable annotation from the instruction to the type
function annotateVar(t, def) {
const ia = instructionAnn({ v: 1 });
return annotate(t, {
v: ia.v !== undefined ? ia.v : def !== undefined ? [def] : null,
t: null,
});
}
// annotate CAR/CDR/UNPAIR/GET
function annotateField(arg, field, insAnn, n, defField) {
var _a, _b, _c, _d;
const fieldAnn = (_a = argAnn(field).f) === null || _a === void 0 ? void 0 : _a[0]; // field's field annotation
const insFieldAnn = (_b = insAnn.f) === null || _b === void 0 ? void 0 : _b[n];
if (insFieldAnn !== undefined &&
insFieldAnn !== '%' &&
fieldAnn !== undefined &&
insFieldAnn !== fieldAnn) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: field names doesn't match: ${insFieldAnn} !== ${fieldAnn}`);
}
const insVarAnn = (_c = insAnn.v) === null || _c === void 0 ? void 0 : _c[n]; // nth instruction's variable annotation
const varAnn = (_d = argAnn(arg).v) === null || _d === void 0 ? void 0 : _d[0]; // instruction argument's variable annotation
return annotate(field, {
t: null,
v: insVarAnn
? insVarAnn === '@%'
? fieldAnn
? ['@' + fieldAnn.slice(1)]
: undefined
: insVarAnn === '@%%'
? varAnn
? ['@' + varAnn.slice(1) + '.' + (fieldAnn ? fieldAnn.slice(1) : defField)]
: fieldAnn
? ['@' + fieldAnn.slice(1)]
: undefined
: [insVarAnn]
: null,
});
}
// comb helper functions
function getN(src, n, i = n) {
const p = unpackComb('pair', src);
if (i === 1) {
return [p.args[0]];
}
else if (i === 2) {
return p.args;
}
const right = p.args[1];
if (isPairType(right)) {
return [p.args[0], ...getN(right, n, i - 1)];
}
else {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: at least ${n} fields are expected`);
}
}
function getNth(src, n, i = n) {
if (i === 0) {
return src;
}
const p = unpackComb('pair', src);
if (i === 1) {
return p.args[0];
}
const right = p.args[1];
if (isPairType(right)) {
return getNth(right, n, i - 2);
}
else if (i === 2) {
return right;
}
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: at least ${n + 1} fields are expected`);
}
function updateNth(src, x, n, i = n) {
if (i === 0) {
return x;
}
const p = unpackComb('pair', src);
if (i === 1) {
return Object.assign(Object.assign({}, p), { args: [x, p.args[1]] });
}
const right = p.args[1];
if (isPairType(right)) {
return Object.assign(Object.assign({}, p), { args: [p.args[0], updateNth(right, x, n, i - 2)] });
}
else if (i === 2) {
return Object.assign(Object.assign({}, p), { args: [p.args[0], x] });
}
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: at least ${n + 1} fields are expected`);
}
const varSuffix = (a, suffix) => [
'@' + (a.v ? a.v[0].slice(1) + '.' : '') + suffix,
];
function branchType(br0, br1) {
if ('failed' in br0 || 'failed' in br1) {
return 'failed' in br0 ? br1 : br0;
}
else {
ensureStacksEqual(br0, br1);
return br0;
}
}
const retStack = ((instruction) => {
var _a, _b, _c, _d, _e;
switch (instruction.prim) {
case 'DUP': {
const n = instruction.args ? parseInt(instruction.args[0].int, 10) : 1;
if (n === 0) {
throw new MichelsonInstructionError(instruction, stack, 'DUP 0 is forbidden');
}
const s = args(n - 1, null)[0];
if (typeID(s) === 'ticket') {
throw new MichelsonInstructionError(instruction, stack, "ticket can't be DUPed");
}
return [s, ...stack];
}
case 'SWAP': {
const s = args(0, null, null);
instructionAnn({});
return [s[1], s[0], ...stack.slice(2)];
}
case 'SOME':
return [
annotate({ prim: 'option', args: [args(0, null)[0]] }, instructionAnn({ t: 1, v: 1 })),
...stack.slice(1),
];
case 'UNIT':
return [annotate({ prim: 'unit' }, instructionAnn({ v: 1, t: 1 })), ...stack];
case 'PAIR': {
const n = instruction.args ? parseInt(instruction.args[0].int, 10) : 2;
if (n < 2) {
throw new MichelsonInstructionError(instruction, stack, `PAIR ${n} is forbidden`);
}
const s = args(0, ...new Array(n).fill(null));
const ia = instructionAnn({ f: n, t: 1, v: 1 }, { specialFields: true });
const trim = (s) => {
const i = s.lastIndexOf('.');
return s.slice(i > 0 ? i + 1 : 1);
};
const retArgs = s.map((v, i) => {
var _a;
const va = argAnn(v);
const f = ia.f && ia.f.length > i && ia.f[i] !== '%'
? ia.f[i] === '%@'
? va.v
? ['%' + trim(((_a = va.v) === null || _a === void 0 ? void 0 : _a[0]) || '')]
: undefined
: [ia.f[i]]
: undefined;
return annotate(v, { v: null, t: null, f });
});
return [
annotate({
prim: 'pair',
args: retArgs,
}, { t: ia.t, v: ia.v }),
...stack.slice(n),
];
}
case 'UNPAIR': {
const n = instruction.args ? parseInt(instruction.args[0].int, 10) : 2;
if (n < 2) {
throw new MichelsonInstructionError(instruction, stack, `UNPAIR ${n} is forbidden`);
}
const s = args(0, ['pair'])[0];
const ia = instructionAnn({ f: 2, v: 2 }, { specialVar: true });
const fields = getN(s, n);
return [
...fields.map((field, i) => annotateField(s, field, ia, i, i === 0 ? 'car' : 'cdr')),
...stack.slice(1),
];
}
case 'CAR':
case 'CDR': {
const s = unpackComb('pair', args(0, ['pair'])[0]);
const field = s.args[instruction.prim === 'CAR' ? 0 : 1];
const ia = instructionAnn({ f: 1, v: 1 }, { specialVar: true });
return [
annotateField(s, field, ia, 0, instruction.prim.toLocaleLowerCase()),
...stack.slice(1),
];
}
case 'CONS': {
const s = args(0, null, ['list']);
ensureTypesEqual(s[0], s[1].args[0]);
return [annotateVar({ prim: 'list', args: [s[1].args[0]] }), ...stack.slice(2)];
}
case 'SIZE':
args(0, ['string', 'list', 'set', 'map', 'bytes']);
return [annotateVar({ prim: 'nat' }), ...stack.slice(1)];
case 'MEM': {
const s = args(0, null, ['set', 'map', 'big_map']);
ensureComparableType(s[0]);
ensureTypesEqual(s[0], s[1].args[0]);
return [annotateVar({ prim: 'bool' }), ...stack.slice(2)];
}
case 'GET':
if (instruction.args) {
// comb operation
const n = parseInt(instruction.args[0].int, 10);
const s = args(0, ['pair'])[0];
return [annotateVar(getNth(s, n)), ...stack.slice(1)];
}
else {
// map operation
const s = args(0, null, ['map', 'big_map']);
ensureComparableType(s[0]);
ensureTypesEqual(s[0], s[1].args[0]);
return [annotateVar({ prim: 'option', args: [s[1].args[1]] }), ...stack.slice(2)];
}
case 'UPDATE':
if (instruction.args) {
// comb operation
const n = parseInt(instruction.args[0].int, 10);
const s = args(0, null, ['pair']);
return [annotateVar(updateNth(s[1], s[0], n)), ...stack.slice(2)];
}
else {
// map operation
const s0 = args(0, null, ['bool', 'option']);
ensureComparableType(s0[0]);
if (s0[1].prim === 'bool') {
const s1 = args(2, ['set']);
ensureTypesEqual(s0[0], s1[0].args[0]);
return [
annotateVar({
prim: 'set',
args: [annotate(s0[0], { t: null })],
}),
...stack.slice(3),
];
}
const s1 = args(2, ['map', 'big_map']);
ensureTypesEqual(s0[0], s1[0].args[0]);
if (s1[0].prim === 'map') {
return [
annotateVar({
prim: 'map',
args: [annotate(s0[0], { t: null }), annotate(s0[1].args[0], { t: null })],
}),
...stack.slice(3),
];
}
ensureBigMapStorableType(s0[1].args[0]);
return [
annotateVar({
prim: 'big_map',
args: [annotate(s0[0], { t: null }), annotate(s0[1].args[0], { t: null })],
}),
...stack.slice(3),
];
}
case 'GET_AND_UPDATE': {
const ia = instructionAnn({ v: 2 });
const s = args(0, null, ['option'], ['map', 'big_map']);
ensureComparableType(s[0]);
ensureTypesEqual(s[0], s[2].args[0]);
ensureTypesEqual(s[1].args[0], s[2].args[1]);
const va = (_a = ia.v) === null || _a === void 0 ? void 0 : _a.map((v) => (v !== '@' ? [v] : undefined));
if (s[2].prim === 'map') {
return [
annotate({ prim: 'option', args: [s[2].args[1]] }, { v: va === null || va === void 0 ? void 0 : va[0] }),
annotate({
prim: 'map',
args: [annotate(s[0], { t: null }), annotate(s[1].args[0], { t: null })],
}, { v: va === null || va === void 0 ? void 0 : va[1] }),
...stack.slice(3),
];
}
ensureBigMapStorableType(s[1].args[0]);
return [
annotate({ prim: 'option', args: [s[2].args[1]] }, { v: va === null || va === void 0 ? void 0 : va[0] }),
annotate({
prim: 'big_map',
args: [annotate(s[0], { t: null }), annotate(s[1].args[0], { t: null })],
}, { v: va === null || va === void 0 ? void 0 : va[1] }),
...stack.slice(3),
];
}
case 'EXEC': {
const s = args(0, null, ['lambda']);
ensureTypesEqual(s[0], s[1].args[0]);
return [annotateVar(s[1].args[1]), ...stack.slice(2)];
}
case 'APPLY': {
const s = args(0, null, ['lambda']);
ensureStorableType(s[0]);
ensurePushableType(s[0]);
if (!isPairType(s[1].args[0])) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: function's argument must be a pair: ${typeID(s[1].args[0])}`);
}
const pt = s[1].args[0];
ensureTypesEqual(s[0], typeArgs(pt)[0]);
return [
annotateVar({ prim: 'lambda', args: [typeArgs(pt)[1], s[1].args[1]] }),
...stack.slice(2),
];
}
case 'FAILWITH': {
const s = args(0, null)[0];
if (!ProtoInferiorTo(proto, exports.Protocol.PtAtLas)) {
ensurePackableType(s);
}
return { failed: s, level: 0 };
}
case 'NEVER':
args(0, ['never']);
return { failed: { prim: 'never' }, level: 0 };
case 'RENAME':
return [annotateVar(args(0, null)[0]), ...stack.slice(1)];
case 'CONCAT': {
const s0 = args(0, ['string', 'list', 'bytes']);
if (s0[0].prim === 'list') {
if (typeID(s0[0].args[0]) !== 'string' && typeID(s0[0].args[0]) !== 'bytes') {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: can't concatenate list of ${typeID(s0[0].args[0])}'s`);
}
return [annotateVar(s0[0].args[0]), ...stack.slice(1)];
}
const s1 = args(1, ['string', 'bytes']);
if (s0[0].prim !== s1[0].prim) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: can't concatenate ${s0[0].prim} with ${s1[0].prim}`);
}
return [annotateVar(s1[0]), ...stack.slice(2)];
}
case 'SLICE':
return [
annotateVar({ prim: 'option', args: [args(0, ['nat'], ['nat'], ['string', 'bytes'])[2]] }, '@slice'),
...stack.slice(3),
];
case 'PACK': {
const s = args(0, null)[0];
ensurePackableType(s);
return [annotateVar({ prim: 'bytes' }, '@packed'), ...stack.slice(1)];
}
case 'ADD': {
const s = args(0, ['nat', 'int', 'timestamp', 'mumav', 'bls12_381_g1', 'bls12_381_g2', 'bls12_381_fr'], ['nat', 'int', 'timestamp', 'mumav', 'bls12_381_g1', 'bls12_381_g2', 'bls12_381_fr']);
if ((s[0].prim === 'nat' && s[1].prim === 'int') ||
(s[0].prim === 'int' && s[1].prim === 'nat')) {
return [annotateVar({ prim: 'int' }), ...stack.slice(2)];
}
else if ((s[0].prim === 'int' && s[1].prim === 'timestamp') ||
(s[0].prim === 'timestamp' && s[1].prim === 'int')) {
return [annotateVar({ prim: 'timestamp' }), ...stack.slice(2)];
}
else if ((s[0].prim === 'int' ||
s[0].prim === 'nat' ||
s[0].prim === 'mumav' ||
s[0].prim === 'bls12_381_g1' ||
s[0].prim === 'bls12_381_g2' ||
s[0].prim === 'bls12_381_fr') &&
s[0].prim === s[1].prim) {
return [annotateVar(s[0]), ...stack.slice(2)];
}
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: can't add ${s[0].prim} to ${s[1].prim}`);
}
case 'SUB': {
const s = ProtoInferiorTo(proto, exports.Protocol.PtAtLas)
? args(0, ['nat', 'int', 'timestamp', 'mumav'], ['nat', 'int', 'timestamp', 'mumav'])
: args(0, ['nat', 'int', 'timestamp'], ['nat', 'int', 'timestamp']);
if (((s[0].prim === 'nat' || s[0].prim === 'int') &&
(s[1].prim === 'nat' || s[1].prim === 'int')) ||
(s[0].prim === 'timestamp' && s[1].prim === 'timestamp')) {
return [annotateVar({ prim: 'int' }), ...stack.slice(2)];
}
else if (s[0].prim === 'timestamp' && s[1].prim === 'int') {
return [annotateVar({ prim: 'timestamp' }), ...stack.slice(2)];
}
else if (s[0].prim === 'mumav' && s[1].prim === 'mumav') {
return [annotateVar({ prim: 'mumav' }), ...stack.slice(2)];
}
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: can't subtract ${s[0].prim} from ${s[1].prim}`);
}
case 'SUB_MUMAV': {
args(0, ['mumav'], ['mumav']);
return [annotateVar({ prim: 'option', args: [{ prim: 'mumav' }] }), ...stack.slice(2)];
}
case 'MUL': {
const s = args(0, ['nat', 'int', 'mumav', 'bls12_381_g1', 'bls12_381_g2', 'bls12_381_fr'], ['nat', 'int', 'mumav', 'bls12_381_g1', 'bls12_381_g2', 'bls12_381_fr']);
if ((s[0].prim === 'nat' && s[1].prim === 'int') ||
(s[0].prim === 'int' && s[1].prim === 'nat')) {
return [annotateVar({ prim: 'int' }), ...stack.slice(2)];
}
else if ((s[0].prim === 'nat' && s[1].prim === 'mumav') ||
(s[0].prim === 'mumav' && s[1].prim === 'nat')) {
return [annotateVar({ prim: 'mumav' }), ...stack.slice(2)];
}
else if (((s[0].prim === 'bls12_381_g1' ||
s[0].prim === 'bls12_381_g2' ||
s[0].prim === 'bls12_381_fr') &&
s[1].prim === 'bls12_381_fr') ||
((s[0].prim === 'nat' || s[0].prim === 'int') && s[0].prim === s[1].prim)) {
return [annotateVar(s[0]), ...stack.slice(2)];
}
else if (((s[0].prim === 'nat' || s[0].prim === 'int') && s[1].prim === 'bls12_381_fr') ||
((s[1].prim === 'nat' || s[1].prim === 'int') && s[0].prim === 'bls12_381_fr')) {
return [annotateVar({ prim: 'bls12_381_fr' }), ...stack.slice(2)];
}
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: can't multiply ${s[0].prim} by ${s[1].prim}`);
}
case 'EDIV': {
const res = (a, b) => ({
prim: 'option',
args: [{ prim: 'pair', args: [{ prim: a }, { prim: b }] }],
});
const s = args(0, ['nat', 'int', 'mumav'], ['nat', 'int', 'mumav']);
if (s[0].prim === 'nat' && s[1].prim === 'nat') {
return [annotateVar(res('nat', 'nat')), ...stack.slice(2)];
}
else if ((s[0].prim === 'nat' || s[0].prim === 'int') &&
(s[1].prim === 'nat' || s[1].prim === 'int')) {
return [annotateVar(res('int', 'nat')), ...stack.slice(2)];
}
else if (s[0].prim === 'mumav' && s[1].prim === 'nat') {
return [annotateVar(res('mumav', 'mumav')), ...stack.slice(2)];
}
else if (s[0].prim === 'mumav' && s[1].prim === 'mumav') {
return [annotateVar(res('nat', 'mumav')), ...stack.slice(2)];
}
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: can't euclideally divide ${s[0].prim} by ${s[1].prim}`);
}
case 'ABS':
args(0, ['int']);
return [annotateVar({ prim: 'nat' }), ...stack.slice(1)];
case 'ISNAT':
args(0, ['int']);
return [annotateVar({ prim: 'option', args: [{ prim: 'nat' }] }), ...stack.slice(1)];
case 'INT':
args(0, ['nat', 'bls12_381_fr', 'bytes']);
return [annotateVar({ prim: 'int' }), ...stack.slice(1)];
case 'BYTES':
args(0, ['nat', 'int']);
return [annotateVar({ prim: 'bytes' }), ...stack.slice(1)];
case 'NAT':
args(0, ['bytes']);
return [annotateVar({ prim: 'nat' }), ...stack.slice(1)];
case 'NEG': {
const s = args(0, ['nat', 'int', 'bls12_381_g1', 'bls12_381_g2', 'bls12_381_fr'])[0];
if (s.prim === 'nat' || s.prim === 'int') {
return [annotateVar({ prim: 'int' }), ...stack.slice(1)];
}
return [annotateVar(s), ...stack.slice(1)];
}
case 'LSL':
case 'LSR':
args(0, ['nat', 'bytes'], ['nat', 'bytes']);
return [annotateVar({ prim: 'nat' }), ...stack.slice(2)];
case 'OR':
case 'XOR': {
const s = args(0, ['nat', 'bytes', 'bool'], ['nat', 'bytes', 'bool']);
if (s[0].prim !== s[1].prim) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: both arguments must be of the same type: ${s[0].prim}, ${s[1].prim}`);
}
return [annotateVar(s[1]), ...stack.slice(2)];
}
case 'AND': {
const s = args(0, ['nat', 'bytes', 'bool', 'int'], ['nat', 'bytes', 'bool']);
if ((s[0].prim !== 'int' || s[1].prim !== 'nat') && s[0].prim !== s[1].prim) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: both arguments must be of the same type: ${s[0].prim}, ${s[1].prim}`);
}
return [annotateVar(s[1]), ...stack.slice(2)];
}
case 'NOT': {
const s = args(0, ['nat', 'bytes', 'bool', 'int'])[0];
if (s.prim === 'bool') {
return [annotateVar({ prim: 'bool' }), ...stack.slice(1)];
}
return [annotateVar({ prim: 'int' }), ...stack.slice(1)];
}
case 'COMPARE': {
const s = args(0, null, null);
ensureComparableType(s[0]);
ensureComparableType(s[1]);
return [annotateVar({ prim: 'int' }), ...stack.slice(2)];
}
case 'EQ':
case 'NEQ':
case 'LT':
case 'GT':
case 'LE':
case 'GE':
args(0, ['int']);
return [annotateVar({ prim: 'bool' }), ...stack.slice(1)];
case 'SELF': {
if ((ctx === null || ctx === void 0 ? void 0 : ctx.contract) === undefined) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: contract required`);
}
const ia = instructionAnn({ f: 1, v: 1 });
const ep = contractEntryPoint(ctx.contract, (_b = ia.f) === null || _b === void 0 ? void 0 : _b[0]);
if (ep === null) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: contract has no entrypoint ${ep}`);
}
return [
annotate({ prim: 'contract', args: [ep] }, { v: ia.v ? ia.v : ['@self'] }),
...stack,
];
}
case 'TRANSFER_TOKENS': {
const s = args(0, null, ['mumav'], ['contract']);
ensureTypesEqual(s[0], s[2].args[0]);
return [annotateVar({ prim: 'operation' }), ...stack.slice(3)];
}
case 'SET_DELEGATE': {
const s = args(0, ['option'])[0];
if (typeID(s.args[0]) !== 'key_hash') {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: key hash expected: ${typeID(s.args[0])}`);
}
return [annotateVar({ prim: 'operation' }), ...stack.slice(1)];
}
case 'IMPLICIT_ACCOUNT':
args(0, ['key_hash']);
return [annotateVar({ prim: 'contract', args: [{ prim: 'unit' }] }), ...stack.slice(1)];
case 'NOW':
return [annotateVar({ prim: 'timestamp' }, '@now'), ...stack];
case 'AMOUNT':
return [annotateVar({ prim: 'mumav' }, '@amount'), ...stack];
case 'BALANCE':
return [annotateVar({ prim: 'mumav' }, '@balance'), ...stack];
case 'CHECK_SIGNATURE':
args(0, ['key'], ['signature'], ['bytes']);
return [annotateVar({ prim: 'bool' }), ...stack.slice(3)];
case 'BLAKE2B':
case 'SHA256':
case 'SHA512':
case 'KECCAK':
case 'SHA3':
args(0, ['bytes']);
return [annotateVar({ prim: 'bytes' }), ...stack.slice(1)];
case 'HASH_KEY':
args(0, ['key']);
return [annotateVar({ prim: 'key_hash' }), ...stack.slice(1)];
case 'SOURCE':
return [annotateVar({ prim: 'address' }, '@source'), ...stack];
case 'SENDER':
return [annotateVar({ prim: 'address' }, '@sender'), ...stack];
case 'ADDRESS': {
const s = args(0, ['contract'])[0];
const ia = instructionAnn({ v: 1 });
return [
annotate({ prim: 'address', [refContract]: s }, { v: ia.v ? ia.v : varSuffix(argAnn(s), 'address') }),
...stack.slice(1),
];
}
case 'SELF_ADDRESS': {
const addr = { prim: 'address' };
if ((ctx === null || ctx === void 0 ? void 0 : ctx.contract) !== undefined) {
addr[refContract] = {
prim: 'contract',
args: [contractSection(ctx.contract, 'parameter').args[0]],
};
}
return [annotateVar(addr, '@address'), ...stack];
}
case 'CHAIN_ID':
return [annotateVar({ prim: 'chain_id' }), ...stack];
case 'DROP': {
instructionAnn({});
const n = instruction.args !== undefined ? parseInt(instruction.args[0].int, 10) : 1;
args(n - 1, null);
return stack.slice(n);
}
case 'DIG': {
instructionAnn({});
const n = parseInt(instruction.args[0].int, 10);
return [args(n, null)[0], ...stack.slice(0, n), ...stack.slice(n + 1)];
}
case 'DUG': {
instructionAnn({});
const n = parseInt(instruction.args[0].int, 10);
return [...stack.slice(1, n + 1), args(0, null)[0], ...stack.slice(n + 1)];
}
case 'NONE':
assertTypeAnnotationsValid(instruction.args[0]);
return [
annotate({ prim: 'option', args: [instruction.args[0]] }, instructionAnn({ t: 1, v: 1 })),
...stack,
];
case 'LEFT':
case 'RIGHT': {
const s = args(0, null)[0];
const ia = instructionAnn({ f: 2, t: 1, v: 1 }, { specialFields: true });
const va = argAnn(s);
const children = [
annotate(s, {
t: null,
v: null,
f: ia.f && ia.f.length > 0 && ia.f[0] !== '%'
? ia.f[0] === '%@'
? va.v
? ['%' + va.v[0].slice(1)]
: undefined
: ia.f
: undefined,
}),
annotate(instruction.args[0], {
t: null,
f: ia.f && ia.f.length > 1 && ia.f[1] !== '%' ? ia.f : undefined,
}),
];
return [
annotate({
prim: 'or',
args: instruction.prim === 'LEFT' ? children : [children[1], children[0]],
}, { t: ia.t, v: ia.v }),
...stack.slice(1),
];
}
case 'NIL':
assertTypeAnnotationsValid(instruction.args[0]);
return [
annotate({ prim: 'list', args: [instruction.args[0]] }, instructionAnn({ t: 1, v: 1 })),
...stack,
];
case 'UNPACK':
args(0, ['bytes']);
assertTypeAnnotationsValid(instruction.args[0]);
return [
annotateVar({ prim: 'option', args: [instruction.args[0]] }, '@unpacked'),
...stack.slice(1),
];
case 'CONTRACT': {
const s = args(0, ['address'])[0];
assertTypeAnnotationsValid(instruction.args[0]);
const ia = instructionAnn({ v: 1, f: 1 });
const contract = s[refContract];
if (contract !== undefined) {
const ep = contractEntryPoint(contract, (_c = ia.f) === null || _c === void 0 ? void 0 : _c[0]);
if (ep === null) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: contract has no entrypoint ${ep}`);
}
ensureTypesEqual(ep, instruction.args[0]);
}
return [
annotate({ prim: 'option', args: [{ prim: 'contract', args: [instruction.args[0]] }] }, { v: ia.v ? ia.v : varSuffix(argAnn(s), 'contract') }),
...stack.slice(1),
];
}
case 'CAST': {
instructionAnn({});
const s = args(0, null)[0];
assertTypeAnnotationsValid(instruction.args[0]);
ensureTypesEqual(instruction.args[0], s);
return [instruction.args[0], ...stack.slice(1)];
}
case 'IF_NONE': {
instructionAnn({});
const s = args(0, ['option'])[0];
const tail = stack.slice(1);
const br0 = functionTypeInternal(instruction.args[0], tail, ctx);
const br1 = functionTypeInternal(instruction.args[1], [annotate(s.args[0], { t: null, v: varSuffix(argAnn(s), 'some') }), ...tail], ctx);
return branchType(br0, br1);
}
case 'IF_LEFT': {
instructionAnn({});
const s = args(0, ['or'])[0];
const va = argAnn(s);
const lefta = argAnn(s.args[0]);
const righta = argAnn(s.args[1]);
const tail = stack.slice(1);
const br0 = functionTypeInternal(instruction.args[0], [
annotate(s.args[0], {
t: null,
v: varSuffix(va, lefta.f ? lefta.f[0].slice(1) : 'left'),
}),
...tail,
], ctx);
const br1 = functionTypeInternal(instruction.args[1], [
annotate(s.args[1], {
t: null,
v: varSuffix(va, righta.f ? righta.f[0].slice(1) : 'right'),
}),
...tail,
], ctx);
return branchType(br0, br1);
}
case 'IF_CONS': {
instructionAnn({});
const s = args(0, ['list'])[0];
const va = argAnn(s);
const tail = stack.slice(1);
const br0 = functionTypeInternal(instruction.args[0], [
annotate(s.args[0], { t: null, v: varSuffix(va, 'hd') }),
annotate(s, { t: null, v: varSuffix(va, 'tl') }),
...tail,
], ctx);
const br1 = functionTypeInternal(instruction.args[1], tail, ctx);
return branchType(br0, br1);
}
case 'IF': {
instructionAnn({});
args(0, ['bool']);
const tail = stack.slice(1);
const br0 = functionTypeInternal(instruction.args[0], tail, ctx);
const br1 = functionTypeInternal(instruction.args[1], tail, ctx);
return branchType(br0, br1);
}
case 'MAP': {
const s = args(0, ['list', 'map', 'option'])[0];
const tail = stack.slice(1);
const elt = s.prim === 'map' ? { prim: 'pair', args: s.args } : s.args[0];
const body = functionTypeInternal(instruction.args[0], [annotate(elt, { t: null, v: varSuffix(argAnn(s), 'elt') }), ...tail], ctx);
if ('failed' in body) {
if (!('prim' in body.failed) || body.failed.prim !== 'never') {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: FAIL is not allowed in MAP`);
}
return { failed: body.failed, level: body.level + 1 };
}
if (body.length < 1) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: function must return a value`);
}
ensureStacksEqual(body.slice(1), tail);
return s.prim === 'list'
? [annotateVar({ prim: 'list', args: [body[0]] }), ...tail]
: s.prim === 'map'
? [annotateVar({ prim: 'map', args: [s.args[0], body[0]] }), ...tail]
: [annotateVar({ prim: 'option', args: [body[0]] }), ...tail];
}
case 'ITER': {
instructionAnn({});
const s = args(0, ['set', 'list', 'map'])[0];
const tail = stack.slice(1);
const elt = s.prim === 'map' ? { prim: 'pair', args: s.args } : s.args[0];
const body = functionTypeInternal(instruction.args[0], [annotate(elt, { t: null, v: varSuffix(argAnn(s), 'elt') }), ...tail], ctx);
if ('failed' in body) {
return { failed: body.failed, level: body.level + 1 };
}
ensureStacksEqual(body, tail);
return tail;
}
case 'LOOP': {
instructionAnn({});
args(0, ['bool']);
const tail = stack.slice(1);
const body = functionTypeInternal(instruction.args[0], tail, ctx);
if ('failed' in body) {
return { failed: body.failed, level: body.level + 1 };
}
ensureStacksEqual(body, [{ prim: 'bool' }, ...tail]);
return tail;
}
case 'LOOP_LEFT': {
instructionAnn({});
const s = args(0, ['or'])[0];
const tail = stack.slice(1);
const body = functionTypeInternal(instruction.args[0], [annotate(s.args[0], { t: null, v: varSuffix(argAnn(s), 'left') }), ...tail], ctx);
if ('failed' in body) {
return { failed: body.failed, level: body.level + 1 };
}
ensureStacksEqual(body, [s, ...tail]);
return [annotate(s.args[1], { t: null, v: instructionAnn({ v: 1 }).v }), ...tail];
}
case 'DIP': {
instructionAnn({});
const n = instruction.args.length === 2 ? parseInt(instruction.args[0].int, 10) : 1;
args(n - 1, null);
const head = stack.slice(0, n);
const tail = stack.slice(n);
// ternary operator is a type guard so use it instead of just `instruction.args.length - 1`
const body = instruction.args.length === 2
? functionTypeInternal(instruction.args[1], tail, ctx)
: functionTypeInternal(instruction.args[0], tail, ctx);
if ('failed' in body) {
return { failed: body.failed, level: body.level + 1 };
}
return [...head, ...body];
}
case 'CREATE_CONTRACT': {
const ia = instructionAnn({ v: 2 });
const s = args(0, ['option'], ['mumav'], null);
if (typeID(s[0].args[0]) !== 'key_hash') {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: key hash expected: ${typeID(s[0].args[0])}`);
}
if (ensureStorableType(s[2])) {
assertContractValid(instruction.args[0]);
assertScalarTypesEqual(contractSection(instruction.args[0], 'storage').args[0], s[2]);
}
const va = (_d = ia.v) === null || _d === void 0 ? void 0 : _d.map((v) => (v !== '@' ? [v] : undefined));
return [
annotate({ prim: 'operation' }, { v: va === null || va === void 0 ? void 0 : va[0] }),
annotate({
prim: 'address',
[refContract]: {
prim: 'contract',
args: [contractSection(instruction.args[0], 'parameter').args[0]],
},
}, { v: va === null || va === void 0 ? void 0 : va[1] }),
...stack.slice(3),
];
}
case 'PUSH':
assertTypeAnnotationsValid(instruction.args[0]);
assertDataValidInternal(instruction.args[1], instruction.args[0], Object.assign(Object.assign({}, ctx), { contract: undefined }));
return [annotateVar(instruction.args[0]), ...stack];
case 'EMPTY_SET':
assertTypeAnnotationsValid(instruction.args[0]);
ensureComparableType(instruction.args[0]);
return [
annotate({ prim: 'set', args: instruction.args }, instructionAnn({ t: 1, v: 1 })),
...stack,
];
case 'EMPTY_MAP':
assertTypeAnnotationsValid(instruction.args[0]);
ensureComparableType(instruction.args[0]);
assertTypeAnnotationsValid(instruction.args[1]);
return [
annotate({ prim: 'map', args: instruction.args }, instructionAnn({ t: 1, v: 1 })),
...stack,
];
case 'EMPTY_BIG_MAP':
assertTypeAnnotationsValid(instruction.args[0]);
ensureComparableType(instruction.args[0]);
assertTypeAnnotationsValid(instruction.args[1]);
ensureBigMapStorableType(instruction.args[0]);
return [
annotate({ prim: 'big_map', args: instruction.args }, instructionAnn({ t: 1, v: 1 })),
...stack,
];
case 'LAMBDA_REC':
case 'LAMBDA': {
assertTypeAnnotationsValid(instruction.args[0]);
assertTypeAnnotationsValid(instruction.args[1]);
const s = [instruction.args[0]];
if (instruction.prim === 'LAMBDA_REC') {
s.push({ prim: 'lambda', args: [instruction.args[0], instruction.args[1]] });
}
const body = functionTypeInternal(instruction.args[2], s, Object.assign(Object.assign({}, ctx), { contract: undefined }));
if ('failed' in body) {
return { failed: body.failed, level: body.level + 1 };
}
if (body.length !== 1) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: function must return a value`);
}
ensureTypesEqual(instruction.args[1], body[0]);
return [
annotateVar({ prim: 'lambda', args: [instruction.args[0], instruction.args[1]] }),
...stack,
];
}
case 'LEVEL':
return [annotateVar({ prim: 'nat' }, '@level'), ...stack];
case 'TOTAL_VOTING_POWER':
return [annotateVar({ prim: 'nat' }), ...stack];
case 'VOTING_POWER':
args(0, ['key_hash']);
return [annotateVar({ prim: 'nat' }), ...stack.slice(1)];
case 'TICKET': {
const s = args(0, null, ['nat'])[0];
ensureComparableType(s);
if (ProtoInferiorTo(proto, exports.Protocol.PtAtLas)) {
return [
annotate({ prim: 'ticket', args: [s] }, instructionAnn({ t: 1, v: 1 })),
...stack.slice(2),
];
}
else {
return [
annotateVar({
prim: 'option',
args: [annotate({ prim: 'ticket', args: [s] }, instructionAnn({ t: 1, v: 1 }))],
}),
...stack.slice(2),
];
}
}
case 'JOIN_TICKETS': {
const s = unpackComb('pair', args(0, ['pair'])[0]);
if (typeID(s.args[0]) !== 'ticket') {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: ticket expected: ${typeID(s.args[0])}`);
}
ensureTypesEqual(s.args[0], s.args[1]);
return [
annotateVar({
prim: 'option',
args: [annotate(s.args[0], { t: null })],
}),
...stack.slice(1),
];
}
case 'SPLIT_TICKET': {
const s = args(0, ['ticket'], ['pair']);
const p = unpackComb('pair', s[1]);
if (typeID(p.args[0]) !== 'nat') {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: nat expected: ${typeID(p.args[0])}`);
}
ensureTypesEqual(p.args[0], p.args[1]);
return [
annotateVar({
prim: 'option',
args: [
{
prim: 'pair',
args: [annotate(s[0], { t: null }), annotate(s[0], { t: null })],
},
],
}),
...stack.slice(2),
];
}
case 'READ_TICKET': {
const ia = instructionAnn({ v: 2 });
const s = args(0, ['ticket'])[0];
const va = (_e = ia.v) === null || _e === void 0 ? void 0 : _e.map((v) => (v !== '@' ? [v] : undefined));
return [
annotate({
prim: 'pair',
args: [{ prim: 'address' }, annotate(s.args[0], { t: null }), { prim: 'nat' }],
}, { v: va === null || va === void 0 ? void 0 : va[0] }),
annotate(s, { v: va === null || va === void 0 ? void 0 : va[1], t: null }),
...stack.slice(1),
];
}
case 'PAIRING_CHECK': {
const p = args(0, ['list'])[0].args[0];
if (!isPairType(p)) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: pair expected: ${typeID(p)}`);
}
const c = unpackComb('pair', p);
if (typeID(c.args[0]) !== 'bls12_381_g1') {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: bls12_381_g1 expected: ${typeID(c.args[0])}`);
}
if (typeID(c.args[1]) !== 'bls12_381_g2') {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: bls12_381_g2 expected: ${typeID(c.args[1])}`);
}
return [annotateVar({ prim: 'bool' }), ...stack.slice(1)];
}
case 'SAPLING_EMPTY_STATE':
return [
annotate({ prim: 'sapling_state', args: [instruction.args[0]] }, instructionAnn({ v: 1, t: 1 })),
...stack,
];
case 'SAPLING_VERIFY_UPDATE': {
const s = args(0, ['sapling_transaction'], ['sapling_state']);
if (parseInt(s[0].args[0].int, 10) !== parseInt(s[1].args[0].int, 10)) {
throw new MichelsonInstructionError(instruction, stack, `${instruction.prim}: sapling memo size mismatch: ${s[0].args[0].int} != ${s[1].args[0].int}`);
}
return ProtoInferiorTo(proto, exports.Protocol.PtAtLas)
? [
annotateVar({
prim: 'option',
args: [
{
prim: 'pair',
args: [{ prim: 'int' }, annotate(s[1], { t: null })],
},
],
}),
...stack.slice(2),
]
: [
annotateVar({
prim: 'option',
args: [
{
prim: 'pair',
args: [
{ prim: 'bytes' },
{
prim: 'pair',
args: [{ prim: 'int' }, annotate(s[1], { t: null })],
},
],
},
],
}),
...stack.slice(2),
];
}
case 'OPEN_CHEST':
args(0, ['chest_key'], ['chest'], ['nat']);
return [
annotateVar({ prim: 'or', args: [{ prim: 'bytes' }, { prim: 'bool' }] }),
...stack.slice(3),
];
case 'VIEW': {
const s = args(0, null, ['address']);
ensurePushableType(s[0]);
return [annotateVar({ prim: 'option', args: [instruction.args[1]] }), ...stack.slice(2)];
}
case 'MIN_BLOCK_TIME':
return [annotateVar({ prim: 'nat' }), ...stack];
case 'EMIT': {
const ia = instructionAnn({ f: 1, t: 1 });
if (instruction.args) {
const s = args(0, null);
ensureTypesEqual(s[0], instruction.args[0]);
return [annotate({ prim: 'operation' }, ia), ...stack.slice(1)];
}
return [annotate({ prim: 'operation' }, ia), ...stack.slice(1)];
}
default:
throw new MichelsonError(instruction, `unexpected instruction: ${instruction.prim}`);
}
})(instruction);
if ((ctx === null || ctx === void 0 ? void 0 : ctx.traceCallback) !== undefined) {
const trace = {
op: instruction,
in: stack,
out: retStack,
};
ctx.traceCallback(trace);
}
return retStack;
}
function contractSection(contract, section) {
for (const s of contract) {
if (s.prim === section) {
return s;
}
}
throw new MichelsonError(contract, `missing contract section: ${section}`);
}
function contractViews(contract) {
const views = {};
for (const s of contract) {
if (s.prim === 'view') {
views[s.args[0].string] = s;
}
}
return views;
}
function isContract(v) {
if (Array.isArray(v)) {
for (const s of v) {
if ('prim' in s && (s.prim === 'parameter' || s.prim === 'storage' || s.prim === 'code')) {
return true;
}
}
}
return false;
}
function contractEntryPoint(src, ep) {
ep = ep || '%default';
const entryPoint = contractEntryPoints(src).find((x) => x[0] === ep);
if (entryPoint !== undefined) {
return entryPoint[1];
}
else if (ep === '%default') {
return isContract(src) ? contractSection(src, 'parameter').args[0] : src;
}
return null;
}
function isOrType(t) {
return Array.isArray(t) || t.prim === 'or';
}
function contractEntryPoints(src) {
if (isContract(src)) {
const param = contractSection(src, 'parameter');
const ch = contractEntryPoints(param.args[0]);
const a = unpackAnnotations(param);
return a.f ? [[a.f[0], param.args[0]], ...ch] : ch;
}
if (isOrType(src)) {
const args = typeArgs(src);
const getArg = (n) => {
const a = unpackAnnotations(args[n]);
if (typeID(args[n]) === 'or') {
const ch = contractEntryPoints(args[n]);
return a.f ? [[a.f[0], args[n]], ...ch] : ch;
}
return a.f ? [[a.f[0], args[n]]] : [];
};
return [...getArg(0), ...getArg(1)];
}
return [];
}
// Contract validation
function assertContractValid(contract, ctx) {
const assertSection = (parameter, storage, ret, code) => {
assertTypeAnnotationsValid(parameter, true);
assertTypeAnnotationsValid(storage);
const arg = {
prim: 'pair',
args: [
Object.assign(Object.assign({}, parameter), { annots: ['@parameter'] }),
Object.assign(Object.assign({}, storage), { annots: ['@storage'] }),
],
};
const out = functionTypeInternal(code, [arg], Object.assign(Object.assign({}, ctx), { contract }));
if ('failed' in out) {
return out;
}
try {
assertStacksEqual(out, [ret]);
}
catch (err) {
if (err instanceof MichelsonError) {
throw new MichelsonInstructionError(code, out, err.message);
}
else {
throw err;
}
}
return out;
};
const parameter = contractSection(contract, 'parameter').args[0];
const storage = contractSection(contract, 'storage').args[0];
const code = contractSection(contract, 'code').args[0];
const expected = {
prim: 'pair',
args: [{ prim: 'list', args: [{ prim: 'operation' }] }, storage],
};
const ret = assertSection(parameter, storage, expected, code);
for (const view of Object.values(contractViews(contract))) {
assertSection(view.args[1], storage, view.args[2], view.args[3]);
}
return ret;
}
// Exported wrapper functions
function assertDataValid(d, t, ctx) {
assertTypeAnnotationsValid(t);
assertDataValidInternal(d, t, ctx || null);
}
function functionType(inst, stack, ctx) {
for (const t of stack) {
assertTypeAnnotationsValid(t);
}
if ((ctx === null || ctx === void 0 ? void 0 : ctx.contract) !== undefined) {
for (const typesec of ['parameter', 'storage']) {
const sec = contractSection(ctx.contract, typesec).args[0];
assertTypeAnnotationsValid(sec);
}
}
return functionTypeInternal(inst, stack, ctx || null);
}
function assertTypesEqual(a, b, field = false) {
if (Array.isArray(a)) {
// type guards don't work for parametrized generic types
for (const v of a) {
assertTypeAnnotationsValid(v);
}
for (const v of b) {
assertTypeAnnotationsValid(v);
}
}
else {
assertTypeAnnotationsValid(a);
assertTypeAnnotationsValid(b);
}
assertScalarTypesEqual(a, b, field);
}
function isTypeAnnotationsValid(t, field = false) {
try {
assertTypeAnnotationsValid(t, field);
return true;
}
catch (_a) {
return false;
}
}
function isContractValid(contract, ctx) {
try {
return assertContractValid(contract, ctx);
}
catch (_a) {
return null;
}
}
function isDataValid(d, t, ctx) {
try {
assertDataValid(d, t, ctx);
return true;
}
catch (_a) {
return false;
}
}
function isTypeEqual(a, b, field = false) {
try {
assertTypesEqual(a, b, field);
return true;
}
catch (_a) {
return false;
}
}
class Contract {
constructor(contract, opt) {
this.contract = contract;
this.ctx = Object.assign({ contract }, opt);
this.output = assertContractValid(contract, this.ctx);
}
static parse(src, opt) {
const p = new Parser(opt);
const expr = typeof src === 'string' ? p.parseScript(src) : p.parseJSON(src);
if (expr === null) {
throw new InvalidMichelsonError('empty Michelson');
}
if (assertMichelsonContract(expr)) {
return new Contract(expr, opt);
}
}
static parseTypeExpression(src, opt) {
const p = new Parser(opt);
const expr = typeof src === 'string' ? p.parseScript(src) : p.parseJSON(src);
if (expr === null) {
throw new InvalidTypeExpressionError('empty type expression');
}
// remove assertTypeAnnotationsValid from if block because: () => void || throw error
if (assertMichelsonType(expr)) {
assertTypeAnnotationsValid(expr);
return expr;
}
}
static parseDataExpression(src, opt) {
const p = new Parser(opt);
const expr = typeof src === 'string' ? p.parseScript(src) : p.parseJSON(src);
if (expr === null) {
throw new InvalidDataExpressionError('empty data expression');
}
if (assertMichelsonData(expr)) {
return expr;
}
throw undefined;
}
section(section) {
return contractSection(this.contract, section);
}
entryPoints() {
return contractEntryPoints(this.contract);
}
entryPoint(ep) {
return contractEntryPoint(this.contract, ep);
}
assertDataValid(d, t) {
assertDataValid(d, t, this.ctx);
}
isDataValid(d, t) {
return isDataValid(d, t, this.ctx);
}
assertParameterValid(ep, d) {
const t = this.entryPoint(ep || undefined);
if (t === null) {
throw new InvalidEntrypointError(ep === null || ep === void 0 ? void 0 : ep.toString());
}
this.assertDataValid(d, t);
}
isParameterValid(ep, d) {
try {
this.assertParameterValid(ep, d);
return true;
}
catch (_a) {
return false;
}
}
functionType(inst, stack) {
return functionType(inst, stack, this.ctx);
}
}
// TODO: dummyContract not used anywhere in the codebase can be deleted?
const dummyContract = new Contract([
{ prim: 'parameter', args: [{ prim: 'unit' }] },
{ prim: 'storage', args: [{ prim: 'unit' }] },
{
prim: 'code',
args: [[{ prim: 'CAR' }, { prim: 'NIL', args: [{ prim: 'operation' }] }, { prim: 'PAIR' }]],
},
]);
function formatStack(s) {
if ('failed' in s) {
return `[FAILED: ${emitMicheline(s.failed)}]`;
}
return s
.map((v, i) => {
const ann = unpackAnnotations(v);
return `[${i}${ann.v ? '/' + ann.v[0] : ''}]: ${emitMicheline(v)}`;
})
.join('\n');
}
function traceDumpFunc(blocks, cb) {
return (v) => {
var _a;
if (Array.isArray(v) && !blocks) {
return;
}
const macro = (_a = v.op[sourceReference]) === null || _a === void 0 ? void 0 : _a.macro;
const msg = `${macro ? 'Macro' : 'Op'}: ${macro ? emitMicheline(macro, undefined, true) + ' / ' : ''}${emitMicheline(v.op)}
Input:
${formatStack(v.in)}
Output:
${formatStack(v.out)}
`;
cb(msg);
};
}
function formatError(err) {
var _a;
if (err instanceof MichelsonInstructionError) {
const macro = (_a = err.val[sourceReference]) === null || _a === void 0 ? void 0 : _a.macro;
return `${macro ? 'Macro' : 'Op'}: ${macro ? emitMicheline(macro, undefined, true) + ' / ' : ''}${emitMicheline(err.val)}
Stack:
${formatStack(err.stackState)}
`;
}
else if (err instanceof MichelsonTypeError) {
const type = Array.isArray(err.val)
? '[' + err.val.map((v, i) => `[${i}]: ${emitMicheline(v)}`).join('; ') + ']'
: emitMicheline(err.val);
return `Type: ${type}
${err.data
? `Data: ${emitMicheline(err.data)}
`
: ''}
`;
}
else {
return `Value: ${emitMicheline(err.val)}`;
}
}
// IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT OR CHECKIN!
const VERSION = {
commitHash: '45fea4a361f29598063e448574800220c4687001',
version: '20.0.0',
};
exports.Contract = Contract;
exports.DefaultProtocol = DefaultProtocol;
exports.JSONParseError = JSONParseError;
exports.MacroError = MacroError;
exports.MichelineParseError = MichelineParseError;
exports.MichelsonError = MichelsonError;
exports.MichelsonInstructionError = MichelsonInstructionError;
exports.MichelsonTypeError = MichelsonTypeError;
exports.MichelsonValidationError = MichelsonValidationError;
exports.Parser = Parser;
exports.ProtoGreaterOrEqual = ProtoGreaterOrEqual;
exports.ProtoInferiorTo = ProtoInferiorTo;
exports.VERSION = VERSION;
exports.assertContractValid = assertContractValid;
exports.assertDataListIfAny = assertDataListIfAny;
exports.assertDataValid = assertDataValid;
exports.assertMichelsonBigMapStorableType = assertMichelsonBigMapStorableType;
exports.assertMichelsonComparableType = assertMichelsonComparableType;
exports.assertMichelsonContract = assertMichelsonContract;
exports.assertMichelsonData = assertMichelsonData;
exports.assertMichelsonInstruction = assertMichelsonInstruction;
exports.assertMichelsonPackableType = assertMichelsonPackableType;
exports.assertMichelsonPassableType = assertMichelsonPassableType;
exports.assertMichelsonPushableType = assertMichelsonPushableType;
exports.assertMichelsonStorableType = assertMichelsonStorableType;
exports.assertMichelsonType = assertMichelsonType;
exports.assertTypeAnnotationsValid = assertTypeAnnotationsValid;
exports.assertTypesEqual = assertTypesEqual;
exports.assertViewNameValid = assertViewNameValid;
exports.contractEntryPoint = contractEntryPoint;
exports.contractEntryPoints = contractEntryPoints;
exports.contractSection = contractSection;
exports.contractViews = contractViews;
exports.decodeAddressBytes = decodeAddressBytes;
exports.decodePublicKeyBytes = decodePublicKeyBytes;
exports.decodePublicKeyHashBytes = decodePublicKeyHashBytes;
exports.dummyContract = dummyContract;
exports.emitMicheline = emitMicheline;
exports.formatError = formatError;
exports.formatStack = formatStack;
exports.functionType = functionType;
exports.instructionIDs = instructionIDs;
exports.isContractValid = isContractValid;
exports.isDataValid = isDataValid;
exports.isInstruction = isInstruction;
exports.isMichelsonCode = isMichelsonCode;
exports.isMichelsonData = isMichelsonData;
exports.isMichelsonError = isMichelsonError;
exports.isMichelsonScript = isMichelsonScript;
exports.isMichelsonType = isMichelsonType;
exports.isTypeAnnotationsValid = isTypeAnnotationsValid;
exports.isTypeEqual = isTypeEqual;
exports.packData = packData;
exports.packDataBytes = packDataBytes;
exports.refContract = refContract;
exports.sourceReference = sourceReference;
exports.traceDumpFunc = traceDumpFunc;
exports.unpackData = unpackData;
exports.unpackDataBytes = unpackDataBytes;
}));
//# sourceMappingURL=taquito-michel-codec.umd.js.map