Logo
Nuevos usuarios de RPC: 35% de descuento el primer mesVer oferta
OnFinality Learn
Solución de problemas de RPC14 min de lectura

Replacement Transaction Underpriced: Cómo solucionar transacciones EVM atascadas

Diagnostica y resuelve el error 'replacement transaction underpriced' entendiendo las reglas de reemplazo del mempool y ejecutando un aumento de comisión o una cancelación correctos.

TL;DR

El error 'replacement transaction underpriced' significa que tu nodo rechazó una segunda transacción porque usaba el mismo nonce que una transacción existente en el pool, pero no aumentó la comisión lo suficiente para cumplir con el umbral mínimo de incremento del cliente. Es un problema de comisión, no de nonce. Para resolverlo, inspecciona la transacción atascada con eth_getTransactionByHash, verifica el nonce pendiente con eth_getTransactionCount y luego aumenta la comisión (mismo nonce, maxFeePerGas y maxPriorityFeePerGas más altos), cancélala (mismo nonce, auto-transferencia de valor 0 con comisión aumentada) o espera si la comisión ya es adecuada. Calcula siempre la comisión de reemplazo a partir de la base fee actual y las estimaciones de priority fee en lugar de adivinar.

Qué significa realmente 'Replacement Transaction Underpriced'

Cuando envías una transacción con eth_sendRawTransaction, el nodo comprueba si ya existe otra transacción del mismo remitente con el mismo nonce en su mempool. Si existe, el nodo trata tu nueva transacción como un reemplazo y aplica una política de reemplazo. El error 'replacement transaction underpriced' se devuelve cuando la comisión de la nueva transacción no supera la comisión de la transacción existente en el porcentaje mínimo de incremento requerido por el cliente. Esto es un rechazo por comisión, no por nonce. El nonce es correcto; el precio no es lo suficientemente agresivo.

La especificación JSON-RPC de Ethereum define eth_sendRawTransaction como el envío de una transacción firmada a la red. No define reglas de reemplazo; esas son específicas de cada cliente. Geth, por ejemplo, documenta un umbral predeterminado de incremento de precio (comúnmente 10% tanto para la propina como para el límite de comisión), pero este valor es configurable y varía según el cliente y la versión. Trata siempre el umbral exacto como 'documentado / varía según el cliente' y verifícalo con la configuración o documentación de tu nodo. Como referencia, consulta la documentación del pool de transacciones de Geth.

Como el reemplazo es rechazado, tu transacción original permanece en el pool. Si esa transacción original está atascada debido a una comisión baja, ahora estás en un bucle: necesitas reemplazarla, pero tu reemplazo debe tener un precio lo suficientemente alto como para superar la transacción antigua y satisfacer la regla de incremento del cliente.

  • Mismo remitente + mismo nonce = intento de reemplazo.
  • Motivo del rechazo: la nueva comisión no supera la comisión antigua en el incremento mínimo del cliente.
  • La transacción original permanece en el mempool; nada se cancela automáticamente.

Secuencia de diagnóstico: confirma que la transacción está atascada y lee sus parámetros de comisión

Antes de reemplazar nada, confirma que la transacción está realmente atascada y no ya minada. Usa eth_getTransactionByHash con el hash de la transacción. Si el resultado es null, es posible que la transacción haya sido descartada por completo del mempool. Si el resultado contiene un blockNumber, la transacción ya está minada y no se necesita reemplazo. Si blockNumber es null y la transacción está presente, está pendiente en el pool. Como referencia, consulta la documentación de la API JSON-RPC de Ethereum.

A continuación, lee el nonce pendiente de la cuenta con eth_getTransactionCount(address, 'pending'). Esto te indica el siguiente nonce que la red espera de esta cuenta, incluidas las transacciones pendientes. Compáralo con el nonce de la transacción atascada. Si el nonce pendiente es mayor que el nonce atascado, puede haber un hueco o una cola de transacciones detrás de la atascada. Si el nonce pendiente es igual al nonce atascado, la transacción atascada es la cabeza de la cola y debe resolverse primero.

