UNPKG

@mavrykdynamics/taquito-local-forging

Version:

Provide local forging functionality to be with taquito

1,655 lines 57.8 kB
import { Prefix, buf2hex, b58cdecode, prefix, prefixLength, b58cencode, InvalidKeyHashError, invalidDetail, ValidationResult, InvalidPublicKeyError, validateBlock } from '@mavrykdynamics/taquito-utils';
import { ParameterValidationError, InvalidHexStringError, InvalidAddressError, InvalidContractAddressError, InvalidOperationKindError, InvalidBlockHashError } from '@mavrykdynamics/taquito-core';
import BigNumber$1, { BigNumber } from 'bignumber.js';

const toHexString = (bytes) => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
const pad = (num, paddingLen = 8) => {
    return num.toString(16).padStart(paddingLen, '0');
};

/*
 * Some code in this file is originally from sotez
 * Copyright (c) 2018 Andrew Kishino
 */
// See: https://protocol.mavryk.org/protocols/005_babylon.html#transactions-now-have-an-entrypoint
const ENTRYPOINT_MAX_LENGTH = 31;
var CODEC;
(function (CODEC) {
    CODEC["SECRET"] = "secret";
    CODEC["RAW"] = "raw";
    CODEC["MV1"] = "mv1";
    CODEC["BRANCH"] = "branch";
    CODEC["ZARITH"] = "zarith";
    CODEC["PUBLIC_KEY"] = "public_key";
    CODEC["PKH"] = "pkh";
    CODEC["PKH_ARR"] = "pkhArr";
    CODEC["DELEGATE"] = "delegate";
    CODEC["SCRIPT"] = "script";
    CODEC["BALLOT_STATEMENT"] = "ballotStmt";
    CODEC["PROPOSAL"] = "proposal";
    CODEC["PROPOSAL_ARR"] = "proposalArr";
    CODEC["INT32"] = "int32";
    CODEC["INT16"] = "int16";
    CODEC["PARAMETERS"] = "parameters";
    CODEC["ADDRESS"] = "address";
    CODEC["SMART_CONTRACT_ADDRESS"] = "smart_contract_address";
    CODEC["SMART_ROLLUP_ADDRESS"] = "smart_rollup_address";
    CODEC["SMART_ROLLUP_COMMITMENT_HASH"] = "smart_rollup_commitment_hash";
    CODEC["VALUE"] = "value";
    CODEC["PADDED_BYTES"] = "padded_bytes";
    CODEC["SMART_ROLLUP_MESSAGE"] = "smart_rollup_message";
    CODEC["MANAGER"] = "manager";
    CODEC["BLOCK_PAYLOAD_HASH"] = "blockPayloadHash";
    CODEC["ENTRYPOINT"] = "entrypoint";
    CODEC["OPERATION"] = "operation";
    CODEC["OP_ACTIVATE_ACCOUNT"] = "activate_account";
    CODEC["OP_DELEGATION"] = "delegation";
    CODEC["OP_TRANSACTION"] = "transaction";
    CODEC["OP_ORIGINATION"] = "origination";
    CODEC["OP_BALLOT"] = "ballot";
    CODEC["OP_FAILING_NOOP"] = "failing_noop";
    CODEC["OP_ATTESTATION"] = "attestation";
    CODEC["OP_ATTESTATION_WITH_DAL"] = "attestation_with_dal";
    CODEC["OP_SEED_NONCE_REVELATION"] = "seed_nonce_revelation";
    CODEC["OP_REVEAL"] = "reveal";
    CODEC["OP_PROPOSALS"] = "proposals";
    CODEC["OP_REGISTER_GLOBAL_CONSTANT"] = "register_global_constant";
    CODEC["OP_TRANSFER_TICKET"] = "transfer_ticket";
    CODEC["BURN_LIMIT"] = "burn_limit";
    CODEC["OP_INCREASE_PAID_STORAGE"] = "increase_paid_storage";
    CODEC["OP_UPDATE_CONSENSUS_KEY"] = "update_consensus_key";
    CODEC["OP_DRAIN_DELEGATE"] = "drain_delegate";
    CODEC["DEPOSITS_LIMIT"] = "deposits_limit";
    CODEC["OP_SET_DEPOSITS_LIMIT"] = "set_deposits_limit";
    CODEC["OP_SMART_ROLLUP_ORIGINATE"] = "smart_rollup_originate";
    CODEC["PVM_KIND"] = "pvm_kind";
    CODEC["OP_SMART_ROLLUP_ADD_MESSAGES"] = "smart_rollup_add_messages";
    CODEC["OP_SMART_ROLLUP_EXECUTE_OUTBOX_MESSAGE"] = "smart_rollup_execute_outbox_message";
    CODEC["OP_DAL_PUBLISH_COMMITMENT"] = "dal_publish_commitment";
    CODEC["SLOT_HEADER"] = "slot_header";
})(CODEC || (CODEC = {}));
// See https://protocol.mavryk.org/shell/p2p_api.html#alpha-michelson-v1-primitives-enumeration-unsigned-8-bit-integer
const opMapping = {
    '00': 'parameter',
    '01': 'storage',
    '02': 'code',
    '03': 'False',
    '04': 'Elt',
    '05': 'Left',
    '06': 'None',
    '07': 'Pair',
    '08': 'Right',
    '09': 'Some',
    '0a': 'True',
    '0b': 'Unit',
    '0c': 'PACK',
    '0d': 'UNPACK',
    '0e': 'BLAKE2B',
    '0f': 'SHA256',
    '10': 'SHA512',
    '11': 'ABS',
    '12': 'ADD',
    '13': 'AMOUNT',
    '14': 'AND',
    '15': 'BALANCE',
    '16': 'CAR',
    '17': 'CDR',
    '18': 'CHECK_SIGNATURE',
    '19': 'COMPARE',
    '1a': 'CONCAT',
    '1b': 'CONS',
    '1c': 'CREATE_ACCOUNT',
    '1d': 'CREATE_CONTRACT',
    '1e': 'IMPLICIT_ACCOUNT',
    '1f': 'DIP',
    '20': 'DROP',
    '21': 'DUP',
    '22': 'EDIV',
    '23': 'EMPTY_MAP',
    '24': 'EMPTY_SET',
    '25': 'EQ',
    '26': 'EXEC',
    '27': 'FAILWITH',
    '28': 'GE',
    '29': 'GET',
    '2a': 'GT',
    '2b': 'HASH_KEY',
    '2c': 'IF',
    '2d': 'IF_CONS',
    '2e': 'IF_LEFT',
    '2f': 'IF_NONE',
    '30': 'INT',
    '31': 'LAMBDA',
    '32': 'LE',
    '33': 'LEFT',
    '34': 'LOOP',
    '35': 'LSL',
    '36': 'LSR',
    '37': 'LT',
    '38': 'MAP',
    '39': 'MEM',
    '3a': 'MUL',
    '3b': 'NEG',
    '3c': 'NEQ',
    '3d': 'NIL',
    '3e': 'NONE',
    '3f': 'NOT',
    '40': 'NOW',
    '41': 'OR',
    '42': 'PAIR',
    '43': 'PUSH',
    '44': 'RIGHT',
    '45': 'SIZE',
    '46': 'SOME',
    '47': 'SOURCE',
    '48': 'SENDER',
    '49': 'SELF',
    '4a': 'STEPS_TO_QUOTA',
    '4b': 'SUB',
    '4c': 'SWAP',
    '4d': 'TRANSFER_TOKENS',
    '4e': 'SET_DELEGATE',
    '4f': 'UNIT',
    '50': 'UPDATE',
    '51': 'XOR',
    '52': 'ITER',
    '53': 'LOOP_LEFT',
    '54': 'ADDRESS',
    '55': 'CONTRACT',
    '56': 'ISNAT',
    '57': 'CAST',
    '58': 'RENAME',
    '59': 'bool',
    '5a': 'contract',
    '5b': 'int',
    '5c': 'key',
    '5d': 'key_hash',
    '5e': 'lambda',
    '5f': 'list',
    '60': 'map',
    '61': 'big_map',
    '62': 'nat',
    '63': 'option',
    '64': 'or',
    '65': 'pair',
    '66': 'set',
    '67': 'signature',
    '68': 'string',
    '69': 'bytes',
    '6a': 'mumav',
    '6b': 'timestamp',
    '6c': 'unit',
    '6d': 'operation',
    '6e': 'address',
    '6f': 'SLICE',
    '70': 'DIG',
    '71': 'DUG',
    '72': 'EMPTY_BIG_MAP',
    '73': 'APPLY',
    '74': 'chain_id',
    '75': 'CHAIN_ID',
    '76': 'LEVEL',
    '77': 'SELF_ADDRESS',
    '78': 'never',
    '79': 'NEVER',
    '7a': 'UNPAIR',
    '7b': 'VOTING_POWER',
    '7c': 'TOTAL_VOTING_POWER',
    '7d': 'KECCAK',
    '7e': 'SHA3',
    '7f': 'PAIRING_CHECK',
    '80': 'bls12_381_g1',
    '81': 'bls12_381_g2',
    '82': 'bls12_381_fr',
    '83': 'sapling_state',
    '84': 'sapling_transaction_deprecated',
    '85': 'SAPLING_EMPTY_STATE',
    '86': 'SAPLING_VERIFY_UPDATE',
    '87': 'ticket',
    '88': 'TICKET_DEPRECATED',
    '89': 'READ_TICKET',
    '8a': 'SPLIT_TICKET',
    '8b': 'JOIN_TICKETS',
    '8c': 'GET_AND_UPDATE',
    '8d': 'chest',
    '8e': 'chest_key',
    '8f': 'OPEN_CHEST',
    '90': 'VIEW',
    '91': 'view',
    '92': 'constant',
    '93': 'SUB_MUMAV',
    '94': 'tx_rollup_l2_address',
    '95': 'MIN_BLOCK_TIME',
    '96': 'sapling_transaction',
    '97': 'EMIT',
    '98': 'Lambda_rec',
    '99': 'LAMBDA_REC',
    '9a': 'TICKET',
    '9b': 'BYTES',
    '9c': 'NAT',
    '9d': 'Ticket',
};
const opMappingReverse = (() => {
    const result = {};
    Object.keys(opMapping).forEach((key) => {
        result[opMapping[key]] = key;
    });
    return result;
})();
// See https://protocol.mavryk.org/shell/p2p_api.html
const kindMapping = {
    0x04: 'activate_account',
    0x6b: 'reveal',
    0x6e: 'delegation',
    0x6c: 'transaction',
    0x6d: 'origination',
    0x06: 'ballot',
    0x15: 'attestation',
    0x17: 'attestation_with_dal',
    0x01: 'seed_nonce_revelation',
    0x05: 'proposals',
    0x6f: 'register_global_constant',
    0x9e: 'transfer_ticket',
    0x70: 'set_deposits_limit',
    0x71: 'increase_paid_storage',
    0x72: 'update_consensus_key',
    0x09: 'drain_delegate',
    0xc8: 'smart_rollup_originate',
    0xc9: 'smart_rollup_add_messages',
    0xce: 'smart_rollup_execute_outbox_message',
    0xe6: 'dal_publish_commitment',
    0x11: 'failing_noop',
};
const kindMappingReverse = (() => {
    const result = {};
    Object.keys(kindMapping).forEach((key) => {
        const keyNum = typeof key === 'string' ? parseInt(key, 10) : key;
        result[kindMapping[keyNum]] = pad(keyNum, 2);
    });
    return result;
})();
// See https://protocol.mavryk.org/protocols/005_babylon.html#transactions-now-have-an-entrypoint
const entrypointMapping = {
    '00': 'default',
    '01': 'root',
    '02': 'do',
    '03': 'set_delegate',
    '04': 'remove_delegate',
    '05': 'deposit',
    '06': 'stake',
    '07': 'unstake',
    '08': 'finalize_unstake',
    '09': 'set_delegate_parameters',
};
const entrypointMappingReverse = (() => {
    const result = {};
    Object.keys(entrypointMapping).forEach((key) => {
        result[entrypointMapping[key]] = key;
    });
    return result;
})();

