# Partial Payments This page describes the specifics of the `Amount` field that appears in `Payment` transactions and various API methods. While the contextual information regarding `Amount` and partial payments is still relevant, the field has been renamed to `DeliverMax` in `rippled` [API v2](/docs/references/http-websocket-apis#api-versioning). This was done to make the field name more specific to its behavior and help prevent the misunderstandings and exploit described below. The sender of any [Payment transaction](/docs/references/protocol/transactions/types/payment) can enable the ["Partial Payment" flag](/docs/references/protocol/transactions/types/payment#payment-flags) and send a payment which delivers less than the `Amount` field indicates. When processing any Payment, use the `delivered_amount` metadata field, not the `Amount` field. The `delivered_amount` is the amount a payment actually delivered. If a Payment does not enable the Partial Payment flag, the `Amount` field of a [Payment transaction](/docs/references/protocol/transactions/types/payment) in the XRP Ledger specifies the amount to deliver after charging for exchange rates and [transfer fees](/docs/concepts/tokens/fungible-tokens/transfer-fees). The Partial Payment flag ([`tfPartialPayment`](/docs/references/protocol/transactions/types/payment#payment-flags)) allows a payment to succeed by reducing the amount received instead of increasing the amount sent. Partial payments are useful for [returning payments](/docs/concepts/payment-types/bouncing-payments) without incurring additional costs to oneself. The amount of XRP used for the [transaction cost](/docs/concepts/transactions/transaction-cost) is always deducted from the sender’s account, regardless of the type of transaction. This transaction cost, or fee, is not included in the `Amount`. Partial payments can be used to exploit naive integrations with the XRP Ledger to steal money from exchanges and gateways. The [Partial Payments Exploit](#partial-payments-exploit) section of this document describes how this exploit works and how you can avoid it. ## Semantics ### Without Partial Payments When sending a Payment that does not use the Partial Payment flag, the `Amount` field of the transaction specifies the exact amount to deliver, and the `SendMax` field specifies the maximum amount and currency to send. If a payment cannot deliver the full `Amount` without exceeding the `SendMax` parameter, or the full amount cannot be delivered for any other reason, the transaction fails. If the `SendMax` field is omitted from the transaction instructions, it is considered to be equal to the `Amount`. In this case, the payment can only succeed if the total amount of fees is 0. In other words: ``` Amount + (fees) = (sent amount) ≤ SendMax ``` In this formula, "fees" refers to [transfer fees](/docs/concepts/tokens/fungible-tokens/transfer-fees) and currency exchange rates. The "sent amount" and the delivered amount (`Amount`) may be denominated in different currencies and converted by consuming Offers in the XRP Ledger's decentralized exchange. The `Fee` field of the transaction refers to the XRP [transaction cost](/docs/concepts/transactions/transaction-cost), which is destroyed to relay the transaction to the network. The exact transaction cost specified is always debited from the sender and is completely separate from the fee calculations for any type of payment. ### With Partial Payments When sending a Payment that has the Partial Payment flag enabled, the `Amount` field of the transaction specifies a maximum amount to deliver. Partial payments can succeed at sending *some* of the intended value despite limitations including fees, not enough liquidity, not enough space in the receiving account's trust lines, or other reasons. The optional `DeliverMin` field specifies a minimum amount to deliver. The `SendMax` field functions the same as with non-partial payments. The partial payment transaction is successful if it delivers any amount equal or greater than the `DeliverMin` field without exceeding the `SendMax` amount. If the `DeliverMin` field is not specified, a partial payment can succeed by delivering any positive amount. In other words: ``` Amount ≥ (Delivered Amount) = SendMax - (Fees) ≥ DeliverMin > 0 ``` ### Partial Payment Limitations Partial Payments have the following limitations: - A partial payment cannot provide the XRP to fund an address; this case returns the [result code](/docs/references/protocol/transactions/transaction-results) `telNO_DST_PARTIAL`. - Direct XRP-to-XRP payments cannot be partial payments; this case returns the [result code](/docs/references/protocol/transactions/transaction-results) `temBAD_SEND_XRP_PARTIAL`. - However, cross-currency payments that involve XRP as one of the currencies *can* be partial payments. ### The `delivered_amount` Field To help understand how much a partial payment actually delivered, the metadata of a successful Payment transaction includes a `delivered_amount` field. This field describes the amount actually delivered, in the [same format](/docs/references/protocol/data-types/basic-data-types#specifying-currency-amounts) as the `Amount` field. For non-partial payments, the `delivered_amount` field of the transaction metadata is equal to the `Amount` field of the transaction. When a payment delivers [tokens](/docs/concepts/tokens), the `delivered_amount` may be slightly different than the `Amount` field due to rounding. The delivered amount is **not available** for transactions that meet **both** of the following criteria: - Is a partial payment - Is included in a validated ledger before 2014-01-20 If both conditions are true, then `delivered_amount` contains the string value `unavailable` instead of an actual amount. If this happens, you can only determine the actual delivered amount by reading the `AffectedNodes` in the transaction's metadata. If the transaction delivered tokens and the `issuer` of the `Amount` is the same account as the `Destination` address, the delivered amount may be divided among multiple `AffectedNodes` members representing trust lines to different counterparties. You can find the `delivered_amount` field in the following places: | API | Method | Field | | --- | --- | --- | | [JSON-RPC / WebSocket](/docs/references/http-websocket-apis) | [account_tx method](/docs/references/http-websocket-apis/public-api-methods/account-methods/account_tx) | `result.transactions` array members' `meta.delivered_amount` | | [JSON-RPC / WebSocket](/docs/references/http-websocket-apis) | [tx method](/docs/references/http-websocket-apis/public-api-methods/transaction-methods/tx) | `result.meta.delivered_amount` | | [JSON-RPC / WebSocket](/docs/references/http-websocket-apis) | [transaction_entry method](/docs/references/http-websocket-apis/public-api-methods/transaction-methods/transaction_entry) | `result.metadata.delivered_amount` | | [JSON-RPC / WebSocket](/docs/references/http-websocket-apis) | [ledger method](/docs/references/http-websocket-apis/public-api-methods/ledger-methods/ledger) (with transactions expanded) | `result.ledger.transactions` array members' `metaData.delivered_amount` | | [WebSocket](/docs/references/http-websocket-apis) | [Transaction subscriptions](/docs/references/http-websocket-apis/public-api-methods/subscription-methods/subscribe#transaction-streams) | Subscription messages' `meta.delivered_amount` | | ripple-lib v1.x | `getTransaction` method | `outcome.deliveredAmount` | | ripple-lib v1.x | `getTransactions` method | array members' `outcome.deliveredAmount` | ## Partial Payments Exploit If a financial institution's integration with the XRP Ledger assumes that the `Amount` field of a Payment is always the full amount delivered, malicious actors may be able to exploit that assumption to steal money from the institution. This exploit can be used against gateways, exchanges, or merchants as long as those institutions' software does not process partial payments correctly. **The correct way to process incoming Payment transactions is to use [the `delivered_amount` metadata field](#the-delivered_amount-field),** not the `Amount` field. This way, an institution is never mistaken about how much it *actually* received. ### Exploit Scenario Steps To exploit a vulnerable financial institution, a malicious actor does something like this: 1. The malicious actor sends a Payment transaction to the institution. This transaction has a large `Amount` field and has the **`tfPartialPayment`** flag enabled. 2. The partial payment succeeds (result code `tesSUCCESS`) but actually delivers a very small amount of the currency specified. 3. The vulnerable institution reads the transaction's `Amount` field without looking at the `Flags` field or `delivered_amount` metadata field. 4. The vulnerable institution credits the malicious actor in an external system, such as the institution's own ledger, for the full `Amount`, despite only receiving a much smaller `delivered_amount` in the XRP Ledger. 5. The malicious actor withdraws as much of the balance as possible to another system before the vulnerable institution notices the discrepancy. - Malicious actors usually prefer to convert the balance to another crypto-currency such as Bitcoin, because blockchain transactions are usually irreversible. With a withdrawal to a fiat currency system, the financial institution may be able to reverse or cancel the transaction several days after it initially executes. - In the case of an exchange, the malicious actor can also withdraw an XRP balance directly back into the XRP Ledger. In the case of a merchant, the order of operations is slightly different, but the concept is the same: 1. The malicious actor requests to buy a large amount of goods or services. 2. The vulnerable merchant invoices the malicious actor for the price of those goods and services. 3. The malicious actor sends a Payment transaction to the merchant. This transaction has a large `Amount` field and has the **`tfPartialPayment`** flag enabled. 4. The partial payment succeeds (result code `tesSUCCESS`) but delivers only a very small amount of the currency specified. 5. The vulnerable merchant reads the transaction's `Amount` field without looking at the `Flags` field or `delivered_amount` metadata field. 6. The vulnerable merchant treats the invoice as paid and provides the goods or services to the malicious actor, despite only receiving a much smaller `delivered_amount` in the XRP Ledger. 7. The malicious actor uses, resells, or absconds with the goods and services before the merchant notices the discrepancy. ### Further Mitigations Using [the `delivered_amount` field](#the-delivered_amount-field) when processing incoming transactions is enough to avoid this exploit. Still, additional proactive business practices can also avoid or mitigate the likelihood of this and similar exploits. For example: - Add additional sanity checks to your business logic for processing withdrawals. Never process a withdrawal if the total balance you hold in the XRP Ledger does not match your expected assets and obligations. - Follow "Know Your Customer" guidelines and strictly verify your customers' identities. You may be able to recognize and block malicious users in advance, or pursue legal action against a malicious actor who exploits your system. ## See Also - **Tools:** - [Transaction Sender](/resources/dev-tools/tx-sender) - **Concepts:** - [Transactions](/docs/concepts/transactions) - **Tutorials:** - [Look Up Transaction Results](/docs/concepts/transactions/finality-of-results/look-up-transaction-results) - [Monitor Incoming Payments with WebSocket](/docs/tutorials/http-websocket-apis/build-apps/monitor-incoming-payments-with-websocket) - [Use Specialized Payment Types](/docs/tutorials/how-tos/use-specialized-payment-types) - [List XRP as an Exchange](/docs/use-cases/defi/list-xrp-as-an-exchange) - **References:** - [Payment transaction](/docs/references/protocol/transactions/types/payment) - [Transaction Metadata](/docs/references/protocol/transactions/metadata) - [account_tx method](/docs/references/http-websocket-apis/public-api-methods/account-methods/account_tx) - [tx method](/docs/references/http-websocket-apis/public-api-methods/transaction-methods/tx)