UNPKG

@mavrykdynamics/taquito-michel-codec

Version:

Michelson parser/validator/formatter

1,087 lines 78.9 kB
"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