/**
 *  @category Error
 *  @description Error that indicates an invalid operation content being passed or used
 */ class InvalidOperationSchemaError extends ParameterValidationError {
    constructor(operation, errorDetail) {
        super();
        this.operation = operation;
        this.errorDetail = errorDetail;
        this.name = 'InvalidOperationSchemaError';
        this.message = `Invalid operation content recevied`;
        errorDetail ? (this.message += ` ${errorDetail}.`) : '';
    }
}
/**
 *  @category Error
 *  @description Error that indicates an entrypoint name exceeding maximum length
 */
class OversizedEntryPointError extends ParameterValidationError {
    constructor(entrypoint) {
        super();
        this.entrypoint = entrypoint;
        this.name = 'OversizedEntryPointError';
        this.message = `Invalid entrypoint length "${entrypoint.length}", maximum length is "${ENTRYPOINT_MAX_LENGTH}".`;
    }
}
/**
 *  @category Error
 *  @description Error that indicates an invalid ballot value being used
 */
class InvalidBallotValueError extends ParameterValidationError {
    constructor(ballotValue) {
        super();
        this.ballotValue = ballotValue;
        this.name = 'InvalidBallotValueError';
        this.message = `Invalid ballot value "${ballotValue}" expecting one of the following: "yay", "nay", "pass".`;
    }
}
/**
 *  @category Error
 *  @description Error that indicates a failure when trying to decode ballot value
 */
class DecodeBallotValueError extends ParameterValidationError {
    constructor(ballotValue) {
        super();
        this.ballotValue = ballotValue;
        this.name = 'DecodeBallotValueError';
        this.message = `Invalid ballot value "${ballotValue}", cannot be decoded.`;
    }
}
/**
 *  @category Error
 *  @description Error that indicates unexpected Michelson Value being passed or used
 */
class UnexpectedMichelsonValueError extends ParameterValidationError {
    constructor(value) {
        super();
        this.value = value;
        this.name = 'UnexpectedMichelsonValueError';
        this.message = `Invalid Michelson value "${value}", unalbe to encode.`;
    }
}
/**
 *  @category Error
 *  @description Error that indicates a failure when trying to decode an operation
 */
class OperationDecodingError extends ParameterValidationError {
    constructor(message) {
        super();
        this.message = message;
        this.name = 'OperationDecodingError';
    }
}
/**
 *  @category Error
 *  @description Error that indicates a failure when trying to encode an operation
 */
class OperationEncodingError extends ParameterValidationError {
    constructor(message) {
        super();
        this.message = message;
        this.name = 'OperationEncodingError';
    }
}
/**
 *  @category Error
 *  @description Error that indicates an unsupported operation being passed or used
 */
class UnsupportedOperationError extends ParameterValidationError {
    constructor(op) {
        super();
        this.op = op;
        this.name = 'UnsupportedOperationError';
        this.message = `Unsupported operation "${op}", can submit an issue on our github for feature request.`;
    }
}
/**
 * @cateogry Error
 * @description Error that indicates an unsupported pvm being passed or used
 */
class UnsupportedPvmKindError extends ParameterValidationError {
    constructor(pvm) {
        super();
        this.pvm = pvm;
        this.name = 'UnsupportedPvmKindError';
        this.message = `Invalid Pvm kind "${pvm}" expecting either "arith" or "wasm_2_0_0".`;
    }
}
/**
 * @category Error
 * @description Error that indicates an unsupported pvm to decode
 */