Lee también maxFeePerGas y maxPriorityFeePerGas de la transacción atascada (para transacciones EIP-1559) o gasPrice (para transacciones legacy). Estos valores son tu línea base. Tu reemplazo debe superarlos en el umbral de incremento del cliente y además ser competitivo con el mercado actual. Para profundizar en la estimación de comisiones, consulta eth_feeHistory y estimación de comisiones.

  • eth_getTransactionByHash: comprueba blockNumber (null = pendiente, no null = minada).
  • eth_getTransactionCount(address, 'pending'): obtén el siguiente nonce utilizable.
  • Lee maxFeePerGas y maxPriorityFeePerGas de la transacción atascada.

Por qué se atascan las transacciones: dinámica del mercado de comisiones y límites de EIP-1559

Una transacción se atasca cuando su comisión está por debajo de lo que el mercado está dispuesto a pagar por su inclusión. Bajo EIP-1559, una transacción especifica un maxFeePerGas y un maxPriorityFeePerGas. La comisión efectiva pagada es min(maxFeePerGas, baseFee + maxPriorityFeePerGas). Si la base fee sube por encima de tu maxFeePerGas menos la priority fee, tu transacción se vuelve no minable porque el protocolo no te permite pagar más allá de tu límite. Permanece en el pool hasta que la base fee baje o la reemplaces. Como referencia, consulta la especificación EIP-1559.

Otro escenario es una transacción descartada. Si el mempool está lleno o la transacción ha sido expulsada debido a una comisión baja, eth_getTransactionByHash puede devolver null. En ese caso, el nonce sigue libre y puedes simplemente enviar una nueva transacción con el mismo nonce y una comisión más alta. Esto no es un reemplazo en sentido estricto porque no hay nada que reemplazar, pero la gestión del nonce es idéntica.

Entender el mempool te ayuda a decidir si esperar o reemplazar. La guía Leer el mempool de Ethereum explica cómo inspeccionar el contenido del pool y las transacciones pendientes.

  • Atascada: comisión por debajo del precio de liquidación del mercado o maxFeePerGas demasiado bajo para la base fee actual.
  • Descartada: transacción expulsada; el nonce vuelve a estar libre.
  • Límite EIP-1559: la comisión efectiva no puede superar maxFeePerGas.

Tres rutas de recuperación: aumentar, cancelar o esperar

La acción correcta depende de si la transacción sigue en el pool, de si el nonce sigue libre y de si el mercado de comisiones actual justifica esperar. Usa la tabla de decisión a continuación para asignar tu situación a la ruta correcta.

AUMENTAR: Si la transacción sigue pendiente y quieres que se ejecute, reenvía el mismo nonce con un maxPriorityFeePerGas y un maxFeePerGas sustancialmente más altos. La nueva comisión debe superar la comisión antigua en el umbral de incremento del cliente y además ser competitiva con el mercado actual. Esta es la solución más común.

CANCELAR: Si ya no quieres que la transacción se ejecute, reenvía el mismo nonce con una auto-transferencia de valor 0 (a tu propia dirección) con la misma comisión aumentada. Este reemplazo se incluirá y consumirá el nonce, cancelando efectivamente la original. La transacción original se descartará del pool una vez que el reemplazo sea minado.

ESPERAR: Si la comisión de la transacción es genuinamente adecuada para las condiciones actuales y el pool simplemente está profundo, esperar puede ser la mejor opción. Reemplazar con una comisión aún más alta podría pagar de más innecesariamente. Monitorea la base fee y la posición de tu transacción en el pool.

  • Sigue en el pool, nonce libre: AUMENTAR o CANCELAR con el mismo nonce.
  • Fuera del pool, nonce libre: envía una nueva transacción con el mismo nonce y una comisión más alta.
  • Nonce consumido: la transacción ya fue minada; no se necesita acción.
  • Nonce aún libre pero transacción pendiente: se requiere reemplazo.

