@mavrykdynamics/taquito-michel-codec
Version:
Michelson parser/validator/formatter
1,087 lines • 78.9 kB
JavaScript
"use strict";
var __rest = (this && this.__rest) || function (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;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTypeEqual = exports.isDataValid = exports.isContractValid = exports.isTypeAnnotationsValid = exports.assertTypesEqual = exports.functionType = exports.assertDataValid = exports.assertContractValid = exports.contractEntryPoints = exports.contractEntryPoint = exports.contractViews = exports.contractSection = exports.assertTypeAnnotationsValid = exports.MichelsonInstructionError = void 0;
const michelson_types_1 = require("./michelson-types");
const utils_1 = require("./utils");
const base58_1 = require("./base58");
const binary_1 = require("./binary");
const michelson_validator_1 = require("./michelson-validator");
class MichelsonInstructionError extends utils_1.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';
}
}
exports.MichelsonInstructionError = 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 utils_1.MichelsonTypeError(a, `types mismatch: ${typeID(a)} != ${typeID(b)}`, undefined);
}
const ann = [(0, utils_1.unpackAnnotations)(a), (0, utils_1.unpackAnnotations)(b)];
if (ann[0].t && ann[1].t && ann[0].t[0] !== ann[1].t[0]) {
throw new utils_1.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 utils_1.MichelsonTypeError(a, `${typeID(a)}: field names mismatch: ${ann[0].f[0]} != ${ann[1].f}`, undefined);
}
if ((0, utils_1.isPairType)(a)) {
const aArgs = (0, utils_1.unpackComb)('pair', a);
const bArgs = (0, utils_1.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 utils_1.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 utils_1.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 = (0, utils_1.unpackAnnotations)(t);
if ((((_a = ann.t) === null || _a === void 0 ? void 0 : _a.length) || 0) > 1) {
throw new utils_1.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 utils_1.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 utils_1.MichelsonTypeError(t, `${t.prim}: field annotations aren't allowed: ${t.annots}`, undefined);
}
}
}
if ((0, utils_1.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]);
}
}
exports.assertTypeAnnotationsValid = assertTypeAnnotationsValid;
// Data integrity check
function _compareMichelsonData(t, a, b) {
if ((0, utils_1.isPairType)(t)) {
if ((0, utils_1.isPairData)(a) && (0, utils_1.isPairData)(b)) {
(0, michelson_validator_1.assertDataListIfAny)(a);
(0, michelson_validator_1.assertDataListIfAny)(b);
const tComb = (0, utils_1.unpackComb)('pair', t);
const aComb = (0, utils_1.unpackComb)('Pair', a);
const bComb = (0, utils_1.unpackComb)('Pair', b);
const x = _compareMichelsonData(tComb.args[0], aComb.args[0], bComb.args[0]);
if (x !== 0) {
return x;
}
return _compareMichelsonData(tComb.args[0], aComb.args[1], bComb.args[1]);
}
}
else {
switch (t.prim) {
case 'int':
case 'nat':
case 'mumav':
if ('int' in a && 'int' in b) {
return new utils_1.LongInteger(a.int).cmp(new utils_1.LongInteger(b.int));
}
break;
case 'string':
if ('string' in a && 'string' in b) {
const x = a.string.localeCompare(b.string);
return x < 0 ? -1 : x > 0 ? 1 : 0;
}
break;
case 'bytes':
if ('bytes' in a && 'bytes' in b) {
const aa = (0, utils_1.parseBytes)(a.bytes);
const bb = (0, utils_1.parseBytes)(b.bytes);
if (aa !== null && bb !== null) {
return (0, utils_1.compareBytes)(aa, bb);
}
}
break;
case 'bool':
if ('prim' in a &&
'prim' in b &&
(a.prim === 'True' || a.prim === 'False') &&
(b.prim === 'True' || b.prim === 'False')) {
return a.prim === b.prim ? 0 : a.prim === 'False' ? -1 : 1;
}
break;
case 'key':
case 'key_hash':
case 'address':
case 'signature':
case 'chain_id':
if (('string' in a || 'bytes' in a) && ('string' in b || 'bytes' in b)) {
return (0, utils_1.compareBytes)('string' in a ? (0, base58_1.decodeBase58Check)(a.string) : (0, utils_1.parseBytes)(a.bytes) || [], 'string' in b ? (0, base58_1.decodeBase58Check)(b.string) : (0, utils_1.parseBytes)(b.bytes) || []);
}
break;
case 'timestamp':
if (('string' in a || 'int' in a) && ('string' in b || 'int' in b)) {
const aa = (0, utils_1.parseDate)(a);
const bb = (0, utils_1.parseDate)(b);
if (aa !== null && bb !== null) {
const x = aa.valueOf() - bb.valueOf();
return x < 0 ? -1 : x > 0 ? 1 : 0;
}
}
break;
case 'unit':
if ('prim' in a && 'prim' in b && a.prim === 'Unit' && b.prim === 'Unit') {
return 0;
}
}
}
// Unlikely, types are expected to be verified before the function call
throw new utils_1.MichelsonTypeError(t, `${typeID(t)}: not comparable values: ${JSON.stringify(a)}, ${JSON.stringify(b)}`, undefined);
}
// 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 && (0, michelson_validator_1.isInstruction)(v)))) {
return false;
}
}
return true;
}
function assertDataValidInternal(d, t, ctx) {
if ((0, utils_1.isPairType)(t)) {
if ((0, utils_1.isPairData)(d)) {
(0, michelson_validator_1.assertDataListIfAny)(d);
const dc = (0, utils_1.unpackComb)('Pair', d);
const tc = (0, utils_1.unpackComb)('pair', t);
assertDataValidInternal(dc.args[0], tc.args[0], ctx);
assertDataValidInternal(dc.args[1], tc.args[1], ctx);
return;
}
throw new utils_1.MichelsonTypeError(t, `pair expected: ${JSON.stringify(d)}`, d);
}
switch (t.prim) {
// Atomic literals
case 'int':
if ('int' in d && (0, utils_1.isDecimal)(d.int)) {
return;
}
throw new utils_1.MichelsonTypeError(t, `integer value expected: ${JSON.stringify(d)}`, d);
case 'nat':
case 'mumav':
if ('int' in d && (0, utils_1.isNatural)(d.int)) {
return;
}
throw new utils_1.MichelsonTypeError(t, `natural value expected: ${JSON.stringify(d)}`, d);
case 'string':
if ('string' in d) {
return;
}
throw new utils_1.MichelsonTypeError(t, `string value expected: ${JSON.stringify(d)}`, d);
case 'bytes':
case 'bls12_381_g1':
case 'bls12_381_g2':
if ('bytes' in d && (0, utils_1.parseBytes)(d.bytes) !== null) {
return;
}
throw new utils_1.MichelsonTypeError(t, `bytes value expected: ${JSON.stringify(d)}`, d);
case 'bool':
if ('prim' in d && (d.prim === 'True' || d.prim === 'False')) {
return;
}
throw new utils_1.MichelsonTypeError(t, `boolean value expected: ${JSON.stringify(d)}`, d);
case 'key_hash':
if ('string' in d &&
(0, utils_1.checkDecodeMavrykID)(d.string, 'ED25519PublicKeyHash', 'SECP256K1PublicKeyHash', 'P256PublicKeyHash') !== null) {
return;
}
else if ('bytes' in d) {
try {
(0, binary_1.decodePublicKeyHashBytes)(d);
return;
}
catch (err) {
// ignore message
}
}
throw new utils_1.MichelsonTypeError(t, `key hash expected: ${JSON.stringify(d)}`, d);
case 'timestamp':
if (('string' in d || 'int' in d) && (0, utils_1.parseDate)(d) !== null) {
return;
}
throw new utils_1.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 ((0, utils_1.checkDecodeMavrykID)(address, 'ED25519PublicKeyHash', 'SECP256K1PublicKeyHash', 'P256PublicKeyHash', 'ContractHash', 'RollupAddress') !== null) {
return;
}
}
else if ('bytes' in d) {
try {
(0, binary_1.decodeAddressBytes)(d);
return;
}
catch (err) {
// ignore message
}
}
throw new utils_1.MichelsonTypeError(t, `address expected: ${JSON.stringify(d)}`, d);
case 'key':
if ('string' in d &&
(0, utils_1.checkDecodeMavrykID)(d.string, 'ED25519PublicKey', 'SECP256K1PublicKey', 'P256PublicKey') !==
null) {
return;
}
else if ('bytes' in d) {
try {
(0, binary_1.decodePublicKeyBytes)(d);
return;
}
catch (err) {
// ignore message
}
}
throw new utils_1.MichelsonTypeError(t, `public key expected: ${JSON.stringify(d)}`, d);
case 'unit':
if ('prim' in d && d.prim === 'Unit') {
return;
}
throw new utils_1.MichelsonTypeError(t, `unit value expected: ${JSON.stringify(d)}`, d);
case 'signature':
if ('bytes' in d ||
('string' in d &&
(0, utils_1.checkDecodeMavrykID)(d.string, 'ED25519Signature', 'SECP256K1Signature', 'P256Signature', 'GenericSignature') !== null)) {
return;
}
throw new utils_1.MichelsonTypeError(t, `signature expected: ${JSON.stringify(d)}`, d);
case 'chain_id':
if ('bytes' in d || 'string' in d) {
const x = 'string' in d ? (0, base58_1.decodeBase58Check)(d.string) : (0, utils_1.parseBytes)(d.bytes);
if (x !== null) {
return;
}
}
throw new utils_1.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 utils_1.MichelsonTypeError(t, `option expected: ${JSON.stringify(d)}`, d);
case 'list':
case 'set':
if ((0, michelson_validator_1.assertDataListIfAny)(d)) {
//let prev: MichelsonData | undefined;
for (const v of d) {
assertDataValidInternal(v, t.args[0], ctx);
}
return;
}
throw new utils_1.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 utils_1.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 utils_1.MichelsonTypeError(t, `function is failed with error type: ${ret.failed}`, d);
}
if (ret.length !== 1) {
throw new utils_1.MichelsonTypeError(t, 'function must return a value', d);
}
assertScalarTypesEqual(t.args[1], ret[0]);
return;
}
throw new utils_1.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 utils_1.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 utils_1.MichelsonTypeError(t, `${t.prim} expected: ${JSON.stringify(d)}`, d);
case 'bls12_381_fr':
if (('int' in d && (0, utils_1.isDecimal)(d.int)) || ('bytes' in d && (0, utils_1.parseBytes)(d.bytes) !== null)) {
return;
}
throw new utils_1.MichelsonTypeError(t, `BLS12-381 element expected: ${JSON.stringify(d)}`, d);
case 'sapling_state':
if (Array.isArray(d)) {
return;
}
throw new utils_1.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 ((0, utils_1.isPairData)(d)) {
// backward compatibility
assertDataValidInternal(d, {
prim: 'pair',
args: [{ prim: 'address' }, t.args[0], { prim: 'nat' }],
}, ctx);
return;
}
throw new utils_1.MichelsonTypeError(t, `ticket expected: ${JSON.stringify(d)}`, d);
default:
throw new utils_1.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) || michelson_types_1.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 utils_1.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 utils_1.MichelsonError) {
throw new MichelsonInstructionError(instruction, stack, err.message);
}
else {
throw err;
}
}
};
}
const argAnn = rethrow(utils_1.unpackAnnotations);
const ensureStacksEqual = rethrow(assertStacksEqual);
const ensureTypesEqual = rethrow(assertScalarTypesEqual);
const ensureComparableType = rethrowTypeGuard(michelson_validator_1.assertMichelsonComparableType);
const ensurePackableType = rethrowTypeGuard(michelson_validator_1.assertMichelsonPackableType);
const ensureStorableType = rethrowTypeGuard(michelson_validator_1.assertMichelsonStorableType);
const ensurePushableType = rethrowTypeGuard(michelson_validator_1.assertMichelsonPushableType);
const ensureBigMapStorableType = rethrowTypeGuard(michelson_validator_1.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 { annots: _annots } = t, 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 = (0, utils_1.unpackComb)('pair', src);
if (i === 1) {
return [p.args[0]];
}
else if (i === 2) {
return p.args;
}
const right = p.args[1];
if ((0, utils_1.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 = (0, utils_1.unpackComb)('pair', src);
if (i === 1) {
return p.args[0];
}
const right = p.args[1];
if ((0, utils_1.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 = (0, utils_1.unpackComb)('pair', src);
if (i === 1) {
return Object.assign(Object.assign({}, p), { args: [x, p.args[1]] });
}
const right = p.args[1];
if ((0, utils_1.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 = (0, utils_1.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 (!(0, utils_1.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 (!(0, michelson_types_1.ProtoInferiorTo)(proto, michelson_types_1.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 = (0, michelson_types_1.ProtoInferiorTo)(proto, michelson_types_1.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': {
const _s = 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