"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deserializeTransferFeePayload = exports.serializeUpdateMessageFeeVAA = exports.serializeUpdateMessageFeePayload = exports.deserializeUpdateMessageFeeVAA = exports.deserializeUpdateMessageFeePayload = exports.serializeGuardianSetUpgradeVAA = exports.serializeGuardianSetUpgradePayload = exports.deserializeGuardianSetUpgradeVAA = exports.deserializeGuardianSetUpgradePayload = exports.serializeContractUpgradeVAA = exports.serializeContractUpgradePayload = exports.deserializeNFTBridgeContractUpgradeVAA = exports.deserializeTokenBridgeContractUpgradeVAA = exports.deserializeCoreContractUpgradeVAA = exports.deserializeContractUpgradePayload = exports.serializeAttestTokenVAA = exports.serializeAttestTokenPayload = exports.deserializeAttestTokenVAA = exports.deserializeAttestTokenPayload = exports.serializeTransferNFTVAA = exports.serializeTransferNFTPayload = exports.deserializeTransferNFTVAA = exports.deserializeTransferNFTPayload = exports.bytes32ToUtf8String = exports.serializeTransferTokenVAA = exports.deserializeTransferTokenVAA = exports.serializeTransferTokenPayload = exports.deserializeTransferTokenPayload = exports.extractSequenceFromVAA = exports.extractPayloadFromVAA = exports.extractBodyFromVAA = exports.Signature = exports.isGovernanceVAA = exports.isApplicationVAA = exports.UpdateRefundAddressActionId = exports.UpdateMinimalConsistencyLevelActionId = exports.DestroyUnexecutedSequencesActionId = exports.AppContractUpgradeActionId = exports.RegisterChainActionId = exports.TransferFeeActionId = exports.UpdateMessageFeeActionId = exports.GuardianSetUpgradeActionId = exports.CoreContractUpgradeActionId = exports.TransferNFTPayloadId = exports.AttestTokenPayloadId = exports.TransferTokenPayloadId = exports.NFTBridgeModule = exports.TokenBridgeModule = exports.CoreModule = exports.METADATA_REPLACE = void 0;
exports.signVAABody = exports.serializeVAA = exports.serializeVAABody = exports.VAAPayloadDeserializers = exports.VAAPayloadSerializers = exports.deserializeVAA = exports.serializeUpdateRefundAddressVAA = exports.serializeUpdateRefundAddressPayload = exports.deserializeUpdateRefundAddressVAA = exports.deserializeUpdateRefundAddressPayload = exports.serializeUpdateMinimalConsistencyLevelVAA = exports.serializeUpdateMinimalConsistencyLevelPayload = exports.deserializeUpdateMinimalConsistencyLevelVAA = exports.deserializeUpdateMinimalConsistencyLevelPayload = exports.serializeDestroyUnexecutedSequencesVAA = exports.serializeDestroyUnexecutedSequencesPayload = exports.deserializeDestroyUnexecutedSequencesVAA = exports.deserializeDestroyUnexecutedSequencesPayload = exports.serializeRegisterChainVAA = exports.serializeRegisterChainPayload = exports.deserializeNFTBridgeRegisterChainVAA = exports.deserializeTokenBridgeRegisterChainVAA = exports.deserializeRegisterChainPayload = exports.serializeAlphContractUpgradeVAA = exports.serializeAlphContractUpgradePayload = exports.deserializeAlphTokenBridgeContractUpgradeVAA = exports.deserializeAlphCoreContractUpgradeVAA = exports.deserializeAlphContractUpgradePayload = exports.serializeTransferFeeVAA = exports.serializeTransferFeePayload = exports.deserializeTransferFeeVAA = void 0;
const array_1 = require("./array");
const consts_1 = require("./consts");
const utils_1 = require("ethers/lib/utils");
const elliptic = __importStar(require("elliptic"));
exports.METADATA_REPLACE = new RegExp("\u0000", "g");
exports.CoreModule = '00000000000000000000000000000000000000000000000000000000436f7265';
exports.TokenBridgeModule = '000000000000000000000000000000000000000000546f6b656e427269646765';
exports.NFTBridgeModule = '00000000000000000000000000000000000000000000004e4654427269646765';
exports.TransferTokenPayloadId = 1;
exports.AttestTokenPayloadId = 2;
exports.TransferNFTPayloadId = 3;
exports.CoreContractUpgradeActionId = 1;
exports.GuardianSetUpgradeActionId = 2;
exports.UpdateMessageFeeActionId = 3;
exports.TransferFeeActionId = 4;
exports.RegisterChainActionId = 1;
exports.AppContractUpgradeActionId = 2;
exports.DestroyUnexecutedSequencesActionId = 240;
exports.UpdateMinimalConsistencyLevelActionId = 241;
exports.UpdateRefundAddressActionId = 242;
function isApplicationVAA(vaa) {
    return vaa.body.payload.type === 'AttestToken'
        || vaa.body.payload.type === 'TransferToken'
        || vaa.body.payload.type === 'TransferNFT';
}
exports.isApplicationVAA = isApplicationVAA;
function isGovernanceVAA(vaa) {
    return !isApplicationVAA(vaa);
}
exports.isGovernanceVAA = isGovernanceVAA;
class Signature {
    constructor(index, sig) {
        this.index = index;
        this.sig = sig;
    }
    static from(data) {
        if (data.length !== 66) {
            throw new Error(`Invalid signature ${array_1.uint8ArrayToHex(data)}, expected 66 bytes`);
        }
        return new Signature(data[0], data.slice(1));
    }
    serialize() {
        return Buffer.concat([Buffer.from([this.index]), this.sig]);
    }
}
exports.Signature = Signature;
function bytesToModule(bytes) {
    const hexStr = array_1.uint8ArrayToHex(bytes);
    switch (hexStr) {
        case exports.CoreModule:
            return 'Core';
        case exports.TokenBridgeModule:
            return 'TokenBridge';
        case exports.NFTBridgeModule:
            return 'NFTBridge';
        default:
            throw new Error(`Invalid module: ${hexStr}`);
    }
}
class Reader {
    constructor(data) {
        this.offset = 0;
        this.buffer = Buffer.from(data);
    }
    updateOffset(size) {
        this.offset += size;
        if (this.offset > this.buffer.length) {
            throw new Error(`Read offset is out of range, offset: ${this.offset}, buffer size: ${this.buffer.length}`);
        }
    }
    readUInt8() {
        this.updateOffset(1);
        return this.buffer.readUInt8(this.offset - 1);
    }
    readUInt16BE() {
        this.updateOffset(2);
        return this.buffer.readUInt16BE(this.offset - 2);
    }
    readUInt32BE() {
        this.updateOffset(4);
        return this.buffer.readUInt32BE(this.offset - 4);
    }
    readUInt64BE() {
        this.updateOffset(8);
        return this.buffer.readBigUInt64BE(this.offset - 8);
    }
    readUInt256BE() {
        return BigInt('0x' + array_1.uint8ArrayToHex(this.readBytes(32)));
    }
    readModule() {
        return bytesToModule(this.readBytes(32));
    }
    readBytes(length) {
        this.updateOffset(length);
        return this.buffer.slice(this.offset - length, this.offset);
    }
    remain() {
        return this.buffer.slice(this.offset);
    }
}
class Writer {
    constructor(length) {
        this.offset = 0;
        this.buffer = Buffer.allocUnsafe(length);
    }
    updateOffset(size) {
        this.offset += size;
        if (this.offset > this.buffer.length) {
            throw new Error(`Write offset is out of range, offset: ${this.offset}, buffer size: ${this.buffer.length}`);
        }
    }
    writeUInt8(value) {
        this.updateOffset(1);
        this.buffer.writeUInt8(value, this.offset - 1);
    }
    writeUInt16BE(value) {
        this.updateOffset(2);
        this.buffer.writeUInt16BE(value, this.offset - 2);
    }
    writeUInt32BE(value) {
        this.updateOffset(4);
        this.buffer.writeUInt32BE(value, this.offset - 4);
    }
    writeUInt64BE(value) {
        this.updateOffset(8);
        this.buffer.writeBigUInt64BE(value, this.offset - 8);
    }
    writeUInt256BE(value) {
        const bytes = Buffer.from(value.toString(16).padStart(64, '0'), 'hex');
        this.writeBytes(bytes);
    }
    writeModule(module) {
        switch (module) {
            case 'Core':
                this.writeBytes(Buffer.from(exports.CoreModule, 'hex'));
                break;
            case 'TokenBridge':
                this.writeBytes(Buffer.from(exports.TokenBridgeModule, 'hex'));
                break;
            case 'NFTBridge':
                this.writeBytes(Buffer.from(exports.NFTBridgeModule, 'hex'));
                break;
        }
    }
    writeBytes(data) {
        this.updateOffset(data.length);
        this.buffer.fill(data, this.offset - data.length, this.offset);
    }
    result() {
        if (this.offset === this.buffer.length) {
            return this.buffer;
        }
        throw new Error(`Write buffer is not full, offset: ${this.offset}, buffer size: ${this.buffer.length}`);
    }
}
function extractBodyFromVAA(signedVAA) {
    const signatureSize = signedVAA[5];
    const offset = 6 + signatureSize * 66;
    return signedVAA.slice(offset);
}
exports.extractBodyFromVAA = extractBodyFromVAA;
function extractPayloadFromVAA(signedVAA) {
    const signatureSize = signedVAA[5];
    const offset = 6 + signatureSize * 66 + 53;
    return signedVAA.slice(offset);
}
exports.extractPayloadFromVAA = extractPayloadFromVAA;
function extractSequenceFromVAA(signedVAA) {
    const signatureSize = signedVAA[5];
    const offset = 6 + signatureSize * 66 + 44;
    return Buffer.from(signedVAA.slice(offset, offset + 8)).readBigUInt64BE();
}
exports.extractSequenceFromVAA = extractSequenceFromVAA;
function _serializeVAABody(body, payloadSerializer) {
    const writer = new Writer(53);
    writer.writeUInt32BE(body.timestamp);
    writer.writeUInt32BE(body.nonce);
    writer.writeUInt16BE(body.emitterChainId);
    writer.writeUInt16BE(body.targetChainId);
    writer.writeBytes(body.emitterAddress);
    writer.writeUInt64BE(body.sequence);
    writer.writeUInt8(body.consistencyLevel);
    return Buffer.concat([writer.result(), payloadSerializer(body.payload)]);
}
function _serializeVAA(vaa, payloadSerializer) {
    const writer = new Writer(6);
    writer.writeUInt8(vaa.version);
    writer.writeUInt32BE(vaa.guardianSetIndex);
    writer.writeUInt8(vaa.signatures.length);
    const signatures = Buffer.concat(vaa.signatures.map(sig => sig.serialize()));
    return Buffer.concat([writer.result(), signatures, _serializeVAABody(vaa.body, payloadSerializer)]);
}
function _deserializeVAABody(data, payloadDeserializer) {
    const reader = new Reader(data);
    return {
        timestamp: reader.readUInt32BE(),
        nonce: reader.readUInt32BE(),
        emitterChainId: reader.readUInt16BE(),
        targetChainId: reader.readUInt16BE(),
        emitterAddress: reader.readBytes(32),
        sequence: reader.readUInt64BE(),
        consistencyLevel: reader.readUInt8(),
        payload: payloadDeserializer(reader.remain())
    };
}
function _deserializeVAA(data, payloadDeserializer) {
    const reader = new Reader(data);
    const version = reader.readUInt8();
    const guardianSetIndex = reader.readUInt32BE();
    const signatureSize = reader.readUInt8();
    if (signatureSize === 0) {
        throw new Error(`Invalid signature size ${signatureSize}`);
    }
    const signatures = Array.from(Array(signatureSize).keys()).map(() => {
        return Signature.from(reader.readBytes(66));
    });
    const body = _deserializeVAABody(reader.remain(), payloadDeserializer);
    return {
        version,
        guardianSetIndex,
        signatures,
        body
    };
}
function validatePayloadSize(payload, expected, type) {
    if (payload.length !== expected) {
        throw new Error(`Invalid ${type} payload ${array_1.uint8ArrayToHex(payload)}, expected ${expected} bytes`);
    }
}
function validatePayloadId(payloadId, expected, type) {
    if (payloadId !== expected) {
        throw new Error(`Invalid ${type} payload id ${payloadId}, expected ${expected}`);
    }
}
function validateModule(module, expected, type) {
    if (module !== expected) {
        throw new Error(`Invalid ${type} payload module ${module}, expected ${expected}`);
    }
}
function deserializeTransferTokenPayload(payload) {
    const reader = new Reader(payload);
    validatePayloadId(reader.readUInt8(), exports.TransferTokenPayloadId, 'TransferToken');
    const amount = reader.readUInt256BE();
    const originAddress = reader.readBytes(32);
    const originChain = reader.readUInt16BE();
    const targetAddressSize = reader.readUInt16BE();
    const targetAddress = reader.readBytes(targetAddressSize);
    const fee = reader.readUInt256BE();
    validatePayloadSize(payload, 101 + targetAddressSize, 'TransferToken');
    return {
        type: 'TransferToken',
        amount,
        originAddress,
        originChain,
        targetAddress,
        fee
    };
}
exports.deserializeTransferTokenPayload = deserializeTransferTokenPayload;
function serializeTransferTokenPayload(payload) {
    const writer = new Writer(101 + payload.targetAddress.length);
    writer.writeUInt8(exports.TransferTokenPayloadId); // payloadId
    writer.writeUInt256BE(payload.amount);
    writer.writeBytes(payload.originAddress);
    writer.writeUInt16BE(payload.originChain);
    writer.writeUInt16BE(payload.targetAddress.length);
    writer.writeBytes(payload.targetAddress);
    writer.writeUInt256BE(payload.fee);
    return writer.result();
}
exports.serializeTransferTokenPayload = serializeTransferTokenPayload;
function deserializeTransferTokenVAA(data) {
    return _deserializeVAA(data, deserializeTransferTokenPayload);
}
exports.deserializeTransferTokenVAA = deserializeTransferTokenVAA;
function serializeTransferTokenVAA(vaa) {
    return _serializeVAA(vaa, serializeTransferTokenPayload);
}
exports.serializeTransferTokenVAA = serializeTransferTokenVAA;
function bytes32ToUtf8String(bytes) {
    return Buffer.from(bytes).toString('utf8').replace(exports.METADATA_REPLACE, '');
}
exports.bytes32ToUtf8String = bytes32ToUtf8String;
function utf8StringTo32Bytes(str) {
    const buf = Buffer.from(str, 'utf8');
    if (buf.length > 32) {
        throw new Error(`String ${str} exceed 32 bytes`);
    }
    const prefix = Buffer.alloc(32 - buf.length);
    return Buffer.concat([prefix, buf]);
}
function deserializeTransferNFTPayload(payload) {
    const reader = new Reader(payload);
    validatePayloadId(reader.readUInt8(), exports.TransferNFTPayloadId, 'TransferNFT');
    const transferNFT = {
        type: 'TransferNFT',
        originAddress: reader.readBytes(32),
        originChain: reader.readUInt16BE(),
        symbol: bytes32ToUtf8String(reader.readBytes(32)),
        name: bytes32ToUtf8String(reader.readBytes(32)),
        tokenId: reader.readUInt256BE(),
        uri: reader.readBytes(reader.readUInt8()),
        targetAddress: reader.readBytes(32)
    };
    if (reader.remain().length !== 0) {
        throw new Error('Invalid size of transfer NFT VAA');
    }
    return transferNFT;
}
exports.deserializeTransferNFTPayload = deserializeTransferNFTPayload;
function deserializeTransferNFTVAA(data) {
    return _deserializeVAA(data, deserializeTransferNFTPayload);
}
exports.deserializeTransferNFTVAA = deserializeTransferNFTVAA;
function serializeTransferNFTPayload(payload) {
    const writer = new Writer(164 + payload.uri.length);
    writer.writeUInt8(exports.TransferNFTPayloadId); // payload id
    writer.writeBytes(payload.originAddress);
    writer.writeUInt16BE(payload.originChain);
    writer.writeBytes(utf8StringTo32Bytes(payload.symbol));
    writer.writeBytes(utf8StringTo32Bytes(payload.name));
    writer.writeUInt256BE(payload.tokenId);
    writer.writeUInt8(payload.uri.length);
    writer.writeBytes(payload.uri);
    writer.writeBytes(payload.targetAddress);
    return writer.result();
}
exports.serializeTransferNFTPayload = serializeTransferNFTPayload;
function serializeTransferNFTVAA(vaa) {
    return _serializeVAA(vaa, serializeTransferNFTPayload);
}
exports.serializeTransferNFTVAA = serializeTransferNFTVAA;
function deserializeAttestTokenPayload(payload) {
    validatePayloadSize(payload, 100, 'AttestToken');
    const reader = new Reader(payload);
    validatePayloadId(reader.readUInt8(), exports.AttestTokenPayloadId, 'AttestToken');
    return {
        type: 'AttestToken',
        tokenId: reader.readBytes(32),
        tokenChainId: reader.readUInt16BE(),
        decimals: reader.readUInt8(),
        symbol: bytes32ToUtf8String(reader.readBytes(32)),
        name: bytes32ToUtf8String(reader.readBytes(32))
    };
}
exports.deserializeAttestTokenPayload = deserializeAttestTokenPayload;
function deserializeAttestTokenVAA(data) {
    return _deserializeVAA(data, deserializeAttestTokenPayload);
}
exports.deserializeAttestTokenVAA = deserializeAttestTokenVAA;
function serializeAttestTokenPayload(payload) {
    const writer = new Writer(100);
    writer.writeUInt8(exports.AttestTokenPayloadId); // payload id
    writer.writeBytes(payload.tokenId);
    writer.writeUInt16BE(payload.tokenChainId);
    writer.writeUInt8(payload.decimals);
    writer.writeBytes(utf8StringTo32Bytes(payload.symbol));
    writer.writeBytes(utf8StringTo32Bytes(payload.name));
    return writer.result();
}
exports.serializeAttestTokenPayload = serializeAttestTokenPayload;
function serializeAttestTokenVAA(vaa) {
    return _serializeVAA(vaa, serializeAttestTokenPayload);
}
exports.serializeAttestTokenVAA = serializeAttestTokenVAA;
function getContractUpgradeActionIdByModule(module) {
    return module === 'Core' ? exports.CoreContractUpgradeActionId : exports.AppContractUpgradeActionId;
}
function deserializeContractUpgradePayload(data) {
    validatePayloadSize(data, 65, 'ContractUpgrade');
    const reader = new Reader(data);
    const module = reader.readModule();
    const actionId = getContractUpgradeActionIdByModule(module);
    validatePayloadId(reader.readUInt8(), actionId, 'ContractUpgrade');
    const newContractAddress = reader.readBytes(32);
    return {
        type: 'ContractUpgrade',
        module,
        newContractAddress
    };
}
exports.deserializeContractUpgradePayload = deserializeContractUpgradePayload;
function deserializeCoreContractUpgradeVAA(data) {
    return _deserializeVAA(data, (payload) => {
        const decoded = deserializeContractUpgradePayload(payload);
        validateModule(decoded.module, 'Core', 'ContractUpgrade');
        return decoded;
    });
}
exports.deserializeCoreContractUpgradeVAA = deserializeCoreContractUpgradeVAA;
function deserializeTokenBridgeContractUpgradeVAA(data) {
    return _deserializeVAA(data, (payload) => {
        const decoded = deserializeContractUpgradePayload(payload);
        validateModule(decoded.module, 'TokenBridge', 'ContractUpgrade');
        return decoded;
    });
}
exports.deserializeTokenBridgeContractUpgradeVAA = deserializeTokenBridgeContractUpgradeVAA;
function deserializeNFTBridgeContractUpgradeVAA(data) {
    return _deserializeVAA(data, (payload) => {
        const decoded = deserializeContractUpgradePayload(payload);
        validateModule(decoded.module, 'NFTBridge', 'ContractUpgrade');
        return decoded;
    });
}
exports.deserializeNFTBridgeContractUpgradeVAA = deserializeNFTBridgeContractUpgradeVAA;
function serializeContractUpgradePayload(payload) {
    const writer = new Writer(65);
    writer.writeModule(payload.module);
    const actionId = getContractUpgradeActionIdByModule(payload.module);
    writer.writeUInt8(actionId);
    writer.writeBytes(payload.newContractAddress);
    return writer.result();
}
exports.serializeContractUpgradePayload = serializeContractUpgradePayload;
function serializeContractUpgradeVAA(vaa) {
    return _serializeVAA(vaa, serializeContractUpgradePayload);
}
exports.serializeContractUpgradeVAA = serializeContractUpgradeVAA;
function deserializeGuardianSetUpgradePayload(data) {
    const reader = new Reader(data);
    validateModule(reader.readModule(), 'Core', 'GuardianSetUpgrade');
    validatePayloadId(reader.readUInt8(), exports.GuardianSetUpgradeActionId, 'GuardianSetUpgrade');
    const newGuardianSetIndex = reader.readUInt32BE();
    const newGuardianSetSize = reader.readUInt8();
    const newGuardianSet = Array.from(Array(newGuardianSetSize).keys()).map(() => {
        return reader.readBytes(20);
    });
    validatePayloadSize(data, 38 + newGuardianSet.length * 20, 'GuardianSetUpgrade');
    return {
        type: 'GuardianSetUpgrade',
        module: 'Core',
        newGuardianSetIndex,
        newGuardianSet
    };
}
exports.deserializeGuardianSetUpgradePayload = deserializeGuardianSetUpgradePayload;
function deserializeGuardianSetUpgradeVAA(data) {
    return _deserializeVAA(data, deserializeGuardianSetUpgradePayload);
}
exports.deserializeGuardianSetUpgradeVAA = deserializeGuardianSetUpgradeVAA;
function serializeGuardianSetUpgradePayload(payload) {
    const writer = new Writer(38 + payload.newGuardianSet.length * 20);
    writer.writeModule('Core');
    writer.writeUInt8(exports.GuardianSetUpgradeActionId); // action id
    writer.writeUInt32BE(payload.newGuardianSetIndex);
    writer.writeUInt8(payload.newGuardianSet.length);
    payload.newGuardianSet.forEach(guardian => {
        writer.writeBytes(guardian);
    });
    return writer.result();
}
exports.serializeGuardianSetUpgradePayload = serializeGuardianSetUpgradePayload;
function serializeGuardianSetUpgradeVAA(vaa) {
    return _serializeVAA(vaa, serializeGuardianSetUpgradePayload);
}
exports.serializeGuardianSetUpgradeVAA = serializeGuardianSetUpgradeVAA;
function deserializeUpdateMessageFeePayload(data) {
    validatePayloadSize(data, 65, 'UpdateMessageFee');
    const reader = new Reader(data);
    validateModule(reader.readModule(), 'Core', 'UpdateMessageFee');
    validatePayloadId(reader.readUInt8(), exports.UpdateMessageFeeActionId, 'UpdateMessageFee');
    const newMessageFee = reader.readUInt256BE();
    return {
        type: 'UpdateMessageFee',
        module: 'Core',
        newMessageFee
    };
}
exports.deserializeUpdateMessageFeePayload = deserializeUpdateMessageFeePayload;
function deserializeUpdateMessageFeeVAA(data) {
    return _deserializeVAA(data, deserializeUpdateMessageFeePayload);
}
exports.deserializeUpdateMessageFeeVAA = deserializeUpdateMessageFeeVAA;
function serializeUpdateMessageFeePayload(payload) {
    const writer = new Writer(65);
    writer.writeModule('Core');
    writer.writeUInt8(exports.UpdateMessageFeeActionId); // action id
    writer.writeUInt256BE(payload.newMessageFee);
    return writer.result();
}
exports.serializeUpdateMessageFeePayload = serializeUpdateMessageFeePayload;
function serializeUpdateMessageFeeVAA(vaa) {
    return _serializeVAA(vaa, serializeUpdateMessageFeePayload);
}
exports.serializeUpdateMessageFeeVAA = serializeUpdateMessageFeeVAA;
function deserializeTransferFeePayload(data) {
    validatePayloadSize(data, 97, 'TransferFee');
    const reader = new Reader(data);
    validateModule(reader.readModule(), 'Core', 'TransferFee');
    validatePayloadId(reader.readUInt8(), exports.TransferFeeActionId, 'TransferFee');
    return {
        type: 'TransferFee',
        module: 'Core',
        amount: reader.readUInt256BE(),
        recipient: reader.readBytes(32)
    };
}
exports.deserializeTransferFeePayload = deserializeTransferFeePayload;
function deserializeTransferFeeVAA(data) {
    return _deserializeVAA(data, deserializeTransferFeePayload);
}
exports.deserializeTransferFeeVAA = deserializeTransferFeeVAA;
function serializeTransferFeePayload(payload) {
    const writer = new Writer(97);
    writer.writeModule('Core');
    writer.writeUInt8(exports.TransferFeeActionId); // action id
    writer.writeUInt256BE(payload.amount);
    writer.writeBytes(payload.recipient);
    return writer.result();
}
exports.serializeTransferFeePayload = serializeTransferFeePayload;
function serializeTransferFeeVAA(vaa) {
    return _serializeVAA(vaa, serializeTransferFeePayload);
}
exports.serializeTransferFeeVAA = serializeTransferFeeVAA;
function deserializeAlphContractUpgradePayload(data) {
    const reader = new Reader(data);
    const module = reader.readModule();
    if (module === 'NFTBridge') {
        throw new Error('NFTBridge does not supported in Alephium now');
    }
    const actionId = getContractUpgradeActionIdByModule(module);
    validatePayloadId(reader.readUInt8(), actionId, 'AlphContractUpgrade');
    const codeLength = reader.readUInt16BE();
    const newCode = reader.readBytes(codeLength);
    if (35 + codeLength === data.length) {
        return {
            type: 'AlphContractUpgrade',
            module,
            newCode
        };
    }
    const prevStateHash = reader.readBytes(32);
    const newStateLength = reader.readUInt16BE();
    const newState = reader.readBytes(newStateLength);
    validatePayloadSize(data, 35 + codeLength + 32 + 2 + newStateLength, 'AlphContractUpgrade');
    return {
        type: 'AlphContractUpgrade',
        module,
        newCode,
        prevStateHash,
        newState
    };
}
exports.deserializeAlphContractUpgradePayload = deserializeAlphContractUpgradePayload;
function deserializeAlphCoreContractUpgradeVAA(data) {
    return _deserializeVAA(data, (payload) => {
        const decoded = deserializeAlphContractUpgradePayload(payload);
        validateModule(decoded.module, 'Core', 'AlphContractUpgrade');
        return decoded;
    });
}
exports.deserializeAlphCoreContractUpgradeVAA = deserializeAlphCoreContractUpgradeVAA;
function deserializeAlphTokenBridgeContractUpgradeVAA(data) {
    return _deserializeVAA(data, (payload) => {
        const decoded = deserializeAlphContractUpgradePayload(payload);
        validateModule(decoded.module, 'TokenBridge', 'AlphContractUpgrade');
        return decoded;
    });
}
exports.deserializeAlphTokenBridgeContractUpgradeVAA = deserializeAlphTokenBridgeContractUpgradeVAA;
function serializeAlphContractUpgradePayload(payload) {
    const writer0 = new Writer(35);
    writer0.writeModule(payload.module);
    writer0.writeUInt8(getContractUpgradeActionIdByModule(payload.module));
    writer0.writeUInt16BE(payload.newCode.length);
    const buffer0 = Buffer.concat([writer0.result(), payload.newCode]);
    if (payload.prevStateHash === undefined && payload.newState === undefined) {
        return buffer0;
    }
    if (payload.prevStateHash === undefined || payload.newState === undefined) {
        throw new Error('Invalid alephium contract upgrade payload');
    }
    const writer1 = new Writer(34);
    writer1.writeBytes(payload.prevStateHash);
    writer1.writeUInt16BE(payload.newState.length);
    return Buffer.concat([buffer0, writer1.result(), payload.newState]);
}
exports.serializeAlphContractUpgradePayload = serializeAlphContractUpgradePayload;
function serializeAlphContractUpgradeVAA(vaa) {
    return _serializeVAA(vaa, serializeAlphContractUpgradePayload);
}
exports.serializeAlphContractUpgradeVAA = serializeAlphContractUpgradeVAA;
function deserializeRegisterChainPayload(payload) {
    validatePayloadSize(payload, 67, 'RegisterChain');
    const reader = new Reader(payload);
    const module = reader.readModule();
    if (module === 'Core') {
        throw new Error('Invalid RegisterChain module: Core');
    }
    validatePayloadId(reader.readUInt8(), exports.RegisterChainActionId, 'RegisterChain');
    const emitterChainId = reader.readUInt16BE();
    const emitterAddress = reader.readBytes(32);
    return {
        type: 'RegisterChain',
        module,
        emitterChainId,
        emitterAddress
    };
}
exports.deserializeRegisterChainPayload = deserializeRegisterChainPayload;
function deserializeTokenBridgeRegisterChainVAA(data) {
    return _deserializeVAA(data, (payload) => {
        const decoded = deserializeRegisterChainPayload(payload);
        validateModule(decoded.module, 'TokenBridge', 'RegisterChain');
        return decoded;
    });
}
exports.deserializeTokenBridgeRegisterChainVAA = deserializeTokenBridgeRegisterChainVAA;
function deserializeNFTBridgeRegisterChainVAA(data) {
    return _deserializeVAA(data, (payload) => {
        const decoded = deserializeRegisterChainPayload(payload);
        validateModule(decoded.module, 'NFTBridge', 'RegisterChain');
        return decoded;
    });
}
exports.deserializeNFTBridgeRegisterChainVAA = deserializeNFTBridgeRegisterChainVAA;
function serializeRegisterChainPayload(payload) {
    const writer = new Writer(67);
    writer.writeModule(payload.module);
    writer.writeUInt8(exports.RegisterChainActionId); // action id
    writer.writeUInt16BE(payload.emitterChainId);
    writer.writeBytes(payload.emitterAddress);
    return writer.result();
}
exports.serializeRegisterChainPayload = serializeRegisterChainPayload;
function serializeRegisterChainVAA(vaa) {
    return _serializeVAA(vaa, serializeRegisterChainPayload);
}
exports.serializeRegisterChainVAA = serializeRegisterChainVAA;
function deserializeDestroyUnexecutedSequencesPayload(payload) {
    const reader = new Reader(payload);
    validateModule(reader.readModule(), 'TokenBridge', 'DestroyUnexecutedSequences');
    validatePayloadId(reader.readUInt8(), exports.DestroyUnexecutedSequencesActionId, 'DestroyUnexecutedSequences');
    const emitterChainId = reader.readUInt16BE();
    const size = reader.readUInt16BE();
    validatePayloadSize(payload, 37 + size * 8, 'DestroyUnexecutedSequences');
    const indexes = Array.from(Array(size).keys()).map(() => {
        return reader.readUInt64BE();
    });
    return {
        type: 'DestroyUnexecutedSequences',
        module: 'TokenBridge',
        emitterChainId,
        indexes
    };
}
exports.deserializeDestroyUnexecutedSequencesPayload = deserializeDestroyUnexecutedSequencesPayload;
function deserializeDestroyUnexecutedSequencesVAA(data) {
    return _deserializeVAA(data, deserializeDestroyUnexecutedSequencesPayload);
}
exports.deserializeDestroyUnexecutedSequencesVAA = deserializeDestroyUnexecutedSequencesVAA;
function serializeDestroyUnexecutedSequencesPayload(payload) {
    const writer = new Writer(37 + payload.indexes.length * 8);
    writer.writeModule('TokenBridge');
    writer.writeUInt8(exports.DestroyUnexecutedSequencesActionId); // action id
    writer.writeUInt16BE(payload.emitterChainId);
    writer.writeUInt16BE(payload.indexes.length);
    payload.indexes.forEach(index => {
        writer.writeUInt64BE(index);
    });
    return writer.result();
}
exports.serializeDestroyUnexecutedSequencesPayload = serializeDestroyUnexecutedSequencesPayload;
function serializeDestroyUnexecutedSequencesVAA(vaa) {
    return _serializeVAA(vaa, serializeDestroyUnexecutedSequencesPayload);
}
exports.serializeDestroyUnexecutedSequencesVAA = serializeDestroyUnexecutedSequencesVAA;
function deserializeUpdateMinimalConsistencyLevelPayload(payload) {
    validatePayloadSize(payload, 34, 'UpdateMinimalConsistencyLevel');
    const reader = new Reader(payload);
    validateModule(reader.readModule(), 'TokenBridge', 'UpdateMinimalConsistencyLevel');
    validatePayloadId(reader.readUInt8(), exports.UpdateMinimalConsistencyLevelActionId, 'UpdateMinimalConsistencyLevel');
    const newConsistencyLevel = reader.readUInt8();
    return {
        type: 'UpdateMinimalConsistencyLevel',
        module: 'TokenBridge',
        newConsistencyLevel
    };
}
exports.deserializeUpdateMinimalConsistencyLevelPayload = deserializeUpdateMinimalConsistencyLevelPayload;
function deserializeUpdateMinimalConsistencyLevelVAA(data) {
    return _deserializeVAA(data, deserializeUpdateMinimalConsistencyLevelPayload);
}
exports.deserializeUpdateMinimalConsistencyLevelVAA = deserializeUpdateMinimalConsistencyLevelVAA;
function serializeUpdateMinimalConsistencyLevelPayload(payload) {
    const writer = new Writer(34);
    writer.writeModule('TokenBridge');
    writer.writeUInt8(exports.UpdateMinimalConsistencyLevelActionId);
    writer.writeUInt8(payload.newConsistencyLevel);
    return writer.result();
}
exports.serializeUpdateMinimalConsistencyLevelPayload = serializeUpdateMinimalConsistencyLevelPayload;
function serializeUpdateMinimalConsistencyLevelVAA(vaa) {
    return _serializeVAA(vaa, serializeUpdateMinimalConsistencyLevelPayload);
}
exports.serializeUpdateMinimalConsistencyLevelVAA = serializeUpdateMinimalConsistencyLevelVAA;
function deserializeUpdateRefundAddressPayload(payload) {
    const reader = new Reader(payload);
    validateModule(reader.readModule(), 'TokenBridge', 'UpdateRefundAddress');
    validatePayloadId(reader.readUInt8(), exports.UpdateRefundAddressActionId, 'UpdateRefundAddress');
    const size = reader.readUInt16BE();
    validatePayloadSize(payload, 35 + size, 'UpdateRefundAddress');
    const newRefundAddress = reader.readBytes(size);
    return {
        type: 'UpdateRefundAddress',
        module: 'TokenBridge',
        newRefundAddress
    };
}
exports.deserializeUpdateRefundAddressPayload = deserializeUpdateRefundAddressPayload;
function deserializeUpdateRefundAddressVAA(data) {
    return _deserializeVAA(data, deserializeUpdateRefundAddressPayload);
}
exports.deserializeUpdateRefundAddressVAA = deserializeUpdateRefundAddressVAA;
function serializeUpdateRefundAddressPayload(payload) {
    const writer = new Writer(35);
    writer.writeModule('TokenBridge');
    writer.writeUInt8(exports.UpdateRefundAddressActionId);
    writer.writeUInt16BE(payload.newRefundAddress.length);
    return Buffer.concat([writer.result(), payload.newRefundAddress]);
}
exports.serializeUpdateRefundAddressPayload = serializeUpdateRefundAddressPayload;
function serializeUpdateRefundAddressVAA(vaa) {
    return _serializeVAA(vaa, serializeUpdateRefundAddressPayload);
}
exports.serializeUpdateRefundAddressVAA = serializeUpdateRefundAddressVAA;
function deserializeApplicationVAA(signedVAA, payloadId) {
    switch (payloadId) {
        case exports.TransferTokenPayloadId:
            return deserializeTransferTokenVAA(signedVAA);
        case exports.AttestTokenPayloadId:
            return deserializeAttestTokenVAA(signedVAA);
        case exports.TransferNFTPayloadId:
            return deserializeTransferNFTVAA(signedVAA);
        default:
            throw new Error(`Invalid application vaa payload id: ${payloadId}`);
    }
}
function deserializeCoreGovernanceVAA(signedVAA, actionId, targetChainId) {
    switch (actionId) {
        case exports.CoreContractUpgradeActionId:
            if (targetChainId === consts_1.CHAIN_ID_ALEPHIUM) {
                return deserializeAlphCoreContractUpgradeVAA(signedVAA);
            }
            return deserializeCoreContractUpgradeVAA(signedVAA);
        case exports.GuardianSetUpgradeActionId:
            return deserializeGuardianSetUpgradeVAA(signedVAA);
        case exports.UpdateMessageFeeActionId:
            return deserializeUpdateMessageFeeVAA(signedVAA);
        case exports.TransferFeeActionId:
            return deserializeTransferFeeVAA(signedVAA);
        default:
            throw new Error(`Invalid CoreGovernancePayload action id ${actionId}`);
    }
}
function deserializeTokenBridgeGovernanceVAA(signedVAA, actionId, targetChainId) {
    switch (actionId) {
        case exports.RegisterChainActionId:
            return deserializeTokenBridgeRegisterChainVAA(signedVAA);
        case exports.AppContractUpgradeActionId:
            if (targetChainId === consts_1.CHAIN_ID_ALEPHIUM) {
                return deserializeAlphTokenBridgeContractUpgradeVAA(signedVAA);
            }
            return deserializeTokenBridgeContractUpgradeVAA(signedVAA);
        case exports.DestroyUnexecutedSequencesActionId:
            return deserializeDestroyUnexecutedSequencesVAA(signedVAA);
        case exports.UpdateMinimalConsistencyLevelActionId:
            return deserializeUpdateMinimalConsistencyLevelVAA(signedVAA);
        case exports.UpdateRefundAddressActionId:
            return deserializeUpdateRefundAddressVAA(signedVAA);
        default:
            throw new Error(`Invalid TokenBridgeGovernancePayload action id ${actionId}`);
    }
}
function deserializeNFTBridgeGovernanceVAA(signedVAA, actionId) {
    switch (actionId) {
        case exports.RegisterChainActionId:
            return deserializeNFTBridgeRegisterChainVAA(signedVAA);
        case exports.AppContractUpgradeActionId:
            return deserializeNFTBridgeContractUpgradeVAA(signedVAA);
        default:
            throw new Error(`Invalid NFTBridgeGovernancePayload action id ${actionId}`);
    }
}
function deserializeGovernanceVAA(signedVAA, module, actionId, targetChainId) {
    switch (module) {
        case 'Core':
            return deserializeCoreGovernanceVAA(signedVAA, actionId, targetChainId);
        case 'TokenBridge':
            return deserializeTokenBridgeGovernanceVAA(signedVAA, actionId, targetChainId);
        case 'NFTBridge':
            return deserializeNFTBridgeGovernanceVAA(signedVAA, actionId);
    }
}
function deserializeVAA(signedVAA) {
    const body = extractBodyFromVAA(signedVAA);
    const payload = body.slice(53);
    const payloadId = payload[0];
    if (payloadId !== 0) {
        return deserializeApplicationVAA(signedVAA, payloadId);
    }
    const module = bytesToModule(payload.slice(0, 32));
    const actionId = payload[32];
    const targetChainId = Buffer.from(body).readUInt16BE(10);
    return deserializeGovernanceVAA(signedVAA, module, actionId, targetChainId);
}
exports.deserializeVAA = deserializeVAA;
exports.VAAPayloadSerializers = {
    'ContractUpgrade': serializeContractUpgradePayload,
    'GuardianSetUpgrade': serializeGuardianSetUpgradePayload,
    'UpdateMessageFee': serializeUpdateMessageFeePayload,
    'TransferFee': serializeTransferFeePayload,
    'AlphContractUpgrade': serializeAlphContractUpgradePayload,
    'RegisterChain': serializeRegisterChainPayload,
    'DestroyUnexecutedSequences': serializeDestroyUnexecutedSequencesPayload,
    'UpdateMinimalConsistencyLevel': serializeUpdateMinimalConsistencyLevelPayload,
    'UpdateRefundAddress': serializeUpdateRefundAddressPayload,
    'AttestToken': serializeAttestTokenPayload,
    'TransferToken': serializeTransferTokenPayload,
    'TransferNFT': serializeTransferNFTPayload
};
exports.VAAPayloadDeserializers = {
    'ContractUpgrade': deserializeContractUpgradePayload,
    'GuardianSetUpgrade': deserializeGuardianSetUpgradePayload,
    'UpdateMessageFee': deserializeUpdateMessageFeePayload,
    'TransferFee': deserializeTransferFeePayload,
    'AlphContractUpgrade': deserializeAlphContractUpgradePayload,
    'RegisterChain': deserializeRegisterChainPayload,
    'DestroyUnexecutedSequences': deserializeDestroyUnexecutedSequencesPayload,
    'UpdateMinimalConsistencyLevel': deserializeUpdateMinimalConsistencyLevelPayload,
    'UpdateRefundAddress': deserializeUpdateRefundAddressPayload,
    'AttestToken': deserializeAttestTokenPayload,
    'TransferToken': deserializeTransferTokenPayload,
    'TransferNFT': deserializeTransferNFTPayload
};
function serializeVAABody(body) {
    const serializer = exports.VAAPayloadSerializers[body.payload.type];
    return _serializeVAABody(body, serializer);
}
exports.serializeVAABody = serializeVAABody;
function serializeVAA(vaa) {
    const serializer = exports.VAAPayloadSerializers[vaa.body.payload.type];
    return _serializeVAA(vaa, serializer);
}
exports.serializeVAA = serializeVAA;
function signVAABody(keys, body) {
    const hash = utils_1.keccak256(utils_1.keccak256(serializeVAABody(body))).slice(2);
    const ec = new elliptic.ec("secp256k1");
    return keys.map((k, index) => {
        const key = ec.keyFromPrivate(k);
        const sig = key.sign(hash, { canonical: true });
        const signature = [
            sig.r.toString(16).padStart(64, '0'),
            sig.s.toString(16).padStart(64, '0'),
            sig.recoveryParam.toString(16).padStart(2, '0')
        ].join('');
        return new Signature(index, Buffer.from(signature, 'hex'));
    });
}
exports.signVAABody = signVAABody;
