UNPKG

@mavrykdynamics/taquito-local-forging

Version:

Provide local forging functionality to be with taquito

284 lines (283 loc) 11.1 kB
"use strict"; 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;