class DecodePvmKindError extends ParameterValidationError {
    constructor(pvm) {
        super();
        this.pvm = pvm;
        this.name = 'DecodePvmKindError';
        this.message = `Invalid Pvm kind "${pvm}", cannot be decoded.`;
    }
}
/**
 * @category Error
 * @description Error that indicates an invalid Smart Rollup Address (sr1)
 */
class InvalidSmartRollupAddressError extends ParameterValidationError {
    constructor(address, errorDetail) {
        super();
        this.address = address;
        this.errorDetail = errorDetail;
        this.name = 'InvalidSmartRollupAddress';
        this.message = `Invalid smart rollup address "${address}"`;
        errorDetail ? (this.message += ` ${errorDetail}.`) : '';
    }
}
/**
 * @category Error
 * @description Error that indicates an invalid Smart Rollup commitment hash (src1)
 */
class InvalidSmartRollupCommitmentHashError extends ParameterValidationError {
    constructor(hash, errorDetail) {
        super();
        this.hash = hash;
        this.errorDetail = errorDetail;
        this.name = 'InvalidSmartRollupCommitmentHashError';
        this.message = `Invalid smart rollup commitment hash "${hash}"`;
        errorDetail ? (this.message += ` ${errorDetail}.`) : '';
    }
}
/**
 * @category Error
 * @description Error that indicates an invalid dal commitment (sh)
 */
class InvalidDalCommitmentError extends ParameterValidationError {
    constructor(commitment, errorDetail) {
        super();
        this.commitment = commitment;
        this.errorDetail = errorDetail;
        this.name = 'InvalidDalCommitmentError';
        this.message = `Invalid dal commitment "${commitment}"`;
        errorDetail ? (this.message += ` ${errorDetail}.`) : '';
    }
}

class Uint8ArrayConsumer {
    static fromHexString(hex) {
        const lowHex = hex.toLowerCase();
        if (/^(([a-f]|\d){2})*$/.test(lowHex)) {
            const arr = new Uint8Array((lowHex.match(/([a-z]|\d){2}/g) || []).map((byte) => parseInt(byte, 16)));
            return new Uint8ArrayConsumer(arr);
        }
        else {
            throw new InvalidHexStringError(lowHex);
        }
    }
    constructor(arr, offset = 0) {
        this.arr = arr;
        this.offset = offset;
    }
    consume(count) {
        const subArr = this.arr.subarray(this.offset, this.offset + count);
        this.offset += count;
        return subArr;
    }
    get(idx) {
        return this.arr[this.offset + idx];
    }
    length() {
        return this.arr.length - this.offset;
    }
    slice(start, end) {
        return new Uint8ArrayConsumer(this.arr.slice(start, end));
    }
}

