@taquito/michelson-encoder
Version:
converts michelson data and types into convenient JS/TS objects
1,431 lines (1,420 loc) • 142 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fast-json-stable-stringify'), require('@taquito/core'), require('bignumber.js'), require('@taquito/utils')) :
typeof define === 'function' && define.amd ? define(['exports', 'fast-json-stable-stringify', '@taquito/core', 'bignumber.js', '@taquito/utils'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.taquitoMichelsonEncoder = {}, global.stringify, global.core, global.BigNumber, global.utils));
})(this, (function (exports, stringify, core, BigNumber, utils) { 'use strict';
var _a$1;
/**
* @category Error
* @description Error that indicates an invalid map type being passed or used
*/
class InvalidMapTypeError extends core.TaquitoError {
constructor(mapType, reason) {
super();
this.mapType = mapType;
this.reason = reason;
this.message = `The map type '${JSON.stringify(mapType)}' is invalid. Reason: ${reason}.`;
this.name = 'InvalidMapTypeError';
}
}
// Retrieve a unique symbol associated with the key from the environment
// Used in order to identify all object that are of type MichelsonMap even if they come from different module
const michelsonMapTypeSymbol = Symbol.for('taquito-michelson-map-type-symbol');
/**
*
* @throws {@link InvalidMapTypeError} when the argument passed to mapType is not a valid map type
*/
function validateMapType(value) {
if (!('prim' in value)) {
throw new InvalidMapTypeError(value, `Missing 'prim' field`);
}
if (!['map', 'big_map'].includes(value.prim)) {
throw new InvalidMapTypeError(value, `The prim field should be 'map' or 'big_map'`);
}
if (!('args' in value)) {
throw new InvalidMapTypeError(value, `Missing 'args' field`);
}
if (!Array.isArray(value.args)) {
throw new InvalidMapTypeError(value, `The 'args' field should be an array`);
}
if (value.args.length !== 2) {
throw new InvalidMapTypeError(value, `The 'args' field should have 2 elements`);
}
}
/**
* @category Error
* @description Error that indicates a map type mismatch, where an attempt to set a key or value in a Map doesn't match the defined type of the Map
*/
class MapTypecheckError extends core.TaquitoError {
constructor(value, type, objectType, reason) {
super();
this.value = value;
this.type = type;
this.reason = reason;
this.name = 'MapTypecheckError';
this.message = `The ${objectType} provided: ${JSON.stringify(value)} is not compatible with the expected michelson type: ${JSON.stringify(type)}. Reason: ${JSON.stringify(reason)}.`;
this.name = 'MapTypecheckError';
}
}
/**
* @description Michelson Map is an abstraction over the michelson native map. It supports complex Pair as key
*/
class MichelsonMap {
// Used to check if an object is a michelson map.
// Using instanceof was not working for project that had multiple instance of taquito dependencies
// as the class constructor is different
static isMichelsonMap(obj) {
return obj && obj[michelsonMapTypeSymbol] === true;
}
/**
* @param mapType If specified key and value will be type-checked before being added to the map
*
* @example new MichelsonMap({ prim: "map", args: [{prim: "string"}, {prim: "int"}]})
*/
constructor(mapType) {
this.valueMap = new Map();
this.keyMap = new Map();
this[_a$1] = true;
if (mapType) {
this.setType(mapType);
}
}
setType(mapType) {
validateMapType(mapType);
this.keySchema = new Schema(mapType.args[0]);
this.valueSchema = new Schema(mapType.args[1]);
}
removeType() {
this.keySchema = undefined;
this.valueSchema = undefined;
}
static fromLiteral(obj, mapType) {
const map = new MichelsonMap(mapType);
Object.keys(obj).forEach((key) => {
map.set(key, obj[key]);
});
return map;
}
typecheckKey(key) {
if (!this.keySchema) {
return;
}
this.keySchema.Typecheck(key);
}
typecheckValue(value) {
if (!this.valueSchema) {
return;
}
this.valueSchema.Typecheck(value);
}
/**
* @throws {@link MapTypecheckError} when the argument passed does not match the expected schema for value
*/
assertTypecheckValue(value) {
try {
this.typecheckValue(value);
}
catch (e) {
throw new MapTypecheckError(value, this.valueSchema, 'value', e);
}
}
/**
* @throws {@link MapTypecheckError} when the argument passed does not match the expected schema for key
*/
assertTypecheckKey(key) {
try {
this.typecheckKey(key);
}
catch (e) {
throw new MapTypecheckError(key, this.keySchema, 'key', e);
}
}
serializeDeterministically(key) {
return stringify(key);
}
*keys() {
for (const [key] of this.entries()) {
yield key;
}
}
*values() {
for (const [, value] of this.entries()) {
yield value;
}
}
*entries() {
for (const key of this.valueMap.keys()) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
yield [this.keyMap.get(key), this.valueMap.get(key)];
}
}
get(key) {
this.assertTypecheckKey(key);
const strKey = this.serializeDeterministically(key);
return this.valueMap.get(strKey);
}
/**
*
* @description Set a key and a value in the MichelsonMap. If the key already exists, override the current value.
*
* @example map.set("myKey", "myValue") // Using a string as key
*
* @example map.set({0: "test", 1: "test1"}, "myValue") // Using a pair as key
*
* @warn The same key can be represented in multiple ways, depending on the type of the key. This duplicate key situation will cause a runtime error (duplicate key) when sending the map data to the Tezos RPC node.
*
* For example, consider a contract with a map whose key is of type boolean. If you set the following values in MichelsonMap: map.set(false, "myValue") and map.set(null, "myValue").
*
* You will get two unique entries in the MichelsonMap. These values will both be evaluated as falsy by the MichelsonEncoder and ultimately rejected by the Tezos RPC.
*/
set(key, value) {
this.assertTypecheckKey(key);
this.assertTypecheckValue(value);
const strKey = this.serializeDeterministically(key);
this.keyMap.set(strKey, key);
this.valueMap.set(strKey, value);
}
delete(key) {
this.assertTypecheckKey(key);
this.keyMap.delete(this.serializeDeterministically(key));
this.valueMap.delete(this.serializeDeterministically(key));
}
has(key) {
this.assertTypecheckKey(key);
const strKey = this.serializeDeterministically(key);
return this.keyMap.has(strKey) && this.valueMap.has(strKey);
}
clear() {
this.keyMap.clear();
this.valueMap.clear();
}
get size() {
return this.keyMap.size;
}
forEach(cb) {
for (const [key, value] of this.entries()) {
cb(value, key, this);
}
}
}
_a$1 = michelsonMapTypeSymbol;
/**
* @category Error
* @description Error that indicates a failure when encoding invalid or incorrect data (e.g. if an address is expected but a number is received)
*/
class TokenValidationError extends core.TaquitoError {
constructor(value, token, baseMessage) {
super();
this.value = value;
this.token = token;
this.name = 'TokenValidationError';
const annot = this.token.annot();
const annotText = annot ? `[${annot}] ` : '';
this.message = `${annotText}${baseMessage}`;
}
}
class Token {
/**
* @description Gets the strategy used for field numbering in Token execute/encode/decode to convert Michelson values to/from javascript objects, returns a value of type {@link FieldNumberingStrategy} that controls how field numbers are calculated
*/
static get fieldNumberingStrategy() {
return Token._fieldNumberingStrategy;
}
/**
* @description Sets the strategy used for field numbering in Token execute/encode/decode to convert Michelson values to/from javascript objects, accepts a value of type {@link FieldNumberingStrategy} that controls how field numbers are calculated
*/
static set fieldNumberingStrategy(value) {
Token._fieldNumberingStrategy = value;
}
constructor(val, idx, fac, parentTokenType) {
this.val = val;
this.idx = idx;
this.fac = fac;
this.parentTokenType = parentTokenType;
this.createToken = this.fac;
}
typeWithoutAnnotations() {
const handleMichelsonExpression = (val) => {
if (typeof val === 'object') {
if (Array.isArray(val)) {
const array = val;
return array.map((item) => handleMichelsonExpression(item));
}
const extended = val;
if (extended.args) {
return {
prim: extended.prim,
args: extended.args.map((x) => handleMichelsonExpression(x)),
};
}
else {
return {
prim: extended.prim,
};
}
}
return val;
};
const handleMichelsonExtended = (val) => {
if (val.args) {
return {
prim: val.prim,
args: val.args.map((x) => handleMichelsonExpression(x)),
};
}
else {
return {
prim: val.prim,
};
}
};
return handleMichelsonExtended(this.val);
}
annot() {
return (Array.isArray(this.val.annots) && this.val.annots.length > 0
? this.val.annots[0]
: String(this.idx)).replace(/(%|:)(_Liq_entry_)?/, '');
}
hasAnnotations() {
return Array.isArray(this.val.annots) && this.val.annots.length;
}
get tokenVal() {
return this.val;
}
ExtractSignature() {
return [[this.ExtractSchema()]];
}
}
Token._fieldNumberingStrategy = 'Latest';
class ComparableToken extends Token {
compare(o1, o2) {
if (o1 === o2) {
return 0;
}
return o1 < o2 ? -1 : 1;
}
}
/**
* @category Error
* @description Error that indicates a failure happening when parsing encoding/executing Big Map types
*/
class BigMapValidationError extends TokenValidationError {
constructor(value, token, message) {
super(value, token, message);
this.value = value;
this.token = token;
this.name = 'BigMapValidationError';
}
}
class BigMapToken extends Token {
constructor(val, idx, fac) {
super(val, idx, fac);
this.val = val;
this.idx = idx;
this.fac = fac;
}
get ValueSchema() {
return this.createToken(this.val.args[1], 0);
}
get KeySchema() {
return this.createToken(this.val.args[0], 0);
}
/**
* @deprecated ExtractSchema has been deprecated in favor of generateSchema
*
*/
ExtractSchema() {
return {
big_map: {
key: this.KeySchema.ExtractSchema(),
value: this.ValueSchema.ExtractSchema(),
},
};
}
generateSchema() {
return {
__michelsonType: BigMapToken.prim,
schema: {
key: this.KeySchema.generateSchema(),
value: this.ValueSchema.generateSchema(),
},
};
}
/**
* @throws {@link BigMapValidationError}
*/
validate(value) {
if (!MichelsonMap.isMichelsonMap(value)) {
throw new BigMapValidationError(value, this, `Value ${JSON.stringify(value)} is not a MichelsonMap`);
}
}
objLitToMichelsonMap(val) {
if (val instanceof MichelsonMap)
return val;
if (typeof val === 'object') {
if (Object.keys(val).length === 0) {
return new MichelsonMap();
}
else {
return MichelsonMap.fromLiteral(val);
}
}
return val;
}
/**
* @throws {@link BigMapValidationError}
*/
Encode(args) {
const val = this.objLitToMichelsonMap(args.pop());
this.validate(val);
return Array.from(val.keys())
.sort((a, b) => this.KeySchema.compare(a, b))
.map((key) => {
return {
prim: 'Elt',
args: [this.KeySchema.EncodeObject(key), this.ValueSchema.EncodeObject(val.get(key))],
};
});
}
/**
* @throws {@link BigMapValidationError}
*/
EncodeObject(args, semantic) {
const val = this.objLitToMichelsonMap(args);
this.validate(val);
if (semantic && semantic[BigMapToken.prim]) {
return semantic[BigMapToken.prim](val, this.val);
}
return Array.from(val.keys())
.sort((a, b) => this.KeySchema.compare(a, b))
.map((key) => {
return {
prim: 'Elt',
args: [this.KeySchema.EncodeObject(key), this.ValueSchema.EncodeObject(val.get(key))],
};
});
}
/**
* @throws {@link InvalidMapTypeError} when the argument passed to val is an array but not a valid map type
* @throws {@link BigMapValidationError} when the value is invalid
*/
Execute(val, semantic) {
if (semantic && semantic[BigMapToken.prim]) {
return semantic[BigMapToken.prim](val, this.val);
}
if (Array.isArray(val)) {
// Athens is returning an empty array for big map in storage
// Internal: In taquito v5 it is still used to decode big map diff (as if they were a regular map)
const map = new MichelsonMap(this.val);
val.forEach((current) => {
map.set(this.KeySchema.ToKey(current.args[0]), this.ValueSchema.Execute(current.args[1]));
});
return map;
}
else if ('int' in val) {
// Babylon is returning an int with the big map id in contract storage
return val.int;
}
else {
throw new BigMapValidationError(val, this, `Big map is expecting either an array (Athens) or an object with an int property (Babylon). Got ${JSON.stringify(val)}`);
}
}
findAndReturnTokens(tokenToFind, tokens) {
if (BigMapToken.prim === tokenToFind) {
tokens.push(this);
}
this.KeySchema.findAndReturnTokens(tokenToFind, tokens);
this.ValueSchema.findAndReturnTokens(tokenToFind, tokens);
return tokens;
}
}
BigMapToken.prim = 'big_map';
/**
* @category Error
* @description Error that indicates a failure happening when parsing encoding/executing an OrToken
*/
class OrValidationError extends TokenValidationError {
constructor(value, token, message) {
super(value, token, message);
this.value = value;
this.token = token;
this.name = 'OrValidationError';
}
}
class OrToken extends ComparableToken {
constructor(val, idx, fac, parentTokenType) {
super(val, idx, fac, parentTokenType);
this.val = val;
this.idx = idx;
this.fac = fac;
this.parentTokenType = parentTokenType;
}
Encode(args) {
const label = args[args.length - 1];
const leftToken = this.createToken(this.val.args[0], this.getIdxForChildren(), 'Or');
let keyCount = 1;
if (leftToken instanceof OrToken) {
keyCount = Object.keys(leftToken.ExtractSchema()).length;
}
const rightToken = this.createToken(this.val.args[1], this.getIdxForChildren() + keyCount, 'Or');
if (String(leftToken.annot()) === String(label) && !(leftToken instanceof OrToken)) {
args.pop();
return { prim: 'Left', args: [leftToken.Encode(args)] };
}
else if (String(rightToken.annot()) === String(label) && !(rightToken instanceof OrToken)) {
args.pop();
return { prim: 'Right', args: [rightToken.Encode(args)] };
}
else {
if (leftToken instanceof OrToken) {
const val = leftToken.Encode(args);
if (val) {
return { prim: 'Left', args: [val] };
}
}
if (rightToken instanceof OrToken) {
const val = rightToken.Encode(args);
if (val) {
return { prim: 'Right', args: [val] };
}
}
return null;
}
}
ExtractSignature() {
const leftToken = this.createToken(this.val.args[0], this.getIdxForChildren(), 'Or');
let keyCount = 1;
if (leftToken instanceof OrToken) {
keyCount = Object.keys(leftToken.ExtractSchema()).length;
}
const rightToken = this.createToken(this.val.args[1], this.getIdxForChildren() + keyCount, 'Or');
const newSig = [];
if (leftToken instanceof OrToken) {
newSig.push(...leftToken.ExtractSignature());
}
else {
for (const sig of leftToken.ExtractSignature()) {
newSig.push([leftToken.annot(), ...sig]);
}
}
if (rightToken instanceof OrToken) {
newSig.push(...rightToken.ExtractSignature());
}
else {
for (const sig of rightToken.ExtractSignature()) {
newSig.push([rightToken.annot(), ...sig]);
}
}
return newSig;
}
/**
* @throws {@link OrValidationError}
*/
EncodeObject(args, semantic) {
this.validateJavascriptObject(args);
const label = Object.keys(args)[0];
const leftToken = this.createToken(this.val.args[0], this.getIdxForChildren(), 'Or');
let keyCount = 1;
if (leftToken instanceof OrToken) {
keyCount = Object.keys(leftToken.ExtractSchema()).length;
}
const rightToken = this.createToken(this.val.args[1], this.getIdxForChildren() + keyCount, 'Or');
if (String(leftToken.annot()) === String(label) && !(leftToken instanceof OrToken)) {
return { prim: 'Left', args: [leftToken.EncodeObject(args[label], semantic)] };
}
else if (String(rightToken.annot()) === String(label) && !(rightToken instanceof OrToken)) {
return { prim: 'Right', args: [rightToken.EncodeObject(args[label], semantic)] };
}
else {
if (leftToken instanceof OrToken) {
const val = leftToken.EncodeObject(args, semantic);
if (val) {
return { prim: 'Left', args: [val] };
}
}
if (rightToken instanceof OrToken) {
const val = rightToken.EncodeObject(args, semantic);
if (val) {
return { prim: 'Right', args: [val] };
}
}
return null;
}
}
/**
* @throws {@link OrValidationError}
*/
validateJavascriptObject(args) {
if (typeof args !== 'object' ||
Array.isArray(args) ||
args === null ||
Object.keys(args).length !== 1) {
throw new OrValidationError(args, this, `EncodeObject expects an object with a single key but got: ${JSON.stringify(args)}`);
}
}
/**
* @throws {@link OrValidationError}
*/
Execute(val, semantics) {
const leftToken = this.createToken(this.val.args[0], this.getIdxForChildren(), 'Or');
let keyCount = 1;
if (leftToken instanceof OrToken) {
keyCount = Object.keys(leftToken.ExtractSchema()).length;
}
const rightToken = this.createToken(this.val.args[1], this.getIdxForChildren() + keyCount, 'Or');
if (val.prim === 'Right') {
if (rightToken instanceof OrToken) {
return rightToken.Execute(val.args[0], semantics);
}
else {
return {
[rightToken.annot()]: rightToken.Execute(val.args[0], semantics),
};
}
}
else if (val.prim === 'Left') {
if (leftToken instanceof OrToken) {
return leftToken.Execute(val.args[0], semantics);
}
return {
[leftToken.annot()]: leftToken.Execute(val.args[0], semantics),
};
}
else {
throw new OrValidationError(val, this, `Was expecting Left or Right prim but got: ${JSON.stringify(val.prim)}`);
}
}
traversal(getLeftValue, getRightValue, concat) {
const leftToken = this.createToken(this.val.args[0], this.getIdxForChildren(), 'Or');
let keyCount = 1;
let leftValue;
if (leftToken instanceof OrToken) {
leftValue = getLeftValue(leftToken);
keyCount = Object.keys(leftToken.ExtractSchema()).length;
}
else {
leftValue = { [leftToken.annot()]: getLeftValue(leftToken) };
}
const rightToken = this.createToken(this.val.args[1], this.getIdxForChildren() + keyCount, 'Or');
let rightValue;
if (rightToken instanceof OrToken) {
rightValue = getRightValue(rightToken);
}
else {
rightValue = { [rightToken.annot()]: getRightValue(rightToken) };
}
const res = concat(leftValue, rightValue);
return res;
}
/**
* @deprecated ExtractSchema has been deprecated in favor of generateSchema
*
*/
ExtractSchema() {
return this.traversal((leftToken) => leftToken.ExtractSchema(), (rightToken) => rightToken.ExtractSchema(), (leftValue, rightValue) => (Object.assign(Object.assign({}, leftValue), rightValue)));
}
generateSchema() {
return {
__michelsonType: OrToken.prim,
schema: this.traversal((leftToken) => {
if (leftToken instanceof OrToken) {
return leftToken.generateSchema().schema;
}
else {
return leftToken.generateSchema();
}
}, (rightToken) => {
if (rightToken instanceof OrToken) {
return rightToken.generateSchema().schema;
}
else {
return rightToken.generateSchema();
}
}, (leftValue, rightValue) => (Object.assign(Object.assign({}, leftValue), rightValue))),
};
}
findToken(label) {
const leftToken = this.createToken(this.val.args[0], this.getIdxForChildren(), 'Or');
let keyCount = 1;
if (leftToken instanceof OrToken) {
keyCount = Object.keys(leftToken.ExtractSchema()).length;
}
const rightToken = this.createToken(this.val.args[1], this.getIdxForChildren() + keyCount, 'Or');
if (String(leftToken.annot()) === String(label) &&
!(leftToken instanceof OrToken) &&
leftToken instanceof ComparableToken) {
return leftToken;
}
else if (String(rightToken.annot()) === String(label) &&
!(rightToken instanceof OrToken) &&
rightToken instanceof ComparableToken) {
return rightToken;
}
else {
if (leftToken instanceof OrToken) {
const tok = leftToken.findToken(label);
if (tok) {
return tok;
}
}
if (rightToken instanceof OrToken) {
const tok = rightToken.findToken(label);
if (tok) {
return tok;
}
}
return null;
}
}
compare(val1, val2) {
const labelVal1 = Object.keys(val1)[0];
const labelVal2 = Object.keys(val2)[0];
if (labelVal1 === labelVal2) {
const token = this.findToken(labelVal1);
if (token instanceof ComparableToken) {
return token.compare(val1[labelVal1], val2[labelVal1]);
}
}
else {
const encoded1 = JSON.stringify(this.EncodeObject(val1));
const encoded2 = JSON.stringify(this.EncodeObject(val2));
return encoded1 < encoded2 ? -1 : 1;
}
}
ToKey(val) {
return this.Execute(val);
}
ToBigMapKey(val) {
return {
key: this.EncodeObject(val),
type: this.typeWithoutAnnotations(),
};
}
findAndReturnTokens(tokenToFind, tokens) {
if (OrToken.prim === tokenToFind) {
tokens.push(this);
}
this.traversal((leftToken) => leftToken.findAndReturnTokens(tokenToFind, tokens), (rightToken) => rightToken.findAndReturnTokens(tokenToFind, tokens), (leftValue, rightValue) => (Object.assign(Object.assign({}, leftValue), rightValue)));
return tokens;
}
getIdxForChildren() {
if (Token.fieldNumberingStrategy === 'Legacy') {
return this.idx;
}
return this.parentTokenType === 'Or' ? this.idx : 0;
}
}
OrToken.prim = 'or';
/**
* @category Error
* @description Error that indicates in invalid token argument being passed
*/
class TokenArgumentValidationError extends core.TaquitoError {
constructor(message) {
super(message);
this.message = message;
this.name = 'TokenArgumentValidationError';
}
}
/**
* @category Error
* @description Error that indicates a failure occurring when doing a comparison of tokens
*/
class TokenComparisonError extends core.TaquitoError {
constructor(val1, val2) {
super();
this.val1 = val1;
this.val2 = val2;
this.name = 'TokenComparisonError';
this.message = `Tokens ${JSON.stringify(val1)} and ${JSON.stringify(val2)} are not comparable`;
}
}
// collapse comb pair
/**
* @throws {@link TokenArgumentValidationError}
*/
function collapse$1(val, prim = PairToken.prim) {
if (Array.isArray(val)) {
return collapse$1({
prim: prim,
args: val,
}, prim);
}
if (val.args === undefined) {
throw new TokenArgumentValidationError(`The value ${JSON.stringify(val)} is an invalid PairToken with no arguments, a pair must have two or more arguments.`);
}
if (val.args.length > 2) {
return [
val.args[0],
{
prim: prim,
args: val.args.slice(1),
},
];
}
return [val.args[0], val.args[1]];
}
class PairToken extends ComparableToken {
constructor(val, idx, fac, parentTokenType) {
super(Array.isArray(val)
? {
prim: PairToken.prim,
args: val,
}
: val.prim
? val
: {
prim: PairToken.prim,
args: val,
}, idx, fac, parentTokenType);
}
args() {
// collapse comb pair
return collapse$1(this.val);
}
tokens() {
let cnt = 0;
return this.args().map((a) => {
const tok = this.createToken(a, this.getIdxForChildren() + cnt, 'Pair');
if (tok instanceof PairToken) {
cnt += Object.keys(tok.ExtractSchema()).length;
}
else {
cnt++;
}
return tok;
});
}
Encode(args) {
return {
prim: 'Pair',
args: this.tokens().map((t) => t.Encode(args)),
};
}
ExtractSignature() {
const args = this.args();
const leftToken = this.createToken(args[0], this.getIdxForChildren(), 'Pair');
let keyCount = 1;
if (leftToken instanceof OrToken) {
keyCount = Object.keys(leftToken.ExtractSchema()).length;
}
const rightToken = this.createToken(args[1], this.getIdxForChildren() + keyCount, 'Pair');
const newSig = [];
for (const leftSig of leftToken.ExtractSignature()) {
for (const rightSig of rightToken.ExtractSignature()) {
newSig.push([...leftSig, ...rightSig]);
}
}
return newSig;
}
ToBigMapKey(val) {
return {
key: this.EncodeObject(val),
type: this.typeWithoutAnnotations(),
};
}
ToKey(val) {
return this.Execute(val);
}
EncodeObject(args, semantic) {
const [leftToken, rightToken] = this.tokens();
let leftValue;
if (leftToken instanceof PairToken && !leftToken.hasAnnotations()) {
leftValue = args;
}
else {
leftValue = args[leftToken.annot()];
}
let rightValue;
if (rightToken instanceof PairToken && !rightToken.hasAnnotations()) {
rightValue = args;
}
else {
rightValue = args[rightToken.annot()];
}
return {
prim: 'Pair',
args: [
leftToken.EncodeObject(leftValue, semantic),
rightToken.EncodeObject(rightValue, semantic),
],
};
}
traversal(getLeftValue, getRightValue) {
const args = this.args();
const leftToken = this.createToken(args[0], this.getIdxForChildren(), 'Pair');
let keyCount = 1;
let leftValue;
if (leftToken instanceof PairToken && !leftToken.hasAnnotations()) {
leftValue = getLeftValue(leftToken);
if (leftToken instanceof PairToken) {
keyCount = Object.keys(leftToken.ExtractSchema()).length;
}
}
else {
leftValue = { [leftToken.annot()]: getLeftValue(leftToken) };
}
const rightToken = this.createToken(args[1], this.getIdxForChildren() + keyCount, 'Pair');
let rightValue;
if (rightToken instanceof PairToken && !rightToken.hasAnnotations()) {
rightValue = getRightValue(rightToken);
}
else {
rightValue = { [rightToken.annot()]: getRightValue(rightToken) };
}
const res = Object.assign(Object.assign({}, leftValue), rightValue);
return res;
}
Execute(val, semantics) {
const args = collapse$1(val, 'Pair');
return this.traversal((leftToken) => leftToken.Execute(args[0], semantics), (rightToken) => rightToken.Execute(args[1], semantics));
}
/**
* @deprecated ExtractSchema has been deprecated in favor of generateSchema
*
*/
ExtractSchema() {
return this.traversal((leftToken) => leftToken.ExtractSchema(), (rightToken) => rightToken.ExtractSchema());
}
generateSchema() {
return {
__michelsonType: PairToken.prim,
schema: this.traversal((leftToken) => {
if (leftToken instanceof PairToken && !leftToken.hasAnnotations()) {
return leftToken.generateSchema().schema;
}
else {
return leftToken.generateSchema();
}
}, (rightToken) => {
if (rightToken instanceof PairToken && !rightToken.hasAnnotations()) {
return rightToken.generateSchema().schema;
}
else {
return rightToken.generateSchema();
}
}),
};
}
/**
* @throws {@link TokenComparisonError}
*/
compare(val1, val2) {
const [leftToken, rightToken] = this.tokens();
const getValue = (token, args) => {
if (token instanceof PairToken && !token.hasAnnotations()) {
return args;
}
else {
return args[token.annot()];
}
};
if (leftToken instanceof ComparableToken && rightToken instanceof ComparableToken) {
const result = leftToken.compare(getValue(leftToken, val1), getValue(leftToken, val2));
if (result === 0) {
return rightToken.compare(getValue(rightToken, val1), getValue(rightToken, val2));
}
return result;
}
throw new TokenComparisonError(val1, val2);
}
findAndReturnTokens(tokenToFind, tokens) {
if (PairToken.prim === tokenToFind) {
tokens.push(this);
}
this.tokens().map((t) => t.findAndReturnTokens(tokenToFind, tokens));
return tokens;
}
getIdxForChildren() {
if (Token.fieldNumberingStrategy === 'Legacy') {
return this.idx;
}
return this.parentTokenType === 'Pair' ? this.idx : 0;
}
}
PairToken.prim = 'pair';
/**
* @category Error
* @description Error that indicates a failure happening when parsing encoding/executing Nat
*/
class NatValidationError extends TokenValidationError {
constructor(value, token, message) {
super(value, token, message);
this.value = value;
this.token = token;
this.name = 'NatValidationError';
}
}
class NatToken extends ComparableToken {
constructor(val, idx, fac) {
super(val, idx, fac);
this.val = val;
this.idx = idx;
this.fac = fac;
}
Execute(val) {
return new BigNumber(val[Object.keys(val)[0]]);
}
/**
* @throws {@link NatValidationError}
*/
Encode(args) {
const val = args.pop();
this.validate(val);
return { int: new BigNumber(val).toFixed() };
}
/**
* @throws {@link NatValidationError}
*/
validate(val) {
const bigNumber = new BigNumber(val);
if (bigNumber.isNaN()) {
throw new NatValidationError(val, this, `Value is not a number: ${JSON.stringify(val)}`);
}
if (bigNumber.isNegative()) {
throw new NatValidationError(val, this, `Value cannot be negative: ${JSON.stringify(val)}`);
}
}
/**
* @throws {@link NatValidationError}
*/
EncodeObject(val, semantic) {
this.validate(val);
if (semantic && semantic[NatToken.prim]) {
return semantic[NatToken.prim](val);
}
return { int: new BigNumber(val).toFixed() };
}
/**
* @deprecated ExtractSchema has been deprecated in favor of generateSchema
*
*/
ExtractSchema() {
return NatToken.prim;
}
generateSchema() {
return {
__michelsonType: NatToken.prim,
schema: NatToken.prim,
};
}
ToBigMapKey(val) {
return {
key: { int: String(val) },
type: { prim: NatToken.prim },
};
}
ToKey({ int }) {
return new BigNumber(int);
}
compare(nat1, nat2) {
const o1 = Number(nat1);
const o2 = Number(nat2);
if (o1 === o2) {
return 0;
}
return o1 < o2 ? -1 : 1;
}
findAndReturnTokens(tokenToFind, tokens) {
if (NatToken.prim === tokenToFind) {
tokens.push(this);
}
return tokens;
}
}
NatToken.prim = 'nat';
class StringToken extends ComparableToken {
constructor(val, idx, fac) {
super(val, idx, fac);
this.val = val;
this.idx = idx;
this.fac = fac;
}
Execute(val) {
return val[Object.keys(val)[0]];
}
/**
* @deprecated ExtractSchema has been deprecated in favor of generateSchema
*
*/
ExtractSchema() {
return StringToken.prim;
}
generateSchema() {
return {
__michelsonType: StringToken.prim,
schema: StringToken.prim,
};
}
Encode(args) {
const val = args.pop();
return { string: val };
}
EncodeObject(val, semantic) {
if (semantic && semantic[StringToken.prim]) {
return semantic[StringToken.prim](val);
}
return { string: val };
}
ToKey({ string }) {
return string;
}
ToBigMapKey(val) {
return {
key: { string: val },
type: { prim: StringToken.prim },
};
}
findAndReturnTokens(tokenToFind, tokens) {
if (StringToken.prim === tokenToFind) {
tokens.push(this);
}
return tokens;
}
}
StringToken.prim = 'string';
/**
* @category Error
* @description Error that indicates a failure happening when parsing encoding/executing an Address
*/
class AddressValidationError extends TokenValidationError {
constructor(value, token, message) {
super(value, token, message);
this.value = value;
this.token = token;
this.name = 'AddressValidationError';
}
}
class AddressToken extends ComparableToken {
constructor(val, idx, fac) {
super(val, idx, fac);
this.val = val;
this.idx = idx;
this.fac = fac;
}
ToBigMapKey(val) {
const decoded = utils.b58decode(val);
return {
key: { bytes: decoded },
type: { prim: 'bytes' },
};
}
/**
* @throws {@link AddressValidationError}
*/
validate(value) {
if (utils.validateAddress(value) !== utils.ValidationResult.VALID) {
throw new AddressValidationError(value, this, `Address is not valid: ${JSON.stringify(value)}`);
}
}
/**
* @throws {@link AddressValidationError}
*/
Encode(args) {
const val = args.pop();
this.validate(val);
return { string: val };
}
/**
* @throws {@link AddressValidationError}
*/
EncodeObject(val, semantic) {
this.validate(val);
if (semantic && semantic[AddressToken.prim]) {
return semantic[AddressToken.prim](val);
}
return { string: val };
}
/**
* @throws {@link AddressValidationError}
*/
Execute(val) {
if (val.string) {
return val.string;
}
if (!val.bytes) {
throw new AddressValidationError(val, this, `cannot be missing both string and bytes: ${JSON.stringify(val)}`);
}
return utils.encodeAddress(val.bytes);
}
/**
* @deprecated ExtractSchema has been deprecated in favor of generateSchema
*
*/
ExtractSchema() {
return AddressToken.prim;
}
generateSchema() {
return {
__michelsonType: AddressToken.prim,
schema: AddressToken.prim,
};
}
/**
* @throws {@link AddressValidationError}
*/
ToKey({ bytes, string }) {
if (string) {
return string;
}
if (!bytes) {
throw new AddressValidationError({ bytes, string }, this, `cannot be missing both string and bytes ${JSON.stringify({ string, bytes })}`);
}
return utils.encodeAddress(bytes);
}
compare(address1, address2) {
const isImplicit = (address) => {
return address.startsWith('tz');
};
const implicit1 = isImplicit(address1);
const implicit2 = isImplicit(address2);
if (implicit1 && !implicit2) {
return -1;
}
else if (implicit2 && !implicit1) {
return 1;
}
return super.compare(address1, address2);
}
findAndReturnTokens(tokenToFind, tokens) {
if (AddressToken.prim === tokenToFind) {
tokens.push(this);
}
return tokens;
}
}
AddressToken.prim = 'address';
/**
* @category Error
* @description Error that indicates a failure happening when parsing encoding/executing a Map
*/
class MapValidationError extends TokenValidationError {
constructor(value, token, message) {
super(value, token, message);
this.value = value;
this.token = token;
this.name = 'MapValidationError';
}
}
class MapToken extends Token {
constructor(val, idx, fac) {
super(val, idx, fac);
this.val = val;
this.idx = idx;
this.fac = fac;
}
get ValueSchema() {
return this.createToken(this.val.args[1], 0);
}
get KeySchema() {
return this.createToken(this.val.args[0], 0);
}
/**
* @throws {@link MapValidationError}
*/
validate(value) {
if (!MichelsonMap.isMichelsonMap(value)) {
throw new MapValidationError(value, this, `Value ${JSON.stringify(value)} is not a valid MichelsonMap`);
}
}
Execute(val, semantics) {
const map = new MichelsonMap(this.val);
val.forEach((current) => {
map.set(this.KeySchema.ToKey(current.args[0]), this.ValueSchema.Execute(current.args[1], semantics));
});
return map;
}
objLitToMichelsonMap(val) {
if (val instanceof MichelsonMap)
return val;
if (typeof val === 'object') {
if (Object.keys(val).length === 0) {
return new MichelsonMap();
}
else {
return MichelsonMap.fromLiteral(val);
}
}
return val;
}
/**
* @throws {@link MapValidationError}
*/
Encode(args) {
const val = this.objLitToMichelsonMap(args.pop());
this.validate(val);
return Array.from(val.keys())
.sort((a, b) => this.KeySchema.compare(a, b))
.map((key) => {
return {
prim: 'Elt',
args: [this.KeySchema.EncodeObject(key), this.ValueSchema.EncodeObject(val.get(key))],
};
});
}
/**
* @throws {@link MapValidationError}
*/
EncodeObject(args, semantic) {
const val = this.objLitToMichelsonMap(args);
this.validate(val);
if (semantic && semantic[MapToken.prim]) {
return semantic[MapToken.prim](val);
}
return Array.from(val.keys())
.sort((a, b) => this.KeySchema.compare(a, b))
.map((key) => {
return {
prim: 'Elt',
args: [this.KeySchema.EncodeObject(key), this.ValueSchema.EncodeObject(val.get(key))],
};
});
}
/**
* @deprecated ExtractSchema has been deprecated in favor of generateSchema
*
*/
ExtractSchema() {
return {
map: {
key: this.KeySchema.ExtractSchema(),
value: this.ValueSchema.ExtractSchema(),
},
};
}
generateSchema() {
return {
__michelsonType: MapToken.prim,
schema: {
key: this.KeySchema.generateSchema(),
value: this.ValueSchema.generateSchema(),
},
};
}
findAndReturnTokens(tokenToFind, tokens) {
if (MapToken.prim === tokenToFind) {
tokens.push(this);
}
this.KeySchema.findAndReturnTokens(tokenToFind, tokens);
this.ValueSchema.findAndReturnTokens(tokenToFind, tokens);
return tokens;
}
}
MapToken.prim = 'map';
class BoolToken extends ComparableToken {
constructor(val, idx, fac) {
super(val, idx, fac);
this.val = val;
this.idx = idx;
this.fac = fac;
}
Execute(val) {
return String(val.prim).toLowerCase() === 'true' ? true : false;
}
Encode(args) {
const val = args.pop();
return { prim: val ? 'True' : 'False' };
}
EncodeObject(val, semantic) {
if (semantic && semantic[BoolToken.prim]) {
return semantic[BoolToken.prim](val);
}
return { prim: val ? 'True' : 'False' };
}
/**
* @deprecated ExtractSchema has been deprecated in favor of generateSchema
*
*/
ExtractSchema() {
return BoolToken.prim;
}
generateSchema() {
return {
__michelsonType: BoolToken.prim,
schema: BoolToken.prim,
};
}
ToBigMapKey(val) {
return {
key: this.EncodeObject(val),
type: { prim: BoolToken.prim },
};
}
ToKey(val) {
return this.EncodeObject(val);
}
compare(val1, val2) {
if ((val1 && val2) || (!val1 && !val2)) {
return 0;
}
else if (val1) {
return 1;
}
else {
return -1;
}
}
findAndReturnTokens(tokenToFind, tokens) {
if (BoolToken.prim === tokenToFind) {
tokens.push(this);
}
return tokens;
}
}
BoolToken.prim = 'bool';
/**
* @category Error
* @description Error that indicates a failure happening when parsing encoding/executing a Contract
*/
class ContractValidationError extends TokenValidationError {
constructor(value, token, message) {
super(value, token, message);
this.value = value;
this.token = token;
this.name = 'ContractValidationError';
}
}
class ContractToken extends Token {
constructor(val, idx, fac) {
super(val, idx, fac);
this.val = val;
this.idx = idx;
this.fac = fac;
}
/**
* @throws {@link ContractValidationError}
*/
validate(value) {
// tz1,tz2 and tz3 seems to be valid contract values (for Unit contract)
if (utils.validateAddress(value) !== utils.ValidationResult.VALID) {
throw new ContractValidationError(value, this, `Value ${JSON.stringify(value)} is not a valid contract address.`);
}
return null;
}
/**
* @throws {@link ContractValidationError}
*/
Execute(val) {
if (val.string) {
return val.string;
}
if (!val.bytes) {
throw new ContractValidationError(val, this, `Value ${JSON.stringify(val)} is not a valid contract address. must contain bytes or string.`);
}
return utils.encodeAddress(val.bytes);
}
/**
* @throws {@link ContractValidationError}
*/
Encode(args) {
const val = args.pop();
this.validate(val);
return { string: val };
}
/**
* @throws {@link ContractValidationError}
*/
EncodeObject(val, semantic) {
this.validate(val);
if (semantic && semantic[ContractToken.prim]) {
return sem