Pagos parciales
El remitente de cualquier [transacción de pago][] puede habilitar el flag de"Partial Payment" y enviar un pago que entregue menos de lo que indica el campo Amount
. Al procesar cualquier Pago, utiliza el campo de metadatos delivered_amount
, no el campo Amount
. El delivered_amount
es la cantidad que un pago realmente entregó.
Si un Pago no habilita el flag de Pago Parcial, el campo Amount
de una [transacción Payment][] en el XRP Ledger especifica la cantidad a entregar después de cobrar por tasas de cambio y costes de transferencia. El flag de Pago Parcial (tfPartialPayment
) permite que un pago tenga éxito al reducir la cantidad recibida en lugar de aumentar la cantidad enviada. Los pagos parciales son útiles para devolver pagos sin incurrir en costos adicionales para uno mismo.
La cantidad de XRP utilizada para el coste de transacción siempre se deduce de la cuenta del remitente, independientemente del tipo de transacción. Este coste de transacción, o comisión, no se incluye en la Amount
.
Los pagos parciales se pueden utilizar para explotar integraciones ingenuas con el XRP Ledger para robar dinero de exchanges y gateways. La sección Explotación de Pagos Parciales de este documento describe cómo funciona esta explotación y cómo puedes evitarla.
Semántica
Sin pagos parciales
Al enviar un Pago que no utiliza el flag de Pago Parcial, el campo Amount
de la transacción especifica la cantidad exacta a entregar, y el campo SendMax
especifica la cantidad máxima y la divisa a enviar. Si un pago no puede entregar la cantidad completa de Amount
sin exceder el parámetro SendMax
, o si la cantidad completa no se puede entregar por cualquier otro motivo, la transacción falla. Si el campo SendMax
se omite de las instrucciones de la transacción, se considera igual a la Amount
. En este caso, el pago solo puede tener éxito si la cantidad total de las tarifas es 0.
En otras palabras:
Cantidad + (costes) = (cantidad enviada) ≤ SendMax
En esta fórmula, "costes" o fees se refiere a costes de transferencia y tipos de cambio de las divisas. La "cantidad enviada" y la cantidad enviada (Amount
) pueden estar denominadas en distintas divisas y convertirse por la consumición de Ofertas en el exchange descentralizado del XRP Ledger.
Nota: El campo Fee
de la transacción se refiere al coste de transacción en XRP, que se destruye para enviar la transacción a la red. El coste de transacción exacto especificado se carga siempr al remitente y se separa completamente de los cálculos de costes para cualquier tipo de pago.
Con pagos parciales
Cuando se envía un Pago que tiene habilitado el flag de Pago Parcial, el campo Amount
de la transacción especifica una cantidad máxima a entregar. Los pagos parciales pueden tener éxito al enviar parte del valor previsto a pesar de limitaciones que incluyen costes, falta de liquidez, falta de espacio en las líneas de confianza (trustlines) de la cuenta receptora, u otras razones.
El campo opcional DeliverMin
especifica una cantidad mínima a entregar. El campo SendMax
funciona de la misma manera que con los pagos no parciales. La transacción de pago parcial tiene éxito si entrega cualquier cantidad igual o mayor que el campo DeliverMin
sin exceder la cantidad SendMax
. Si el campo DeliverMin
no está especificado, un pago parcial puede tener éxito al entregar cualquier cantidad positiva.
En otras palabras:
Cantidad ≥ (Cantidad enviada) = SendMax - (Costes) ≥ DeliverMin > 0
Limitaciones de los pagos parciales
Los pagos parciales tienen las siguientes limitaciones:
- Un pago parcial no puede proporcionar el XRP para crear una dirección; en este caso se devuelve el código de resultado
telNO_DST_PARTIAL
. - Pagos directoss de XRP a XRP no pueden ser pagos parciales; este caso devuelve el código de resultado
temBAD_SEND_XRP_PARTIAL
.- Sin embargo, los pagos entre divisas que involucran a XRP como una de las divisas pueden ser pagos parciales.
El campo delivered_amount
Para ayudar a entender cuánto entregó realmente un pago parcial, los metadatos de una transacción de Pago exitosa incluyen un campo delivered_amount
. Este campo describe la cantidad realmente entregada, en el mismo formato que el campo Amount
.
Para pagos no parciales, el campo delivered_amount
de los metadatos de la transacción es igual al campo Amount
de la transacción. Cuando un pago entrega tokens, el campo delivered_amount
puede ser ligeramente diferente al campo Amount
debido al redondeo.
La cantidad entregada no está disponible para transacciones que cumplen ambos de los siguientes criterios:
- Es un pago parcial
- Está incluido en un ledger validado anterior al 20 de enero de 2014
Si ambas condiciones son verdaderas, entonces delivered_amount
contiene el valor del string unavailable
en lugar de una cantidad real. Si esto ocurre, solo puedes determinar la cantidad entregada real leyendo los AffectedNodes
en los metadatos de la transacción. Si la transacción entregó tokens y el issuer
del Amount
es la misma cuenta que la dirección Destination
, la cantidad entregada puede dividirse entre varios miembros de AffectedNodes
que representan líneas de confianza (trustlines) con distintas contrapartes.
Puedes encontrar el campo delivered_amount
en los siguientes lugares:
API | Método | Campo |
---|---|---|
JSON-RPC / WebSocket | [método account_tx][] | result.transactions miembros del array meta.delivered_amount |
JSON-RPC / WebSocket | [método tx][] | result.meta.delivered_amount |
JSON-RPC / WebSocket | [método transaction_entry][] | result.metadata.delivered_amount |
JSON-RPC / WebSocket | [método ledger][] (con las transacciones ampliadas) | result.ledger.transactions miembros del array metaData.delivered_amount |
WebSocket | subscripciones Transaction | Mensajes de subscripción de meta.delivered_amount |
ripple-lib v1.x | método getTransaction | outcome.deliveredAmount |
ripple-lib v1.x | método getTransactions | miembros del array outcome.deliveredAmount |
Exploit de pagos parciales
Si la integración de una institución financiera con el XRP Ledger asume que el campo Amount
de un Pago es siempre la cantidad completa entregada, actores maliciosos podrían aprovechar esa suposición para robar dinero de la institución. Este exploit puede utilizarse contra pasarelas, exchanges o comerciantes siempre que el software de esas instituciones no procese los pagos parciales correctamente.
La forma correcta de procesar las transacciones de Pago entrantes es utilizar el campo delivered_amount
de los metadatos, no el campo Amount
. De este modo, una institución nunca se equivocará sobre cuanto recibe realmente.
Pasos del escenario del Exploit
Para realizar un exploit a una institución financiera vulnerable, un actor malicioso puede hacer lo siguiente:
- El actor malicioso envía una transacción de Pago a la institución. Esta transacción tiene un campo
Amount
grande y tiene el flag detfPartialPayment
activado. - El pago parcial tiene éxito (código de resultado
tesSUCCESS
) pero en realidad entrega una cantidad muy pequeña de la divisa especificada. - La institución vulnerable lee el campo
Amount
sin mirar el campoFlags
o el campo de metadatosdelivered_amount
. - La institutución vulnerable acredita al actor malicioso en un sistema externo, como el propio ledger de la institución, por el
Amount
completo, a pesar de recibir solo undelivered_amount
pequeño en el XRP Ledger. - El actor malicioso retira tanto saldo como sea posible antes de que la institución vulnerable note la discrepancia.
- Los actores maliciosos suelen preferir convertir el saldo a otra criptomoneda como Bitcoin, porque las transacciones de blockchain suelen ser irreversibles. Con un retiro a un sistema de moneda fiduciaria, la institución financiera podría revertir o cancelar la transacción varios días después de que se ejecute inicialmente.
- En el caso de un exchange, el actor malicioso también puede retirar un saldo de XRP directamente de nuevo al XRP Ledger.
En el caso de un comerciante, el orden de las operaciones es ligeramente diferente, pero el concepto es el mismo:
- El actor malicioso solicita comprar una gran cantidad de bienes o servicios.
- El comerciante vulnerable factura al actor malicioso por el precio de esos bienes o servicios.
- El actor malicioso envía una transacción de Pago al comerciante. Esta transacción tiene un campo
Amount
grande y tiene el flagtfPartialPayment
activado. - El pago parcial tiene éxito (código de resultado
tesSUCCESS
) pero entrega solo una cantidad muy pequeña de la divisa especificada. - El comerciante vulnerable lee el campo
Amount
de la transacción sin mirar el campoFlags
o el campo de los metadatosdelivered_amount
. - El comerciante vulnerable trata la factura como pagada y proporciona los bienes o servicios al actor malicioso, a pesar de recibir solo una mucho menor
delivered_amount
en el XRP Ledger. - El actor malicioso utiliza, revende, o se marcha con los bienes y servicios antes de que el comerciantes note la discrepancia.
Mitigaciones adicionales
Utilizar el campo delivered_amount
al procesar transacciones entrantes es suficiente para evitar este exploit. Aún así, prácticas de negocio proactivas adicionales también pueden evitar o mitigar la probabilidad de esta o exploits similares. Por ejemplo:
- Añade chequeos adicionales a la lógica de tu negocio para procesar los retiros. Nunca proceses un retiro si el balance total que tienes en el XRP Ledger no coincide con tus activos y obligaciones esperados.
- Sigue las directrices "Know Your Customer" y verifica estrictamente las identidades de tus clientes. Puede que reconozcas y bloquees usuarios maliciosos de antemano, o emprender acciones legales contra el actor malicioso que genera exploits a tu sistema.
Ver también
- Herramientas:
- Conceptos:
- Tutoriales:
- Referencias:
- [Transacción de Pago][]
- Metadatos de transacción
- [método account_tx][]
- [método tx][]