Tabla de decisión: del síntoma a la acción

Usa esta tabla para determinar rápidamente la ruta de recuperación correcta. Las entradas clave son el resultado de eth_getTransactionByHash (presente o null) y la comparación entre el nonce de la transacción atascada y el nonce pendiente de eth_getTransactionCount.

Si la transacción está presente y su nonce es igual al nonce pendiente, es la cabeza de la cola. Debes reemplazarla para desbloquear las transacciones posteriores. Si su nonce es menor que el nonce pendiente, puede haber otras transacciones delante de ella, pero reemplazarla sigue siendo válido si usas el mismo nonce.

Si la transacción es null y el nonce pendiente es igual al nonce atascado, el nonce está libre. Puedes enviar una nueva transacción con ese nonce y una comisión más alta. Si el nonce pendiente es mayor que el nonce atascado, el nonce ha sido consumido por otra transacción y la transacción atascada es irrelevante.

  • Presente + nonce == nonce pendiente: reemplaza con el mismo nonce y una comisión más alta.
  • Presente + nonce < nonce pendiente: reemplaza con el mismo nonce y una comisión más alta; comprueba si hay huecos.
  • Null + nonce == nonce pendiente: envía una nueva transacción con el mismo nonce y una comisión más alta.
  • Null + nonce < nonce pendiente: el nonce ya fue consumido; no se necesita acción.

Cómo calcular una comisión de reemplazo válida

No adivines la comisión de reemplazo. Lee la base fee actual y una estimación de priority fee de la red. Puedes usar eth_feeHistory o eth_maxPriorityFeePerGas. Luego establece el maxPriorityFeePerGas y el maxFeePerGas de tu reemplazo estrictamente por encima tanto de los valores de la transacción antigua (al menos en el umbral de incremento del cliente) como de las estimaciones actuales del mercado.

Para EIP-1559, una fórmula segura es: newMaxPriorityFeePerGas = max(oldMaxPriorityFeePerGas * (1 + bump), currentPriorityFeeEstimate). newMaxFeePerGas = max(oldMaxFeePerGas * (1 + bump), currentBaseFee * 2 + newMaxPriorityFeePerGas). El factor de incremento es específico del cliente; un valor predeterminado común es 10%, pero verifícalo con tu nodo. Redondea siempre hacia arriba para evitar quedar justo por debajo del umbral.

Si estás usando una transacción legacy con gasPrice, se aplica la misma lógica: newGasPrice = max(oldGasPrice * (1 + bump), currentGasPriceEstimate).

  • Lee la base fee actual y la estimación de priority fee.
  • Aplica el factor de incremento a los valores de comisión antiguos.
  • Toma el máximo entre la comisión antigua incrementada y la comisión actual del mercado.

Ejemplo ejecutable en Node.js: inspeccionar, aumentar y enviar

Este ejemplo usa ethers.js v6 para inspeccionar una transacción atascada, calcular una comisión de reemplazo y enviar un aumento con el mismo nonce. Asume que tienes el hash de la transacción atascada y la clave privada del remitente. Reemplaza la URL RPC con el endpoint de tu proveedor. Para endpoints confiables, consulta la guía de endpoints RPC (RPC Assistant).

El código primero obtiene la transacción atascada y el nonce pendiente. Luego calcula nuevos valores de comisión basados en las comisiones de la transacción antigua y las condiciones actuales de la red. Finalmente, envía una nueva transacción con el mismo nonce y las comisiones aumentadas. Si el reemplazo es rechazado con 'replacement transaction underpriced', aumenta el factor de incremento y reintenta.

const { ethers } = require('ethers');