const isPrim = (value) => {
    return 'prim' in value;
};
const isBytes = (value) => {
    return 'bytes' in value && typeof value.bytes === 'string';
};
const isString = (value) => {
    return 'string' in value && typeof value.string === 'string';
};
const isInt = (value) => {
    return 'int' in value && typeof value.int === 'string';
};
const scriptEncoder = (script) => {
    const code = valueEncoder(script.code);
    const storage = valueEncoder(script.storage);
    return `${pad(code.length / 2, 8)}${code}${pad(storage.length / 2, 8)}${storage}`;
};
const scriptDecoder = (value) => {
    const code = extractRequiredLen(value);
    const storage = extractRequiredLen(value);
    return {
        code: valueDecoder(new Uint8ArrayConsumer(code)),
        storage: valueDecoder(new Uint8ArrayConsumer(storage)),
    };
};
const valueEncoder = (value) => {
    if (Array.isArray(value)) {
        const encoded = value.map((x) => valueEncoder(x)).join('');
        const len = encoded.length / 2;
        return `02${pad(len)}${encoded}`;
    }
    else if (isPrim(value)) {
        return primEncoder(value);
    }
    else if (isBytes(value)) {
        return bytesEncoder(value);
    }
    else if (isString(value)) {
        return stringEncoder(value);
    }
    else if (isInt(value)) {
        return intEncoder(value);
    }
    throw new UnexpectedMichelsonValueError(JSON.stringify(value));
};
const valueDecoder = (value) => {
    const preamble = value.consume(1);
    switch (preamble[0]) {
        case 0x0a:
            return bytesDecoder(value);
        case 0x01:
            return stringDecoder(value);
        case 0x00:
            return intDecoder(value);
        case 0x02: {
            const val = new Uint8ArrayConsumer(extractRequiredLen(value));
            const results = [];
            while (val.length() > 0) {
                results.push(valueDecoder(val));
            }
            return results;
        }
        default:
            return primDecoder(value, preamble);
    }
};
const extractRequiredLen = (value, bytesLength = 4) => {
    const len = value.consume(bytesLength);
    const valueLen = parseInt(Buffer.from(len).toString('hex'), 16);
    return value.consume(valueLen);
};
/**
 * @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;
};
const bytesEncoder = (value) => {
    if (!/^([A-Fa-f0-9]{2})*$/.test(value.bytes)) {
        throw new InvalidHexStringError(value.bytes);
    }
    const len = value.bytes.length / 2;
    return `0a${pad(len)}${value.bytes}`;
};
const bytesDecoder = (value) => {
    const bytes = extractRequiredLen(value);
    return {
        bytes: Buffer.from(bytes).toString('hex'),
    };
};
const stringEncoder = (value) => {
    const str = Buffer.from(value.string, 'utf8').toString('hex');
    const hexLength = str.length / 2;
    return `01${pad(hexLength)}${str}`;
};
const stringDecoder = (value) => {
    const str = extractRequiredLen(value);
    return {
        string: Buffer.from(str).toString('utf8'),
    };
};
const intEncoder = ({ int }) => {
    const num = new 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('')}`;
};
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(numBin.join(''), 2);
    if (isNegative) {
        num = num.times(-1);
    }
    return {
        int: num.toFixed(),
    };
};
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 = pad(Math.min(2 * argsCount + hasAnnot + 0x03, 9), 2);
    const op = opMappingReverse[value.prim];
    let encodedArgs = (value.args || []).map((arg) => valueEncoder(arg)).join('');
    const encodedAnnots = Array.isArray(value.annots) ? encodeAnnots(value.annots) : '';
    if ((value.prim === 'LAMBDA' || value.prim === 'LAMBDA_REC') && argsCount) {
        encodedArgs = pad(encodedArgs.length / 2) + encodedArgs + pad(0);
    }
    if ((value.prim === 'pair' || value.prim === 'Pair') && argsCount > 2) {
        encodedArgs =
            encodedAnnots === ''
                ? pad(encodedArgs.length / 2) + encodedArgs + pad(0)
                : pad(encodedArgs.length / 2) + encodedArgs;
    }
    if (value.prim === 'view' && value.args) {
        encodedArgs = pad(encodedArgs.length / 2) + encodedArgs + pad(0);
    }
    return `${preamble}${op}${encodedArgs}${encodedAnnots}`;
};
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: opMapping[op],
    };
    if (opMapping[op] === 'LAMBDA' || opMapping[op] === 'LAMBDA_REC') {
        value.consume(4);
    }
    if (opMapping[op] === 'view') {
        if (argsCount != 0) {
            return primViewDecoder(value, result);
        }
        else {
            return result;
        }
    }
    let combPairArgs;
    let combPairAnnots;
    if ((opMapping[op] === 'pair' || opMapping[op] === 'Pair') && argsCount > 2) {
        combPairArgs = decodeCombPair(value);
        argsCount = 0;
        combPairAnnots = decodeAnnots(value);
    }
    const args = new Array(argsCount).fill(0).map(() => valueDecoder(value));
    if (opMapping[op] === 'LAMBDA' || 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'] = decodeAnnots(value);
    }
    return result;
};
const primViewDecoder = (value, result) => {
    value.consume(4);
    result['args'] = new Array(4).fill(0).map(() => valueDecoder(value));
    value.consume(4);
    return result;
};
const decodeCombPair = (val) => {
    const array = new Uint8ArrayConsumer(extractRequiredLen(val));
    const args = [];
    while (array.length() > 0) {
        args.push(valueDecoder(array));
    }
    return args;
};
const encodeAnnots = (value) => {
    const mergedAnnot = value
        .map((x) => {
        return Buffer.from(x, 'utf8').toString('hex');
    })
        .join('20');
    const len = mergedAnnot.length / 2;
    return `${pad(len)}${mergedAnnot}`;
};
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'));
};

// https://protocol.mavryk.org/shell/p2p_api.html specifies data types and structure for forging
const prefixEncoder = (prefix$1) => (str) => {
    return buf2hex(Buffer.from(b58cdecode(str, prefix[prefix$1])));
};
const prefixDecoder = (pre) => (str) => {
    const val = str.consume(prefixLength[pre]);
    return b58cencode(val, prefix[pre]);
};
const mv1Decoder = prefixDecoder(Prefix.MV1);
const branchDecoder = prefixDecoder(Prefix.B);
const publicKeyHashDecoder = (val) => {
    const prefix = val.consume(1);
    if (prefix[0] === 0x00) {
        return prefixDecoder(Prefix.MV1)(val);
    }
    else if (prefix[0] === 0x01) {
        return prefixDecoder(Prefix.MV2)(val);
    }
    else if (prefix[0] === 0x02) {
        return prefixDecoder(Prefix.MV3)(val);
    }
};
const publicKeyHashesDecoder = (val) => {
    if (!boolDecoder(val)) {
        return undefined;
    }
    const publicKeyHashes = [];
    val.consume(4);
    while (val.length() > 0) {
        publicKeyHashes.push(publicKeyHashDecoder(val));
    }
    return publicKeyHashes;
};
const branchEncoder = prefixEncoder(Prefix.B);
const mv1Encoder = prefixEncoder(Prefix.MV1);
const boolEncoder = (bool) => (bool ? 'ff' : '00');
const proposalEncoder = (proposal) => {
    return prefixEncoder(Prefix.P)(proposal);
};
const proposalDecoder = (proposal) => {
    return prefixDecoder(Prefix.P)(proposal);
};
const proposalsDecoder = (proposal) => {
    const proposals = [];
    proposal.consume(4);
    while (proposal.length() > 0) {
        proposals.push(proposalDecoder(proposal));
    }
    return proposals;
};
const proposalsEncoder = (proposals) => {
    return pad(32 * proposals.length) + proposals.map((x) => proposalEncoder(x)).join('');
};
const ballotEncoder = (ballot) => {
    switch (ballot) {
        case 'yay':
            return '00';
        case 'nay':
            return '01';
        case 'pass':
            return '02';
        default:
            throw new InvalidBallotValueError(ballot);
    }
};
const ballotDecoder = (ballot) => {
    const value = ballot.consume(1);
    switch (value[0]) {
        case 0x00:
            return 'yay';
        case 0x01:
            return 'nay';
        case 0x02:
            return 'pass';
        default:
            throw new DecodeBallotValueError(value[0].toString());
    }
};
const pvmKindEncoder = (pvm) => {
    switch (pvm) {
        case 'arith':
            return '00';
        case 'wasm_2_0_0':
            return '01';
        case 'riscv':
            return '02';
        default:
            throw new UnsupportedPvmKindError(pvm);
    }
};
const pvmKindDecoder = (pvm) => {
    const value = pvm.consume(1);
    switch (value[0]) {
        case 0x00:
            return 'arith';
        case 0x01:
            return 'wasm_2_0_0';
        case 0x02:
            return 'riscv';
        default:
            throw new DecodePvmKindError(value[0].toString());
    }
};
const delegateEncoder = (val) => {
    if (val) {
        return boolEncoder(true) + publicKeyHashEncoder(val);
    }
    else {
        return boolEncoder(false);
    }
};
const int32Encoder = (val) => {
    const num = parseInt(String(val), 10);
    const byte = [];
    for (let i = 0; i < 4; i++) {
        const shiftBy = (4 - (i + 1)) * 8;
        byte.push((num & (0xff << shiftBy)) >> shiftBy);
    }
    return Buffer.from(byte).toString('hex');
};
const int32Decoder = (val) => {
    const num = val.consume(4);
    let finalNum = 0;
    for (let i = 0; i < num.length; i++) {
        finalNum = finalNum | (num[i] << ((num.length - (i + 1)) * 8));
    }
    return finalNum;
};
const int16Encoder = (val) => {
    const num = parseInt(String(val), 10);
    const byte = [];
    for (let i = 0; i < 2; i++) {
        const shiftBy = (2 - (i + 1)) * 8;
        byte.push((num & (0xff << shiftBy)) >> shiftBy);
    }
    return Buffer.from(byte).toString('hex');
};
const int16Decoder = (val) => {
    const num = val.consume(2);
    let finalNum = 0;
    for (let i = 0; i < num.length; i++) {
        finalNum = finalNum | (num[i] << ((num.length - (i + 1)) * 8));
    }
    return finalNum;
};
const boolDecoder = (val) => {
    const bool = val.consume(1);
    return bool[0] === 0xff;
};
const delegateDecoder = (val) => {
    const hasDelegate = boolDecoder(val);
    if (hasDelegate) {
        return publicKeyHashDecoder(val);
    }
};
const publicKeyHashEncoder = (val) => {
    const pubkeyPrefix = val.substring(0, 3);
    switch (pubkeyPrefix) {
        case Prefix.MV1:
            return '00' + prefixEncoder(Prefix.MV1)(val);
        case Prefix.MV2:
            return '01' + prefixEncoder(Prefix.MV2)(val);
        case Prefix.MV3:
            return '02' + prefixEncoder(Prefix.MV3)(val);
        case Prefix.MV4:
            return '03' + prefixEncoder(Prefix.MV4)(val);
        default:
            throw new InvalidKeyHashError(val, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) +
                ` expecting one for the following "${Prefix.MV1}", "${Prefix.MV2}", "${Prefix.MV3}" or "${Prefix.MV4}".`);
    }
};
const publicKeyHashesEncoder = (val) => {
    if (!val) {
        return boolEncoder(false);
    }
    if (val.length === 0) {
        return boolEncoder(true) + pad(0);
    }
    const publicKeyHashes = val.reduce((prev, curr) => {
        return prev + publicKeyHashEncoder(curr);
    }, '');
    return boolEncoder(true) + pad(publicKeyHashes.length / 2) + publicKeyHashes;
};
const publicKeyEncoder = (val) => {
    const pubkeyPrefix = val.substring(0, 4);
    switch (pubkeyPrefix) {
        case Prefix.EDPK:
            return '00' + prefixEncoder(Prefix.EDPK)(val);
        case Prefix.SPPK:
            return '01' + prefixEncoder(Prefix.SPPK)(val);
        case Prefix.P2PK:
            return '02' + prefixEncoder(Prefix.P2PK)(val);
        default:
            throw new InvalidPublicKeyError(val, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) +
                ` expecting one of the following '${Prefix.EDPK}', '${Prefix.SPPK}', '${Prefix.P2PK}' or '${Prefix.BLPK}'.`);
    }
};
const addressEncoder = (val) => {
    const pubkeyPrefix = val.substring(0, 3);
    switch (pubkeyPrefix) {
        case Prefix.MV1:
        case Prefix.MV2:
        case Prefix.MV3:
        case Prefix.MV4:
            return '00' + publicKeyHashEncoder(val);
        case Prefix.KT1:
            return '01' + prefixEncoder(Prefix.KT1)(val) + '00';
        default:
            throw new InvalidAddressError(val, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) +
                ` expecting one of the following prefix '${Prefix.MV1}', ${Prefix.MV2}', '${Prefix.MV3}', '${Prefix.MV4}' or '${Prefix.KT1}'.`);
    }
};
const smartRollupAddressEncoder = (val) => {
    if (val.substring(0, 3) !== Prefix.SR1) {
        throw new InvalidSmartRollupAddressError(val, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) + ` expecting prefix '${Prefix.SR1}'.`);
    }
    return prefixEncoder(Prefix.SR1)(val);
};
const smartContractAddressEncoder = (val) => {
    const prefix = val.substring(0, 3);
    if (prefix === Prefix.KT1) {
        return '01' + prefixEncoder(Prefix.KT1)(val) + '00';
    }
    throw new InvalidContractAddressError(val, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) + ` expecting prefix '${Prefix.KT1}'.`);
};
const publicKeyDecoder = (val) => {
    const preamble = val.consume(1);
    switch (preamble[0]) {
        case 0x00:
            return prefixDecoder(Prefix.EDPK)(val);
        case 0x01:
            return prefixDecoder(Prefix.SPPK)(val);
        case 0x02:
            return prefixDecoder(Prefix.P2PK)(val);
        default:
            throw new InvalidPublicKeyError(val.toString(), invalidDetail(ValidationResult.NO_PREFIX_MATCHED));
    }
};
const smartRollupCommitmentHashEncoder = (val) => {
    const prefix = val.substring(0, 4);
    if (prefix === Prefix.SRC1) {
        return prefixEncoder(Prefix.SRC1)(val);
    }
    throw new InvalidSmartRollupCommitmentHashError(val, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) + ` expecting prefix '${Prefix.SRC1}'`);
};
const addressDecoder = (val) => {
    const preamble = val.consume(1);
    switch (preamble[0]) {
        case 0x00:
            return publicKeyHashDecoder(val);
        case 0x01: {
            const address = prefixDecoder(Prefix.KT1)(val);
            val.consume(1);
            return address;
        }
        default:
            throw new InvalidAddressError(val.toString(), ': Unable to decode.');
    }
};
const smartRollupAddressDecoder = (val) => {
    const address = prefixDecoder(Prefix.SR1)(val);
    if (address.substring(0, 3) !== Prefix.SR1) {
        throw new InvalidSmartRollupAddressError(address, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) + ` expecting prefix '${Prefix.SR1}'.`);
    }
    return address;
};
const smartContractAddressDecoder = (val) => {
    const preamble = val.consume(1);
    if (preamble[0] === 0x01) {
        const scAddress = prefixDecoder(Prefix.KT1)(val);
        val.consume(1);
        return scAddress;
    }
    throw new InvalidContractAddressError(val.toString(), invalidDetail(ValidationResult.NO_PREFIX_MATCHED));
};
const smartRollupCommitmentHashDecoder = (val) => {
    const address = prefixDecoder(Prefix.SRC1)(val);
    if (address.substring(0, 4) !== Prefix.SRC1) {
        throw new InvalidSmartRollupCommitmentHashError(address, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) + ` expecting prefix '${Prefix.SRC1}'`);
    }
    return address;
};
const zarithEncoder = (n) => {
    const fn = [];
    let nn = new BigNumber$1(n, 10);
    if (nn.isNaN()) {
        throw new TypeError(`Invalid zarith number ${n}`);
    }
    // eslint-disable-next-line no-constant-condition
    while (true) {
        if (nn.lt(128)) {
            if (nn.lt(16))
                fn.push('0');
            fn.push(nn.toString(16));
            break;
        }
        else {
            let b = nn.mod(128);
            nn = nn.minus(b);
            nn = nn.dividedBy(128);
            b = b.plus(128);
            fn.push(b.toString(16));
        }
    }
    return fn.join('');
};
const zarithDecoder = (n) => {
    let mostSignificantByte = 0;
    while (mostSignificantByte < n.length() && (n.get(mostSignificantByte) & 128) !== 0) {
        mostSignificantByte += 1;
    }
    let num = new BigNumber$1(0);
    for (let i = mostSignificantByte; i >= 0; i -= 1) {
        const tmp = n.get(i) & 0x7f;
        num = num.multipliedBy(128);
        num = num.plus(tmp);
    }
    n.consume(mostSignificantByte + 1);
    return new BigNumber$1(num).toString();
};
const entrypointDecoder = (value) => {
    const preamble = pad(value.consume(1)[0], 2);
    if (preamble in entrypointMapping) {
        return entrypointMapping[preamble];
    }
    else {
        const entry = extractRequiredLen(value, 1);
        const entrypoint = Buffer.from(entry).toString('utf8');
        if (entrypoint.length > ENTRYPOINT_MAX_LENGTH) {
            throw new OversizedEntryPointError(entrypoint);
        }
        return entrypoint;
    }
};
const parametersDecoder = (val) => {
    const preamble = val.consume(1);
    if (preamble[0] === 0x00) {
        return;
    }
    else {
        const encodedEntrypoint = entrypointDecoder(val);
        const params = extractRequiredLen(val);
        const parameters = valueDecoder(new Uint8ArrayConsumer(params));
        return {
            entrypoint: encodedEntrypoint,
            value: parameters,
        };
    }
};
const entrypointEncoder = (entrypoint) => {
    if (entrypoint in entrypointMappingReverse) {
        return `${entrypointMappingReverse[entrypoint]}`;
    }
    else {
        if (entrypoint.length > ENTRYPOINT_MAX_LENGTH) {
            throw new OversizedEntryPointError(entrypoint);
        }
        const value = { string: entrypoint };
        return `ff${valueEncoder(value).slice(8)}`;
    }
};
const parametersEncoder = (val) => {
    if (!val || (val.entrypoint === 'default' && 'prim' in val.value && val.value.prim === 'Unit')) {
        return '00';
    }
    const encodedEntrypoint = entrypointEncoder(val.entrypoint);
    const parameters = valueEncoder(val.value);
    const length = pad(parameters.length / 2);
    return `ff${encodedEntrypoint}${length}${parameters}`;
};
const valueParameterEncoder = (value) => {
    const valueEncoded = valueEncoder(value);
    return `${pad(valueEncoded.length / 2)}${valueEncoded}`;
};
const valueParameterDecoder = (val) => {
    const value = extractRequiredLen(val);
    return valueDecoder(new Uint8ArrayConsumer(value));
};
const blockPayloadHashEncoder = prefixEncoder(Prefix.VH);
const blockPayloadHashDecoder = prefixDecoder(Prefix.VH);
const entrypointNameEncoder = (entrypoint) => {
    const value = { string: entrypoint };
    return `${valueEncoder(value).slice(2)}`;
};
const entrypointNameDecoder = (val) => {
    const entry = extractRequiredLen(val);
    return Buffer.from(entry).toString('utf8');
};
const burnLimitEncoder = (val) => {
    return !val ? '00' : `ff${zarithEncoder(val)}`;
};
const burnLimitDecoder = (value) => {
    const prefix = value.consume(1);
    if (Buffer.from(prefix).toString('hex') !== '00') {
        return zarithDecoder(value);
    }
};
const depositsLimitEncoder = (val) => {
    return !val ? '00' : `ff${zarithEncoder(val)}`;
};
const depositsLimitDecoder = (value) => {
    const prefix = value.consume(1);
    if (Buffer.from(prefix).toString('hex') !== '00') {
        return zarithDecoder(value);
    }
};
const paddedBytesEncoder = (val, paddingLength = 8) => {
    return `${pad(val.length / 2, paddingLength)}${val}`;
};
const paddedBytesDecoder = (val) => {
    const value = extractRequiredLen(val);
    return Buffer.from(value).toString('hex');
};
const smartRollupMessageEncoder = (val) => {
    const message = val.reduce((prev, curr) => {
        return prev + `${pad(curr.length / 2)}${curr}`;
    }, '');
    return `${pad(message.length / 2)}${message}`;
};
const smartRollupMessageDecoder = (val) => {
    const valueArray = extractRequiredLen(val);
    const ret = stripLengthPrefixFromBytes(new Uint8ArrayConsumer(valueArray));
    return ret.map((value) => Buffer.from(value).toString('hex'));
};
const dalCommitmentEncoder = (val) => {
    const prefix = val.substring(0, 2);
    if (prefix === Prefix.SH) {
        return prefixEncoder(Prefix.SH)(val);
    }
    throw new InvalidDalCommitmentError(val, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) + ` expecting prefix '${Prefix.SH}'`);
};
const dalCommitmentDecoder = (val) => {
    const commitment = prefixDecoder(Prefix.SH)(val);
    if (commitment.substring(0, 2) !== Prefix.SH) {
        throw new InvalidDalCommitmentError(commitment, invalidDetail(ValidationResult.NO_PREFIX_MATCHED) + ` expecting prefix '${Prefix.SH}'`);
    }
    return commitment;
};
const slotHeaderEncoder = (val) => {
    return pad(val.slot_index, 2) + dalCommitmentEncoder(val.commitment) + val.commitment_proof;
};
const slotHeaderDecoder = (val) => {
    const preamble = val.consume(1);
    return {
        slot_index: Number(preamble[0].toString(10)),
        commitment: dalCommitmentDecoder(val),
        commitment_proof: toHexString(val.consume(96)), // rpcForger expect commitment_proof bytes to be len 96
    };
};

const ManagerOperationSchema = {
    branch: CODEC.BRANCH,
    contents: [CODEC.OPERATION],
};
const ActivationSchema = {
    pkh: CODEC.MV1,
    secret: CODEC.SECRET,
};
const RevealSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    public_key: CODEC.PUBLIC_KEY,
};
const DelegationSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    delegate: CODEC.DELEGATE,
};
const TransactionSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    amount: CODEC.ZARITH,
    destination: CODEC.ADDRESS,
    parameters: CODEC.PARAMETERS,
};
const OriginationSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    balance: CODEC.ZARITH,
    delegate: CODEC.DELEGATE,
    script: CODEC.SCRIPT,
};
const BallotSchema = {
    source: CODEC.PKH,
    period: CODEC.INT32,
    proposal: CODEC.PROPOSAL,
    ballot: CODEC.BALLOT_STATEMENT,
};
const AttestationSchema = {
    slot: CODEC.INT16,
    level: CODEC.INT32,
    round: CODEC.INT32,
    block_payload_hash: CODEC.BLOCK_PAYLOAD_HASH,
};
const AttestationWithDalSchema = {
    slot: CODEC.INT16,
    level: CODEC.INT32,
    round: CODEC.INT32,
    block_payload_hash: CODEC.BLOCK_PAYLOAD_HASH,
    dal_attestation: CODEC.ZARITH,
};
const SeedNonceRevelationSchema = {
    level: CODEC.INT32,
    nonce: CODEC.RAW,
};
const ProposalsSchema = {
    source: CODEC.PKH,
    period: CODEC.INT32,
    proposals: CODEC.PROPOSAL_ARR,
};
const RegisterGlobalConstantSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    value: CODEC.VALUE,
};
const TransferTicketSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    ticket_contents: CODEC.VALUE,
    ticket_ty: CODEC.VALUE,
    ticket_ticketer: CODEC.ADDRESS,
    ticket_amount: CODEC.ZARITH,
    destination: CODEC.ADDRESS,
    entrypoint: CODEC.ENTRYPOINT,
};
const IncreasePaidStorageSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    amount: CODEC.ZARITH,
    destination: CODEC.SMART_CONTRACT_ADDRESS,
};
const UpdateConsensusKeySchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    pk: CODEC.PUBLIC_KEY,
};
const DrainDelegateSchema = {
    consensus_key: CODEC.PKH,
    delegate: CODEC.PKH,
    destination: CODEC.PKH,
};
const SetDepositsLimitSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    limit: CODEC.DEPOSITS_LIMIT,
};
const SmartRollupOriginateSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    pvm_kind: CODEC.PVM_KIND,
    kernel: CODEC.PADDED_BYTES,
    parameters_ty: CODEC.VALUE,
    whitelist: CODEC.PKH_ARR,
};
const SmartRollupAddMessagesSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    message: CODEC.SMART_ROLLUP_MESSAGE,
};
const SmartRollupExecuteOutboxMessageSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    rollup: CODEC.SMART_ROLLUP_ADDRESS,
    cemented_commitment: CODEC.SMART_ROLLUP_COMMITMENT_HASH,
    output_proof: CODEC.PADDED_BYTES,
};
const DalPublishCommitmentSchema = {
    source: CODEC.PKH,
    fee: CODEC.ZARITH,
    counter: CODEC.ZARITH,
    gas_limit: CODEC.ZARITH,
    storage_limit: CODEC.ZARITH,
    slot_header: CODEC.SLOT_HEADER,
};
const FailingNoopSchema = {
    arbitrary: CODEC.PADDED_BYTES,
};
const operationEncoder = (encoders) => (operation) => {
    if (!(operation.kind in encoders) || !(operation.kind in kindMappingReverse)) {
        throw new InvalidOperationKindError(operation.kind);
    }
    return kindMappingReverse[operation.kind] + encoders[operation.kind](operation);
};
const operationDecoder = (decoders) => (value) => {
    const op = value.consume(1);
    const operationName = kindMapping[op[0]];
    if (operationName === undefined) {
        throw new UnsupportedOperationError(op[0].toString());
    }
    const decodedObj = decoders[operationName](value);
    if (typeof decodedObj !== 'object') {
        throw new OperationDecodingError('Invalid operation, cannot be decoded.');
    }
    return Object.assign({ kind: operationName }, decodedObj);
};
const schemaEncoder = (encoders) => (schema) => (value) => {
    const keys = Object.keys(schema);
    return keys.reduce((prev, key) => {
        const valueToEncode = schema[key];
        if (value && Array.isArray(valueToEncode)) {
            const encoder = encoders[valueToEncode[0]];
            const values = value[key];
            if (!Array.isArray(values)) {
                throw new OperationEncodingError(`Invalid operation value "${JSON.stringify(values)}" of key "${key}, expected value to be Array.`);
            }
            return (prev + values.reduce((prevBytes, current) => prevBytes + encoder(current), ''));
        }
        else {
            const encoder = encoders[valueToEncode];
            return prev + encoder(value[key]);
        }
    }, '');
};
const schemaDecoder = (decoders) => (schema) => (value) => {
    const keys = Object.keys(schema);
    return keys.reduce((prev, key) => {
        const valueToEncode = schema[key];
        if (Array.isArray(valueToEncode)) {
            const decoder = decoders[valueToEncode[0]];
            const decoded = [];
            const lastLength = value.length();
            while (value.length() > 0) {
                decoded.push(decoder(value));
                if (lastLength === value.length()) {
                    throw new OperationDecodingError('Unable to decode value');
                }
            }
            return Object.assign(Object.assign({}, prev), { [key]: decoded });
        }
        else {
            const decoder = decoders[valueToEncode];
            const result = decoder(value);
            if (typeof result !== 'undefined') {
                return Object.assign(Object.assign({}, prev), { [key]: result });
            }
            else {
                return Object.assign({}, prev);
            }
        }
    }, {});
};

const decoders = {
    [CODEC.SECRET]: (val) => toHexString(val.consume(20)),
    [CODEC.RAW]: (val) => toHexString(val.consume(32)),
    [CODEC.MV1]: mv1Decoder,
    [CODEC.BRANCH]: branchDecoder,
    [CODEC.ZARITH]: zarithDecoder,
    [CODEC.PUBLIC_KEY]: publicKeyDecoder,
    [CODEC.PKH]: publicKeyHashDecoder,
    [CODEC.PKH_ARR]: publicKeyHashesDecoder,
    [CODEC.DELEGATE]: delegateDecoder,
    [CODEC.INT32]: int32Decoder,
    [CODEC.SCRIPT]: scriptDecoder,
    [CODEC.BALLOT_STATEMENT]: ballotDecoder,
    [CODEC.PROPOSAL]: proposalDecoder,
    [CODEC.PROPOSAL_ARR]: proposalsDecoder,
    [CODEC.PARAMETERS]: parametersDecoder,
    [CODEC.ADDRESS]: addressDecoder,
    [CODEC.SMART_ROLLUP_ADDRESS]: smartRollupAddressDecoder,
    [CODEC.SMART_CONTRACT_ADDRESS]: smartContractAddressDecoder,
    [CODEC.SMART_ROLLUP_COMMITMENT_HASH]: smartRollupCommitmentHashDecoder,
    [CODEC.VALUE]: valueParameterDecoder,
    [CODEC.INT16]: int16Decoder,
    [CODEC.BLOCK_PAYLOAD_HASH]: blockPayloadHashDecoder,
    [CODEC.ENTRYPOINT]: entrypointNameDecoder,
    [CODEC.BURN_LIMIT]: burnLimitDecoder,
    [CODEC.DEPOSITS_LIMIT]: depositsLimitDecoder,
    [CODEC.PVM_KIND]: pvmKindDecoder,
    [CODEC.PADDED_BYTES]: paddedBytesDecoder,
    [CODEC.SMART_ROLLUP_MESSAGE]: smartRollupMessageDecoder,
    [CODEC.SLOT_HEADER]: slotHeaderDecoder,
};
decoders[CODEC.OPERATION] = operationDecoder(decoders);
decoders[CODEC.OP_ACTIVATE_ACCOUNT] = (val) => schemaDecoder(decoders)(ActivationSchema)(val);
decoders[CODEC.OP_FAILING_NOOP] = (val) => schemaDecoder(decoders)(FailingNoopSchema)(val);
decoders[CODEC.OP_DELEGATION] = (val) => schemaDecoder(decoders)(DelegationSchema)(val);
decoders[CODEC.OP_TRANSACTION] = (val) => schemaDecoder(decoders)(TransactionSchema)(val);
decoders[CODEC.OP_ORIGINATION] = (val) => schemaDecoder(decoders)(OriginationSchema)(val);
decoders[CODEC.OP_BALLOT] = (val) => schemaDecoder(decoders)(BallotSchema)(val);
decoders[CODEC.OP_ATTESTATION] = (val) => schemaDecoder(decoders)(AttestationSchema)(val);
decoders[CODEC.OP_ATTESTATION_WITH_DAL] = (val) => schemaDecoder(decoders)(AttestationWithDalSchema)(val);
decoders[CODEC.OP_SEED_NONCE_REVELATION] = (val) => schemaDecoder(decoders)(SeedNonceRevelationSchema)(val);
decoders[CODEC.OP_PROPOSALS] = (val) => schemaDecoder(decoders)(ProposalsSchema)(val);
decoders[CODEC.OP_REVEAL] = (val) => schemaDecoder(decoders)(RevealSchema)(val);
decoders[CODEC.OP_REGISTER_GLOBAL_CONSTANT] = (val) => schemaDecoder(decoders)(RegisterGlobalConstantSchema)(val);
decoders[CODEC.OP_TRANSFER_TICKET] = (val) => schemaDecoder(decoders)(TransferTicketSchema)(val);
decoders[CODEC.OP_INCREASE_PAID_STORAGE] = (val) => schemaDecoder(decoders)(IncreasePaidStorageSchema)(val);
decoders[CODEC.OP_UPDATE_CONSENSUS_KEY] = (val) => schemaDecoder(decoders)(UpdateConsensusKeySchema)(val);
decoders[CODEC.OP_DRAIN_DELEGATE] = (val) => schemaDecoder(decoders)(DrainDelegateSchema)(val);
decoders[CODEC.OP_SMART_ROLLUP_ORIGINATE] = (val) => schemaDecoder(decoders)(SmartRollupOriginateSchema)(val);
decoders[CODEC.OP_SMART_ROLLUP_ADD_MESSAGES] = (val) => schemaDecoder(decoders)(SmartRollupAddMessagesSchema)(val);
decoders[CODEC.OP_SMART_ROLLUP_EXECUTE_OUTBOX_MESSAGE] = (val) => schemaDecoder(decoders)(SmartRollupExecuteOutboxMessageSchema)(val);
decoders[CODEC.OP_DAL_PUBLISH_COMMITMENT] = (val) => schemaDecoder(decoders)(DalPublishCommitmentSchema)(val);
decoders[CODEC.MANAGER] = schemaDecoder(decoders)(ManagerOperationSchema);
decoders[CODEC.OP_SET_DEPOSITS_LIMIT] = (val) => schemaDecoder(decoders)(SetDepositsLimitSchema)(val);

const encoders = {
    [CODEC.SECRET]: (val) => val,
    [CODEC.RAW]: (val) => val,
    [CODEC.MV1]: mv1Encoder,
    [CODEC.BRANCH]: branchEncoder,
    [CODEC.ZARITH]: zarithEncoder,
    [CODEC.PUBLIC_KEY]: publicKeyEncoder,
    [CODEC.PKH]: publicKeyHashEncoder,
    [CODEC.PKH_ARR]: publicKeyHashesEncoder,
    [CODEC.DELEGATE]: delegateEncoder,
    [CODEC.SCRIPT]: scriptEncoder,
    [CODEC.BALLOT_STATEMENT]: ballotEncoder,
    [CODEC.PROPOSAL]: proposalEncoder,
    [CODEC.PROPOSAL_ARR]: proposalsEncoder,
    [CODEC.INT32]: int32Encoder,
    [CODEC.PARAMETERS]: parametersEncoder,
    [CODEC.ADDRESS]: addressEncoder,
    [CODEC.SMART_ROLLUP_ADDRESS]: smartRollupAddressEncoder,
    [CODEC.SMART_CONTRACT_ADDRESS]: smartContractAddressEncoder,
    [CODEC.SMART_ROLLUP_COMMITMENT_HASH]: smartRollupCommitmentHashEncoder,
    [CODEC.VALUE]: valueParameterEncoder,
    [CODEC.INT16]: int16Encoder,
    [CODEC.BLOCK_PAYLOAD_HASH]: blockPayloadHashEncoder,
    [CODEC.ENTRYPOINT]: entrypointNameEncoder,
    [CODEC.BURN_LIMIT]: burnLimitEncoder,
    [CODEC.DEPOSITS_LIMIT]: depositsLimitEncoder,
    [CODEC.PVM_KIND]: pvmKindEncoder,
    [CODEC.PADDED_BYTES]: paddedBytesEncoder,
    [CODEC.SMART_ROLLUP_MESSAGE]: smartRollupMessageEncoder,
    [CODEC.SLOT_HEADER]: slotHeaderEncoder,
};
encoders[CODEC.OPERATION] = operationEncoder(encoders);
encoders[CODEC.OP_ACTIVATE_ACCOUNT] = (val) => schemaEncoder(encoders)(ActivationSchema)(val);
encoders[CODEC.OP_DELEGATION] = (val) => schemaEncoder(encoders)(DelegationSchema)(val);
encoders[CODEC.OP_TRANSACTION] = (val) => schemaEncoder(encoders)(TransactionSchema)(val);
encoders[CODEC.OP_ORIGINATION] = (val) => schemaEncoder(encoders)(OriginationSchema)(val);
encoders[CODEC.OP_BALLOT] = (val) => schemaEncoder(encoders)(BallotSchema)(val);
encoders[CODEC.OP_ATTESTATION] = (val) => schemaEncoder(encoders)(AttestationSchema)(val);
encoders[CODEC.OP_ATTESTATION_WITH_DAL] = (val) => schemaEncoder(encoders)(AttestationWithDalSchema)(val);
encoders[CODEC.OP_SEED_NONCE_REVELATION] = (val) => schemaEncoder(encoders)(SeedNonceRevelationSchema)(val);
encoders[CODEC.OP_PROPOSALS] = (val) => schemaEncoder(encoders)(ProposalsSchema)(val);
encoders[CODEC.OP_REVEAL] = (val) => schemaEncoder(encoders)(RevealSchema)(val);
encoders[CODEC.OP_REGISTER_GLOBAL_CONSTANT] = (val) => schemaEncoder(encoders)(RegisterGlobalConstantSchema)(val);
encoders[CODEC.OP_TRANSFER_TICKET] = (val) => schemaEncoder(encoders)(TransferTicketSchema)(val);
encoders[CODEC.OP_INCREASE_PAID_STORAGE] = (val) => schemaEncoder(encoders)(IncreasePaidStorageSchema)(val);
encoders[CODEC.OP_UPDATE_CONSENSUS_KEY] = (val) => schemaEncoder(encoders)(UpdateConsensusKeySchema)(val);
encoders[CODEC.OP_DRAIN_DELEGATE] = (val) => schemaEncoder(encoders)(DrainDelegateSchema)(val);
encoders[CODEC.OP_SMART_ROLLUP_ORIGINATE] = (val) => schemaEncoder(encoders)(SmartRollupOriginateSchema)(val);
encoders[CODEC.OP_SMART_ROLLUP_ADD_MESSAGES] = (val) => schemaEncoder(encoders)(SmartRollupAddMessagesSchema)(val);
encoders[CODEC.OP_SMART_ROLLUP_EXECUTE_OUTBOX_MESSAGE] = (val) => schemaEncoder(encoders)(SmartRollupExecuteOutboxMessageSchema)(val);
encoders[CODEC.OP_DAL_PUBLISH_COMMITMENT] = (val) => schemaEncoder(encoders)(DalPublishCommitmentSchema)(val);
encoders[CODEC.MANAGER] = schemaEncoder(encoders)(ManagerOperationSchema);
encoders[CODEC.OP_SET_DEPOSITS_LIMIT] = (val) => schemaEncoder(encoders)(SetDepositsLimitSchema)(val);
encoders[CODEC.OP_FAILING_NOOP] = (val) => schemaEncoder(encoders)(FailingNoopSchema)(val);

const OperationKindMapping = {
    activate_account: ActivationSchema,
    reveal: RevealSchema,
    delegation: DelegationSchema,
    transaction: TransactionSchema,
    origination: OriginationSchema,
    ballot: BallotSchema,
    attestation: AttestationSchema,
    attestation_with_dal: AttestationWithDalSchema,
    seed_nonce_revelation: SeedNonceRevelationSchema,
    proposals: ProposalsSchema,
    register_global_constant: RegisterGlobalConstantSchema,
    transfer_ticket: TransferTicketSchema,
    increase_paid_storage: IncreasePaidStorageSchema,
    update_consensus_key: UpdateConsensusKeySchema,
    drain_delegate: DrainDelegateSchema,
    set_deposits_limit: SetDepositsLimitSchema,
    smart_rollup_originate: SmartRollupOriginateSchema,
    smart_rollup_add_messages: SmartRollupAddMessagesSchema,
    smart_rollup_execute_outbox_message: SmartRollupExecuteOutboxMessageSchema,
    dal_publish_commitment: DalPublishCommitmentSchema,
    failing_noop: FailingNoopSchema,
};
// Asymmetric difference: only account for things in arr2 that are not present in arr1, not vice versa
const getArrayDifference = (arr1, arr2) => {
    return arr2.filter((x) => !arr1.includes(x));
};
const deleteArrayElementByValue = (array, item) => {
    return array.filter((e) => e !== item);
};
/**
 * @returns A boolean value to indicate whether the operation kind is valid or not
 */
