import { maxUint256 } from '../constants/number.js';
import { InvalidAddressError } from '../errors/address.js';
import { BaseError } from '../errors/base.js';
import { InvalidChainIdError } from '../errors/chain.js';
import { FeeCapTooHighError, TipAboveFeeCapError } from '../errors/node.js';
import { serializeTransaction as serializeTransaction_op } from '../op-stack/serializers.js';
import { isAddress } from '../utils/address/isAddress.js';
import { concatHex } from '../utils/data/concat.js';
import { toHex } from '../utils/encoding/toHex.js';
import { toRlp } from '../utils/encoding/toRlp.js';
import { serializeAccessList } from '../utils/transaction/serializeAccessList.js';
import { toYParitySignatureArray } from '../utils/transaction/serializeTransaction.js';
import { isCIP64, isEmpty, isPresent } from './utils.js';
export function serializeTransaction(transaction, signature) {
    if (isCIP64(transaction))
        return serializeTransactionCIP64(transaction, signature);
    return serializeTransaction_op(transaction, signature);
}
export const serializers = {
    transaction: serializeTransaction,
};
function serializeTransactionCIP64(transaction, signature) {
    assertTransactionCIP64(transaction);
    const { chainId, gas, nonce, to, value, maxFeePerGas, maxPriorityFeePerGas, accessList, feeCurrency, data, } = transaction;
    const serializedTransaction = [
        toHex(chainId),
        nonce ? toHex(nonce) : '0x',
        maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x',
        maxFeePerGas ? toHex(maxFeePerGas) : '0x',
        gas ? toHex(gas) : '0x',
        to ?? '0x',
        value ? toHex(value) : '0x',
        data ?? '0x',
        serializeAccessList(accessList),
        feeCurrency,
        ...toYParitySignatureArray(transaction, signature),
    ];
    return concatHex([
        '0x7b',
        toRlp(serializedTransaction),
    ]);
}
// maxFeePerGas must be less than maxUint256
const MAX_MAX_FEE_PER_GAS = maxUint256;
export function assertTransactionCIP42(transaction) {
    const { chainId, maxPriorityFeePerGas, gasPrice, maxFeePerGas, to, feeCurrency, gatewayFee, gatewayFeeRecipient, } = transaction;
    if (chainId <= 0)
        throw new InvalidChainIdError({ chainId });
    if (to && !isAddress(to))
        throw new InvalidAddressError({ address: to });
    if (gasPrice)
        throw new BaseError('`gasPrice` is not a valid CIP-42 Transaction attribute.');
    if (isPresent(maxFeePerGas) && maxFeePerGas > MAX_MAX_FEE_PER_GAS)
        throw new FeeCapTooHighError({ maxFeePerGas });
    if (isPresent(maxPriorityFeePerGas) &&
        isPresent(maxFeePerGas) &&
        maxPriorityFeePerGas > maxFeePerGas)
        throw new TipAboveFeeCapError({ maxFeePerGas, maxPriorityFeePerGas });
    if ((isPresent(gatewayFee) && isEmpty(gatewayFeeRecipient)) ||
        (isPresent(gatewayFeeRecipient) && isEmpty(gatewayFee))) {
        throw new BaseError('`gatewayFee` and `gatewayFeeRecipient` must be provided together.');
    }
    if (isPresent(feeCurrency) && !isAddress(feeCurrency)) {
        throw new BaseError('`feeCurrency` MUST be a token address for CIP-42 transactions.');
    }
    if (isPresent(gatewayFeeRecipient) && !isAddress(gatewayFeeRecipient)) {
        throw new InvalidAddressError(gatewayFeeRecipient);
    }
    if (isEmpty(feeCurrency) && isEmpty(gatewayFeeRecipient)) {
        throw new BaseError('Either `feeCurrency` or `gatewayFeeRecipient` must be provided for CIP-42 transactions.');
    }
}
export function assertTransactionCIP64(transaction) {
    const { chainId, maxPriorityFeePerGas, gasPrice, maxFeePerGas, to, feeCurrency, } = transaction;
    if (chainId <= 0)
        throw new InvalidChainIdError({ chainId });
    if (to && !isAddress(to))
        throw new InvalidAddressError({ address: to });
    if (gasPrice)
        throw new BaseError('`gasPrice` is not a valid CIP-64 Transaction attribute.');
    if (isPresent(maxFeePerGas) && maxFeePerGas > MAX_MAX_FEE_PER_GAS)
        throw new FeeCapTooHighError({ maxFeePerGas });
    if (isPresent(maxPriorityFeePerGas) &&
        isPresent(maxFeePerGas) &&
        maxPriorityFeePerGas > maxFeePerGas)
        throw new TipAboveFeeCapError({ maxFeePerGas, maxPriorityFeePerGas });
    if (isPresent(feeCurrency) && !isAddress(feeCurrency)) {
        throw new BaseError('`feeCurrency` MUST be a token address for CIP-64 transactions.');
    }
    if (isEmpty(feeCurrency)) {
        throw new BaseError('`feeCurrency` must be provided for CIP-64 transactions.');
    }
}
//# sourceMappingURL=serializers.js.map