viem
Version:
127 lines • 6.08 kB
JavaScript
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 { isAddress } from '../../utils/address/isAddress.js';
import { concatHex } from '../../utils/data/concat.js';
import { trim } from '../../utils/data/trim.js';
import { toHex } from '../../utils/encoding/toHex.js';
import { toRlp } from '../../utils/encoding/toRlp.js';
import { serializeAccessList } from '../../utils/transaction/serializeAccessList.js';
import { serializeTransaction as serializeTransaction_, } from '../../utils/transaction/serializeTransaction.js';
import { isCIP42, isCIP64, isEmpty, isPresent } from './utils.js';
export const serializeTransaction = (tx, signature) => {
if (isCIP64(tx))
return serializeTransactionCIP64(tx, signature);
if (isCIP42(tx))
return serializeTransactionCIP42(tx, signature);
return serializeTransaction_(tx, signature);
};
export const serializers = {
transaction: serializeTransaction,
};
// There shall be a typed transaction with the code 0x7c that has the following format:
// 0x7c || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, feecurrency, gatewayFeeRecipient, gatewayfee, destination, amount, data, access_list, signature_y_parity, signature_r, signature_s]).
// This will be in addition to the type 0x02 transaction as specified in EIP-1559.
function serializeTransactionCIP42(transaction, signature) {
assertTransactionCIP42(transaction);
const { chainId, gas, nonce, to, value, maxFeePerGas, maxPriorityFeePerGas, accessList, feeCurrency, gatewayFeeRecipient, gatewayFee, data, } = transaction;
const serializedTransaction = [
toHex(chainId),
nonce ? toHex(nonce) : '0x',
maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x',
maxFeePerGas ? toHex(maxFeePerGas) : '0x',
gas ? toHex(gas) : '0x',
feeCurrency ?? '0x',
gatewayFeeRecipient ?? '0x',
gatewayFee ? toHex(gatewayFee) : '0x',
to ?? '0x',
value ? toHex(value) : '0x',
data ?? '0x',
serializeAccessList(accessList),
];
if (signature) {
serializedTransaction.push(signature.v === 27n ? '0x' : toHex(1), // yParity
trim(signature.r), trim(signature.s));
}
return concatHex([
'0x7c',
toRlp(serializedTransaction),
]);
}
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,
];
if (signature) {
serializedTransaction.push(signature.v === 27n ? '0x' : toHex(1), // yParity
trim(signature.r), trim(signature.s));
}
return concatHex([
'0x7b',
toRlp(serializedTransaction),
]);
}
// maxFeePerGas must be less than 2^256 - 1
const MAX_MAX_FEE_PER_GAS = 2n ** 256n - 1n;
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