const validateOperationKind = (opKind) => {
    const opKindList = Object.keys(OperationKindMapping);
    return opKindList.includes(opKind);
};
/**
 *  returns 0 when the two array of properties are identical or the passed property
 *  does not have any missing parameters from the corresponding schema
 *
 *  @returns array element differences if there are missing required property keys
 */
const validateMissingProperty = (operationContent) => {
    const kind = operationContent.kind;
    const keys = Object.keys(operationContent);
    const cleanKeys = deleteArrayElementByValue(keys, 'kind');
    const schemaKeys = Object.keys(OperationKindMapping[kind]);
    return getArrayDifference(cleanKeys, schemaKeys);
};

var ProtocolsHash;
(function (ProtocolsHash) {
    ProtocolsHash["PtAtLas"] = "PtAtLasdzXg4XxeVNtWheo13nG4wHXP22qYMqFcT3fyBpWkFero";
    ProtocolsHash["PtBoreas"] = "PtBoreasK2KPuKbeYtXeEdudEHS7YcMFHE9amwheUc4kejTxgRi";
    ProtocolsHash["ProtoALpha"] = "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK";
})(ProtocolsHash || (ProtocolsHash = {}));

// IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT OR CHECKIN!
const VERSION = {
    commitHash: '45fea4a361f29598063e448574800220c4687001',
    version: '20.0.0',
};