async function bumpStuckTransaction(rpcUrl, privateKey, stuckTxHash) {
  const provider = new ethers.JsonRpcProvider(rpcUrl);
  const wallet = new ethers.Wallet(privateKey, provider);

  // 1. Fetch the stuck transaction
  const stuckTx = await provider.getTransaction(stuckTxHash);
  if (!stuckTx) {
    console.log('Transaction not found in mempool. It may be dropped or mined.');
    return;
  }
  if (stuckTx.blockNumber) {
    console.log('Transaction already mined in block', stuckTx.blockNumber);
    return;
  }

  // 2. Get pending nonce
  const pendingNonce = await provider.getTransactionCount(wallet.address, 'pending');
  console.log('Stuck nonce:', stuckTx.nonce, 'Pending nonce:', pendingNonce);

  // 3. Compute replacement fees
  const feeData = await provider.getFeeData();
  const bumpFactor = 1.2; // 20% bump; adjust based on client threshold
  const oldMaxPriority = stuckTx.maxPriorityFeePerGas || 0n;
  const oldMaxFee = stuckTx.maxFeePerGas || stuckTx.gasPrice || 0n;

  const newMaxPriority = oldMaxPriority * BigInt(Math.floor(bumpFactor * 100)) / 100n;
  const newMaxFee = oldMaxFee * BigInt(Math.floor(bumpFactor * 100)) / 100n;

  const finalMaxPriority = newMaxPriority > (feeData.maxPriorityFeePerGas || 0n) ? newMaxPriority : feeData.maxPriorityFeePerGas;
  const finalMaxFee = newMaxFee > (feeData.maxFeePerGas || 0n) ? newMaxFee : feeData.maxFeePerGas;

  console.log('Replacement fees:', { maxPriorityFeePerGas: finalMaxPriority, maxFeePerGas: finalMaxFee });

  // 4. Send replacement with same nonce
  const tx = await wallet.sendTransaction({
    to: stuckTx.to,
    value: stuckTx.value,
    data: stuckTx.data,
    nonce: stuckTx.nonce,
    maxPriorityFeePerGas: finalMaxPriority,
    maxFeePerGas: finalMaxFee,
    gasLimit: stuckTx.gasLimit,
    chainId: (await provider.getNetwork()).chainId
  });

  console.log('Replacement sent:', tx.hash);
  await tx.wait();
  console.log('Replacement mined');
}

// Usage:
// bumpStuckTransaction('https://your-rpc-endpoint', '0x...', '0x...');

Manejo del error 'Replacement Underpriced' en un bucle de reintentos

Si tu reemplazo es rechazado con 'replacement transaction underpriced', significa que tu incremento fue insuficiente. El umbral de incremento requerido por el nodo es mayor que tu aumento, o la comisión actual del mercado es mayor que tu nueva comisión. En ese caso, aumenta el factor de incremento y reintenta. Un patrón común es empezar con un incremento del 10%, luego 20%, luego 50%, hasta que el reemplazo sea aceptado.

Ten en cuenta que cada reintento debe usar el mismo nonce. Si accidentalmente usas un nuevo nonce, creas un hueco en la secuencia de nonces y todas las transacciones posteriores quedarán atascadas detrás del hueco. Este es un error común. Verifica siempre el nonce antes de enviar.

Si usas ethers.js, ten en cuenta que la biblioteca puede rellenar automáticamente los campos de comisión si no los especificas. Al reemplazar, establece siempre explícitamente maxFeePerGas y maxPriorityFeePerGas con tus valores calculados para evitar que la biblioteca use estimaciones obsoletas.

  • Reintenta con incrementos mayores hasta que sea aceptado.
  • Usa siempre el mismo nonce para los reemplazos.
  • Establece explícitamente los campos de comisión para evitar estimaciones obsoletas.

Errores comunes y consideraciones específicas de la red

Usar un nuevo nonce en lugar del mismo es el error más dañino. Crea un hueco de nonce, y la red no minará ninguna transacción con un nonce superior hasta que se rellene el hueco. Esto puede dar lugar a una cola de transacciones atascadas. Para una explicación detallada de la gestión de nonces bajo concurrencia, consulta Gestión de nonces EVM bajo concurrencia.

