@mavrykdynamics/taquito-local-forging
Version:
Provide local forging functionality to be with taquito
284 lines (283 loc) • 11.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeAnnots = exports.encodeAnnots = exports.decodeCombPair = exports.primViewDecoder = exports.primDecoder = exports.primEncoder = exports.intDecoder = exports.intEncoder = exports.stringDecoder = exports.stringEncoder = exports.bytesDecoder = exports.bytesEncoder = exports.stripLengthPrefixFromBytes = exports.extractRequiredLen = exports.valueDecoder = exports.valueEncoder = exports.scriptDecoder = exports.scriptEncoder = exports.isInt = exports.isString = exports.isBytes = exports.isPrim = void 0;
const bignumber_js_1 = require("bignumber.js");
const uint8array_consumer_1 = require("../uint8array-consumer");
const constants_1 = require("../constants");
const utils_1 = require("../utils");
const errors_1 = require("../errors");
const taquito_core_1 = require("@mavrykdynamics/taquito-core");
const isPrim = (value) => {
return 'prim' in value;
};
exports.isPrim = isPrim;
const isBytes = (value) => {
return 'bytes' in value && typeof value.bytes === 'string';
};
exports.isBytes = isBytes;
const isString = (value) => {
return 'string' in value && typeof value.string === 'string';
};
exports.isString = isString;
const isInt = (value) => {
return 'int' in value && typeof value.int === 'string';
};
exports.isInt = isInt;
const scriptEncoder = (script) => {
const code = (0, exports.valueEncoder)(script.code);
const storage = (0, exports.valueEncoder)(script.storage);
return `${(0, utils_1.pad)(code.length / 2, 8)}${code}${(0, utils_1.pad)(storage.length / 2, 8)}${storage}`;
};
exports.scriptEncoder = scriptEncoder;
const scriptDecoder = (value) => {
const code = (0, exports.extractRequiredLen)(value);
const storage = (0, exports.extractRequiredLen)(value);
return {
code: (0, exports.valueDecoder)(new uint8array_consumer_1.Uint8ArrayConsumer(code)),
storage: (0, exports.valueDecoder)(new uint8array_consumer_1.Uint8ArrayConsumer(storage)),
};
};
exports.scriptDecoder = scriptDecoder;
const valueEncoder = (value) => {
if (Array.isArray(value)) {
const encoded = value.map((x) => (0, exports.valueEncoder)(x)).join('');
const len = encoded.length / 2;
return `02${(0, utils_1.pad)(len)}${encoded}`;
}
else if ((0, exports.isPrim)(value)) {
return (0, exports.primEncoder)(value);
}
else if ((0, exports.isBytes)(value)) {
return (0, exports.bytesEncoder)(value);
}
else if ((0, exports.isString)(value)) {
return (0, exports.stringEncoder)(value);
}
else if ((0, exports.isInt)(value)) {
return (0, exports.intEncoder)(value);
}
throw new errors_1.UnexpectedMichelsonValueError(JSON.stringify(value));
};
exports.valueEncoder = valueEncoder;
const valueDecoder = (value) => {
const preamble = value.consume(1);
switch (preamble[0]) {
case 0x0a:
return (0, exports.bytesDecoder)(value);
case 0x01:
return (0, exports.stringDecoder)(value);
case 0x00:
return (0, exports.intDecoder)(value);
case 0x02: {
const val = new uint8array_consumer_1.Uint8ArrayConsumer((0, exports.extractRequiredLen)(value));
const results = [];
while (val.length() > 0) {
results.push((0, exports.valueDecoder)(val));
}
return results;
}
default:
return (0, exports.primDecoder)(value, preamble);
}
};
exports.valueDecoder = valueDecoder;
const extractRequiredLen = (value, bytesLength = 4) => {
const len = value.consume(bytesLength);
const valueLen = parseInt(Buffer.from(len).toString('hex'), 16);
return value.consume(valueLen);
};
exports.extractRequiredLen = extractRequiredLen;
/**
* @description parse bytes into multiple items of an array
* @param value Uint8ArrayConsumer class of forged segment to parse
* @param bytesLength default 4 bytes for length of variable bytes
* @returns array of Uint8Array values for each array item
*/
const stripLengthPrefixFromBytes = (value, bytesLength = 4) => {
const ret = [];
let values = value;
while (values.length()) {
const len = values.consume(bytesLength);
const valueLen = parseInt(Buffer.from(len).toString('hex'), 16);
ret.push(values.consume(valueLen));
values = values.slice(valueLen + bytesLength);
}
return ret;
};
exports.stripLengthPrefixFromBytes = stripLengthPrefixFromBytes;
const bytesEncoder = (value) => {
if (!/^([A-Fa-f0-9]{2})*$/.test(value.bytes)) {
throw new taquito_core_1.InvalidHexStringError(value.bytes);
}
const len = value.bytes.length / 2;
return `0a${(0, utils_1.pad)(len)}${value.bytes}`;
};
exports.bytesEncoder = bytesEncoder;
const bytesDecoder = (value) => {
const bytes = (0, exports.extractRequiredLen)(value);
return {
bytes: Buffer.from(bytes).toString('hex'),
};
};
exports.bytesDecoder = bytesDecoder;
const stringEncoder = (value) => {
const str = Buffer.from(value.string, 'utf8').toString('hex');
const hexLength = str.length / 2;
return `01${(0, utils_1.pad)(hexLength)}${str}`;
};
exports.stringEncoder = stringEncoder;
const stringDecoder = (value) => {
const str = (0, exports.extractRequiredLen)(value);
return {
string: Buffer.from(str).toString('utf8'),
};
};
exports.stringDecoder = stringDecoder;
const intEncoder = ({ int }) => {
const num = new bignumber_js_1.BigNumber(int, 10);
const positiveMark = num.toString(2)[0] === '-' ? '1' : '0';
const binary = num.toString(2).replace(/-/g, '');
const pad = binary.length <= 6
? 6
: (binary.length - 6) % 7
? binary.length + 7 - ((binary.length - 6) % 7)
: binary.length;
const splitted = binary.padStart(pad, '0').match(/\d{6,7}/g);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const reversed = splitted.reverse();
reversed[0] = positiveMark + reversed[0];
const numHex = reversed.map((x, i) =>
// Add one to the last chunk
parseInt((i === reversed.length - 1 ? '0' : '1') + x, 2)
.toString(16)
.padStart(2, '0'));
return `00${numHex.join('')}`;
};
exports.intEncoder = intEncoder;
const intDecoder = (value) => {
let c = value.consume(1)[0];
const hexNumber = [];
const isNotLastChunkMask = 1 << 7;
while (c & isNotLastChunkMask) {
hexNumber.push(c);
c = value.consume(1)[0];
}
hexNumber.push(c);
const isNegative = !!((1 << 6) & hexNumber[0]);
hexNumber[0] = hexNumber[0] & 0b1111111;
const numBin = hexNumber
.map((x, i) => x
.toString(2)
.slice(i === 0 ? -6 : -7)
.padStart(i === 0 ? 6 : 7, '0'))
.reverse();
let num = new bignumber_js_1.BigNumber(numBin.join(''), 2);
if (isNegative) {
num = num.times(-1);
}
return {
int: num.toFixed(),
};
};
exports.intDecoder = intDecoder;
const primEncoder = (value) => {
const hasAnnot = +Array.isArray(value.annots);
const argsCount = Array.isArray(value.args) ? value.args.length : 0;
// Specify the number of args max is 3 without annotation
const preamble = (0, utils_1.pad)(Math.min(2 * argsCount + hasAnnot + 0x03, 9), 2);
const op = constants_1.opMappingReverse[value.prim];
let encodedArgs = (value.args || []).map((arg) => (0, exports.valueEncoder)(arg)).join('');
const encodedAnnots = Array.isArray(value.annots) ? (0, exports.encodeAnnots)(value.annots) : '';
if ((value.prim === 'LAMBDA' || value.prim === 'LAMBDA_REC') && argsCount) {
encodedArgs = (0, utils_1.pad)(encodedArgs.length / 2) + encodedArgs + (0, utils_1.pad)(0);
}
if ((value.prim === 'pair' || value.prim === 'Pair') && argsCount > 2) {
encodedArgs =
encodedAnnots === ''
? (0, utils_1.pad)(encodedArgs.length / 2) + encodedArgs + (0, utils_1.pad)(0)
: (0, utils_1.pad)(encodedArgs.length / 2) + encodedArgs;
}
if (value.prim === 'view' && value.args) {
encodedArgs = (0, utils_1.pad)(encodedArgs.length / 2) + encodedArgs + (0, utils_1.pad)(0);
}
return `${preamble}${op}${encodedArgs}${encodedAnnots}`;
};
exports.primEncoder = primEncoder;
const primDecoder = (value, preamble) => {
const hasAnnot = (preamble[0] - 0x03) % 2 === 1;
let argsCount = Math.floor((preamble[0] - 0x03) / 2);
const op = value.consume(1)[0].toString(16).padStart(2, '0');
const result = {
prim: constants_1.opMapping[op],
};
if (constants_1.opMapping[op] === 'LAMBDA' || constants_1.opMapping[op] === 'LAMBDA_REC') {
value.consume(4);
}
if (constants_1.opMapping[op] === 'view') {
if (argsCount != 0) {
return (0, exports.primViewDecoder)(value, result);
}
else {
return result;
}
}
let combPairArgs;
let combPairAnnots;
if ((constants_1.opMapping[op] === 'pair' || constants_1.opMapping[op] === 'Pair') && argsCount > 2) {
combPairArgs = (0, exports.decodeCombPair)(value);
argsCount = 0;
combPairAnnots = (0, exports.decodeAnnots)(value);
}
const args = new Array(argsCount).fill(0).map(() => (0, exports.valueDecoder)(value));
if (constants_1.opMapping[op] === 'LAMBDA' || constants_1.opMapping[op] === 'LAMBDA_REC') {
value.consume(4);
}
if (combPairArgs) {
result['args'] = combPairArgs;
}
else if (args.length) {
result['args'] = args;
}
if (combPairAnnots && combPairAnnots[0] !== '') {
result['annots'] = combPairAnnots;
}
else if (hasAnnot) {
result['annots'] = (0, exports.decodeAnnots)(value);
}
return result;
};
exports.primDecoder = primDecoder;
const primViewDecoder = (value, result) => {
value.consume(4);
result['args'] = new Array(4).fill(0).map(() => (0, exports.valueDecoder)(value));
value.consume(4);
return result;
};
exports.primViewDecoder = primViewDecoder;
const decodeCombPair = (val) => {
const array = new uint8array_consumer_1.Uint8ArrayConsumer((0, exports.extractRequiredLen)(val));
const args = [];
while (array.length() > 0) {
args.push((0, exports.valueDecoder)(array));
}
return args;
};
exports.decodeCombPair = decodeCombPair;
const encodeAnnots = (value) => {
const mergedAnnot = value
.map((x) => {
return Buffer.from(x, 'utf8').toString('hex');
})
.join('20');
const len = mergedAnnot.length / 2;
return `${(0, utils_1.pad)(len)}${mergedAnnot}`;
};
exports.encodeAnnots = encodeAnnots;
const decodeAnnots = (val) => {
const len = val.consume(4);
const annotLen = parseInt(Buffer.from(len).toString('hex'), 16);
const restOfAnnot = val.consume(annotLen);
const restOfAnnotHex = Buffer.from(restOfAnnot).toString('hex');
return restOfAnnotHex.split('20').map((x) => Buffer.from(x, 'hex').toString('utf8'));
};
exports.decodeAnnots = decodeAnnots;