Las comisiones de transacción de Polkadot son calculadas por el pallet transaction-payment como la suma de una comisión base, una comisión por longitud y una comisión por weight. La comisión por weight se deriva del weight calculado del extrinsic, que depende de la ejecución y del estado actual, y se multiplica por un multiplicador de comisión dinámico que aumenta cuando los bloques están llenos y disminuye cuando no lo están. El método RPC payment_queryInfo devuelve una estimación parcial de la comisión para un extrinsic completamente construido y firmado, mientras que payment_queryFeeDetails proporciona un desglose por componente. Debido a que la estimación se calcula con el estado y el multiplicador actuales, es una predicción, no una garantía; los clientes deben volver a estimar cerca del momento de envío y tener en cuenta el manejo de lotes y propinas.
Estimación de comisiones en Polkadot y el pallet transaction-payment
Las comisiones de transacción de Polkadot son calculadas por el pallet transaction-payment, que suma tres componentes: una comisión base, una comisión por longitud proporcional al tamaño codificado del extrinsic y una comisión por weight derivada del weight calculado de la llamada. Esta fórmula está documentada en la página Calcular comisiones de transacción de la documentación para desarrolladores de Polkadot, que es la fuente autorizada para los componentes de la comisión y el pallet que los calcula.
La comisión base es un monto fijo por extrinsic, la comisión por longitud escala con la longitud en bytes del extrinsic codificado, y la comisión por weight es el producto del weight calculado y un factor de conversión de weight a comisión, multiplicado además por un multiplicador de comisión dinámico. El multiplicador se ajusta según la ocupación de los bloques: aumenta cuando los bloques están consistentemente llenos y disminuye cuando no lo están, como se describe en la documentación de Polkadot sobre comisiones de transacción.
Debido a que el componente de weight depende de la ejecución y del estado actual, la comisión total no puede predecirse solo a partir de la llamada. Por eso existen los métodos RPC payment_queryInfo y payment_queryFeeDetails: simulan el extrinsic contra el estado actual para devolver una estimación.
- Comisión base: fija por extrinsic.
- Comisión por longitud: proporcional al tamaño codificado del extrinsic.
- Comisión por weight: weight calculado × factor de weight a comisión × multiplicador dinámico.
Weight V2: weight bidimensional y su impacto en las comisiones
Weight V2 introdujo un modelo bidimensional con refTime (tiempo de referencia) y proofSize (tamaño de la prueba). refTime representa el tiempo computacional, mientras que proofSize representa el tamaño de la prueba requerida para la operación. Ambas dimensiones se usan para calcular la comisión por weight, como se documenta en la documentación de Substrate sobre weights y en la documentación de Polkadot sobre Weight V2.
El weight de una llamada no se conoce hasta que se ejecuta, porque depende de las lecturas y escrituras de almacenamiento realizadas. Por ejemplo, una transferencia puede tener un weight diferente según si la cuenta destinataria ya existe. Por lo tanto, el componente de weight de la comisión no puede predecirse solo a partir de la llamada sin ejecución.
El método payment_queryInfo simula el extrinsic para calcular el weight y devuelve la comisión parcial. Por eso requiere un extrinsic completamente construido y firmado: la firma forma parte del extrinsic codificado, y el cálculo del weight puede depender de la longitud de la firma y de los datos de la llamada.
- refTime: tiempo computacional.
- proofSize: tamaño de la prueba.
- El weight se determina en la ejecución, no solo a partir de la llamada.
payment_queryInfo: parámetros de solicitud y campos de respuesta
El método payment_queryInfo acepta un único parámetro: el extrinsic completamente construido y firmado como una cadena hexadecimal. Según la referencia JSON-RPC de la API de Polkadot.js, el método devuelve una comisión parcial y, cuando está presente, el weight del extrinsic. La comisión parcial es la comisión estimada para el extrinsic, excluyendo cualquier propina.
Llamar a payment_queryInfo con una llamada sin firmar o antes de firmar falla porque el hex del extrinsic debe incluir la firma. El método simula el extrinsic tal como se incluiría en un bloque, y la firma forma parte de esa simulación. Si pasas un extrinsic sin firmar, el método devolverá un error, normalmente indicando que el extrinsic es inválido o no se puede decodificar.
La respuesta incluye la comisión parcial como una cadena que representa el monto en la unidad más pequeña (por ejemplo, Planck para DOT). También puede incluir el weight, lo cual es útil para entender el componente de weight. Sin embargo, la comisión parcial ya incluye la comisión por weight, por lo que no necesitas calcularla por separado.
- Parámetro: hex del extrinsic firmado.
- Devuelve: comisión parcial (cadena) y opcionalmente weight.
- Falla si el extrinsic no está firmado o está mal formado.
payment_queryFeeDetails: desglose de comisión por componente
El método payment_queryFeeDetails proporciona una respuesta más rica que payment_queryInfo: devuelve la comisión desglosada en sus componentes: base, len, adjustedWeight y tip. Esto permite a un cliente ver exactamente de dónde proviene el costo, como se documenta en la referencia JSON-RPC de la API de Polkadot.js.
El componente adjustedWeight es la comisión por weight después de aplicar el multiplicador de comisión dinámico. La propina (tip) es el monto adicional opcional que el remitente incluyó para priorizar la transacción. Los componentes base y len son las comisiones fija y por longitud, respectivamente.
Se recomienda usar payment_queryFeeDetails cuando necesitas entender la composición de la comisión o cuando quieres mostrar un desglose a los usuarios. Acepta el mismo parámetro que payment_queryInfo: el hex del extrinsic firmado.
- Devuelve: base, len, adjustedWeight, tip.
- adjustedWeight incluye el multiplicador dinámico.
- Mismo parámetro que payment_queryInfo.
Estimaciones dependientes del estado y el multiplicador de comisión dinámico
La comisión por weight se multiplica por un multiplicador de comisión dinámico que se ajusta según la ocupación de los bloques. Cuando los bloques están llenos, el multiplicador aumenta, incrementando la comisión por weight; cuando no están llenos, disminuye. Este mecanismo se describe en la documentación de Polkadot sobre comisiones de transacción.
Debido a que el multiplicador cambia con el tiempo, dos estimaciones para el mismo extrinsic en momentos diferentes serán distintas. Una estimación obtenida cuando el multiplicador es bajo puede ser menor que la comisión realmente cobrada si el multiplicador sube antes de que se incluya la transacción. A la inversa, si el multiplicador disminuye, la comisión real puede ser menor que la estimación.
El multiplicador se almacena en el storage del pallet transaction-payment y puede leerse en un bloque específico usando consultas de estado. Esto permite a un cliente determinar si la comisión cotizada está con un multiplicador normal o elevado. Para más información sobre cómo leer el storage en un bloque, consulta Estado de Polkadot en un bloque con state_queryStorageAt.
- El multiplicador sube cuando los bloques están llenos y baja cuando no lo están.
- Las estimaciones varían según el multiplicador en el momento de la consulta.
- Lee el multiplicador desde el storage para evaluar el nivel de comisión.
# payment_queryInfo takes a signed extrinsic hex; read the multiplier for the same block.
curl -s -X POST "$POLKADOT_RPC" -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"payment_queryInfo","params":["0x<signed-extrinsic-hex>"]}'
# The transaction-payment fee multiplier raises the weight component when blocks are full.
curl -s -X POST "$POLKADOT_RPC" -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":2,"method":"state_getStorage","params":["0x<twox64_concat(\"TransactionPayment\", \"NextFeeMultiplier\")>"]}'Leer el multiplicador de comisión desde el storage de transaction-payment
El multiplicador de comisión se almacena en el pallet transaction-payment bajo el elemento de storage NextFeeMultiplier. Puedes consultarlo en un bloque específico usando el método RPC state_getStorage o a través de la API de polkadot.js. El valor es un número de punto fijo que representa el multiplicador.
Para leer el multiplicador, necesitas la clave de storage de NextFeeMultiplier. Puedes obtenerla desde los metadatos usando la guía Substrate state_getMetadata y versiones del runtime. Alternativamente, la API de polkadot.js proporciona una forma conveniente de consultarlo.
Conocer el multiplicador ayuda a interpretar la estimación: si el multiplicador es alto, la comisión por weight está elevada y la estimación puede ser mayor de lo habitual. Si es bajo, la estimación se acerca más a las comisiones base y por longitud.
- Elemento de storage: NextFeeMultiplier.
- Consulta vía state_getStorage o la API de polkadot.js.
- Un multiplicador alto indica una comisión por weight elevada.
Ejemplo ejecutable en Node.js: estimar comisiones con @polkadot/api
El siguiente script de Node.js usa @polkadot/api para conectarse a un endpoint RPC de Polkadot, construir un extrinsic de transferencia, estimar su comisión con payment_queryInfo, leer el multiplicador de comisión y comparar la estimación con un lote de las mismas llamadas. Asume que tienes una cuenta con fondos y un endpoint válido.
El script primero construye el extrinsic, lo firma y luego llama a payment_queryInfo con el hex del extrinsic firmado. También consulta el elemento de storage NextFeeMultiplier. Finalmente, construye un lote de la misma transferencia y estima su comisión para mostrar que la comisión del lote no es simplemente la suma de las estimaciones por llamada.
const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api');
async function main() {
const provider = new WsProvider('wss://rpc.polkadot.io');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });
const alice = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive('14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3', 1000000000);
const signed = await transfer.signAsync(alice);
const hex = signed.toHex();
const info = await api.rpc.payment.queryInfo(hex);
console.log('Partial fee:', info.partialFee.toString());
console.log('Weight:', info.weight.toString());
const multiplier = await api.query.transactionPayment.nextFeeMultiplier();
console.log('Next fee multiplier:', multiplier.toString());
const batch = api.tx.utility.batchAll([transfer, transfer]);
const signedBatch = await batch.signAsync(alice);
const batchInfo = await api.rpc.payment.queryInfo(signedBatch.toHex());
console.log('Batch partial fee:', batchInfo.partialFee.toString());
await api.disconnect();
}
main().catch(console.error);Tabla de resultados: medir estimaciones contra tu propio endpoint
Para validar la estimación de comisiones contra tu propio endpoint, completa la siguiente tabla con datos de tus propias pruebas. Usa un extrinsic consistente (por ejemplo, una transferencia) y registra la estimación devuelta por payment_queryInfo, el weight, el multiplicador en el momento de la estimación y la comisión realizada después de la inclusión. Esto te ayudará a entender cómo se compara la estimación con la comisión real en tu entorno.
Ejecuta la prueba varias veces en diferentes alturas de bloque para observar el efecto del multiplicador. Ten en cuenta que la comisión realizada es la comisión real deducida de la cuenta del remitente, que puedes encontrar en el evento de pago de la transacción o comparando los saldos antes y después de la inclusión.
- Estimación devuelta (comisión parcial):
- Weight:
- Multiplicador en el momento de la estimación:
- Comisión realizada después de la inclusión:
- Diferencia (realizada - estimada):
Modos de fallo y solución de problemas
Los modos de fallo comunes incluyen: 'payment_queryInfo returned an error' para un extrinsic sin firmar o mal formado; una estimación menor que la comisión realmente cobrada porque el multiplicador subió; un lote cuya comisión no es la suma de las estimaciones por llamada; y endpoints que no exponen el namespace payment. Este último varía según el proveedor, así que consulta la documentación de tu proveedor.
Si recibes un error por un extrinsic sin firmar, asegúrate de firmar el extrinsic antes de llamar a payment_queryInfo. Si la estimación es menor que la comisión real, vuelve a estimar cerca del momento de envío y considera agregar una propina para priorizar la inclusión. Para lotes, la comisión se calcula para todo el lote como un único extrinsic, por lo que no es la suma de las estimaciones individuales; usa payment_queryInfo sobre el propio extrinsic del lote.
Si tu endpoint no admite el namespace payment, es posible que necesites cambiar a un proveedor que sí lo haga. Los endpoints RPC de Polkadot (RPC Assistant) de OnFinality pueden ayudarte a encontrar un endpoint adecuado. Para más información sobre cómo manejar errores de dispatch, consulta Decodificar errores de dispatch de extrinsics de Polkadot.
- Extrinsic sin firmar: firma antes de llamar.
- Aumento del multiplicador: vuelve a estimar cerca del envío.
- Comisión de lote: estima el extrinsic del lote, no las llamadas individuales.
- Soporte del endpoint: varía según el proveedor.
Limitaciones y compensaciones de la estimación de comisiones
La estimación de comisión es una predicción contra el estado actual y el multiplicador de comisión actual. No es una garantía de la comisión que se cobrará. La comisión real depende del estado en el bloque en el que se incluye la transacción, que puede diferir del estado en el momento de la estimación.
Manejo de propinas: la comisión parcial devuelta por payment_queryInfo no incluye la propina. Si incluyes una propina, la comisión total será mayor. La propina se suma a la comisión y no está sujeta al multiplicador.
Debido a que la estimación depende del estado, es recomendable volver a estimar cerca del momento de envío, especialmente durante períodos de alta actividad de la red. Para una visión más amplia de los métodos RPC de Polkadot, consulta el centro de aprendizaje de OnFinality y los endpoints RPC de Polkadot (RPC Assistant).
- La estimación no es una garantía.
- La propina no está incluida en la comisión parcial.
- Vuelve a estimar cerca del momento de envío.
Próximos pasos: integrar la estimación de comisiones en tu aplicación
Para integrar la estimación de comisiones en tu aplicación, usa payment_queryInfo o payment_queryFeeDetails para obtener una estimación antes de enviar una transacción. Muestra la estimación a los usuarios, pero deja claro que es una estimación y que puede cambiar. Considera leer el multiplicador de comisión para dar contexto sobre si las comisiones están actualmente elevadas.
Para uso en producción, asegúrate de que tu endpoint RPC admita el namespace payment. OnFinality proporciona endpoints RPC de Polkadot confiables y un servicio de API que se puede usar para la estimación de comisiones. Para detalles de precios, consulta Precios de RPC.
Para profundizar tu comprensión de RPC de Polkadot, explora guías relacionadas como Leer extrinsics y eventos de Polkadot en un bloque y Finalidad GRANDPA y justificaciones de Polkadot.
- Usa payment_queryInfo o payment_queryFeeDetails.
- Lee el multiplicador para dar contexto.
- Elige un endpoint que admita el namespace payment.