/**
 * @packageDocumentation
 * @module @mavrykdynamics/taquito-local-forging
 */
const PROTOCOL_CURRENT = ProtocolsHash.PtBoreas;
function getCodec(codec, _proto) {
    return {
        encoder: encoders[codec],
        decoder: (hex) => {
            const consumer = Uint8ArrayConsumer.fromHexString(hex);
            return decoders[codec](consumer);
        },
    };
}
//
class LocalForger {
    constructor(protocolHash = PROTOCOL_CURRENT) {
        this.protocolHash = protocolHash;
        this.codec = getCodec(CODEC.MANAGER, this.protocolHash);
    }
    forge(params) {
        const branchValidation = validateBlock(params.branch);
        if (branchValidation !== ValidationResult.VALID) {
            throw new InvalidBlockHashError(params.branch, invalidDetail(branchValidation));
        }
        for (const content of params.contents) {
            if (!validateOperationKind(content.kind)) {
                throw new InvalidOperationKindError(content.kind);
            }
            const diff = validateMissingProperty(content);
            if (diff.length === 1) {
                if (content.kind === 'delegation' && diff[0] === 'delegate') {
                    continue;
                }
                else if (content.kind === 'origination' && diff[0] === 'delegate') {
                    continue;
                }
                else if (content.kind === 'transaction' && diff[0] === 'parameters') {
                    continue;
                }
                else if (content.kind === 'set_deposits_limit' && diff[0] === 'limit') {
                    continue;
                }
                else if (content.kind === 'smart_rollup_originate' && diff[0] === 'whitelist') {
                    continue;
                }
                else {
                    throw new InvalidOperationSchemaError(content, `missing properties "${diff.join(', ')}"`);
                }
            }
            else if (diff.length > 1) {
                throw new InvalidOperationSchemaError(content, `missing properties "${diff.join(', ')}"`);
            }
        }
        const forged = this.codec.encoder(params).toLowerCase();
        return Promise.resolve(forged);
    }
    parse(hex) {
        return Promise.resolve(this.codec.decoder(hex));
    }
}
const localForger = new LocalForger();

export { CODEC, LocalForger, ProtocolsHash, Uint8ArrayConsumer, VERSION, decoders, encoders, getCodec, localForger, opMapping, opMappingReverse };
//# sourceMappingURL=taquito-local-forging.es6.js.map