Aumentar sin refrescar la base fee es otro error común. Si la base fee ha subido desde que enviaste la transacción por primera vez, tu maxFeePerGas aumentado puede seguir estando por debajo de la base fee actual más la priority fee, lo que hace que el reemplazo no sea minable. Obtén siempre datos de comisión frescos antes de calcular el reemplazo.

En algunas redes, el modelo de comisiones es diferente. Los secuenciadores de capa 2 pueden tener semánticas de reemplazo distintas, y algunas cadenas usan un modelo legacy de gasPrice sin EIP-1559. En cadenas estilo BSC, el gasPrice es el único parámetro de comisión. Verifica siempre las reglas de reemplazo de la red específica. Para la red principal de Ethereum, la página de la red Ethereum ofrece una visión general de los métodos RPC compatibles.

Los mempools privados y los relays MEV ofrecen una ruta alternativa. Enviar una transacción a través de un relay privado puede evitar el mempool público y las reglas de reemplazo, pero es un flujo de trabajo especializado y no una solución general.

  • Un nuevo nonce crea un hueco y bloquea a las sucesoras.
  • Una base fee obsoleta puede hacer que una transacción aumentada no sea minable.
  • Las cadenas L2 y las que no usan EIP-1559 tienen reglas de reemplazo diferentes.
  • Los mempools privados evitan las políticas de reemplazo del pool público.

Limitaciones: reorganizaciones, huecos de nonce y diferencias entre secuenciadores

Las reorganizaciones pueden complicar el reemplazo. Si un reemplazo es minado y luego ocurre una reorganización, la transacción original puede reaparecer en el pool. En ese caso, es posible que tengas que reemplazar de nuevo. Monitorea siempre el estado de la transacción después de un reemplazo.

Los huecos de nonce son un riesgo persistente. Si tienes un hueco, no se minará ninguna transacción con un nonce superior hasta que se rellene. Debes enviar una transacción con el nonce faltante o reemplazar la transacción que creó el hueco. Herramientas como eth_getTransactionCount con 'pending' ayudan a identificar huecos.

En L2 y otras redes basadas en secuenciadores, las semánticas de reemplazo pueden diferir. Algunos secuenciadores procesan transacciones en orden FIFO y pueden no admitir en absoluto el reemplazo basado en comisiones. Consulta siempre la documentación de la red. Para la fiabilidad general de RPC, consulta Manejo de timeouts de RPC en Ethereum.

  • Las reorganizaciones pueden resucitar transacciones reemplazadas.
  • Los huecos de nonce bloquean todas las transacciones con nonce superior.
  • Los secuenciadores L2 pueden no admitir el reemplazo basado en comisiones.

Próximos pasos: monitoreo, automatización y selección de proveedor

Después de resolver una transacción atascada, considera configurar un monitoreo que te avise cuando las transacciones permanezcan pendientes más allá de un umbral. Esto puede ayudarte a actuar antes de que el mercado de comisiones se mueva demasiado. Puedes usar eth_getTransactionByHash en un bucle de sondeo o suscribirte a transacciones pendientes vía WebSocket.

Para sistemas en producción, automatiza la lógica de aumento con un bucle de reintentos que incremente la comisión hasta que el reemplazo sea aceptado. Limita siempre la comisión máxima para evitar pagar de más. Prueba tu lógica en una testnet antes de desplegarla en la red principal.

Elegir un proveedor RPC confiable es crítico para el envío y reemplazo oportunos de transacciones. OnFinality ofrece servicio de API con endpoints para Ethereum y otras redes. Para detalles de precios, consulta Precios de RPC. Para explorar más guías de solución de problemas, visita el centro de aprendizaje de OnFinality.

  • Monitorea las transacciones pendientes con sondeo o WebSocket.
  • Automatiza la lógica de aumento con un bucle de reintentos con límite.
  • Usa un proveedor RPC confiable para un envío consistente.

Nunca te preocupes por la infraestructura nuevamente

OnFinality elimina la carga pesada de DevOps para que puedas construir de forma más inteligente y rápida.

Comenzar