Full Report
The XRP blockchain have a feature called partial payment. This allows a payment to deliver part of what the amount fields says. Why? I'm guessing this is a feature to break up large transfers over time to another user. When the feature is used, the delivered_amount field contains the actual amount that was delivered. In other cases, the amount contains the full amount of funds that were sent. In terms of security, they have a hypothetical attack that I felt was interesting. If your sending funds to an exchange, delivered_amount MUST be checked on the transfer. Otherwise, the user will be credited with more funds than they actual sent. An interesting feature that I'm sure has led to problems in the past.
Analysis Summary
# Best Practices: Handling XRP Ledger Partial Payments
## Overview
The XRP Ledger (XRPL) includes a "Partial Payment" feature enabled via the `tfPartialPayment` flag. This allow a transaction to succeed even if it delivers only a portion of the amount specified in the `Amount` (or `DeliverMax` in API v2) field. If an application (like an exchange or gateway) incorrectly reads the intended amount instead of the actually delivered amount, it remains vulnerable to "Partial Payment Exploits," leading to the balance being credited with funds that were never actually received.
## Key Recommendations
### Immediate Actions
1. **Switch Metadata Fields:** Immediately update all payment processing logic to rely exclusively on the `delivered_amount` metadata field rather than the `Amount` or `DeliverMax` fields.
2. **Verify Transaction Flags:** Implement a check for the `tfPartialPayment` flag in incoming transactions. If your system does not explicitly support partial payments, consider flagging these for manual review.
3. **Sanitize API Versioning:** Ensure your integration uses `rippled` API v2 where the `Amount` field is renamed to `DeliverMax` to reduce semantic confusion among developers.
### Short-term Improvements (1-3 months)
1. **Audit Transaction Logs:** Review historical transaction data to identify any instances where `delivered_amount` differed from `Amount` and reconcile balances.
2. **Enhanced Validation Logic:** Implement "Strict Receipt" logic: if a transaction is received with the `tfPartialPayment` flag, the system must perform a secondary validation against the ledger state to confirm the net increase in the account’s balance.
3. **Implement Real-time Monitoring:** Deploy web-socket listeners that specifically alert when a transaction contains the `tfPartialPayment` flag.
### Long-term Strategy (3+ months)
1. **Zero-Trust Integration:** Adopt a "Verify via Metadata" architecture for all blockchain interactions, assuming that transaction-level fields are "intent" and metadata fields are "reality."
2. **Automated Reconciliation:** Build a cross-referencing engine that compares internal database credits against on-chain `delivered_amount` totals daily to detect discrepancies automatically.
## Implementation Guidance
### For Small Organizations
- Focus on using high-level SDKs that abstract metadata. Ensure you are calling the method that returns the *effective* delivered amount, not the *requested* amount.
### For Medium Organizations
- Implement automated alerts for any incoming transaction where the `tfPartialPayment` flag is active.
- Require dual-signature or manual approval for crediting accounts when a partial payment is detected.
### For Large Enterprises (Exchanges/Custodians)
- **KYC/AML Linkage:** Cross-reference users who attempt partial payment exploits with identity data to block malicious actors.
- **Infrastructure:** Use a dedicated `rippled` node to fetch transaction metadata directly rather than relying on third-party explorers which may display the "intent" amount.
## Configuration Examples
**Vulnerable Logic (DO NOT USE):**
javascript
// This ignores metadata and looks at the transaction intent
const creditedAmount = tx.Amount;
**Secure Logic (Recommended):**
javascript
// Always check the metadata for the actual result
if (tx.meta && tx.meta.delivered_amount) {
const creditedAmount = tx.meta.delivered_amount;
} else {
// Fallback for older transactions where Amount is the delivered amount
// but ONLY if the tfPartialPayment flag is NOT set
const creditedAmount = tx.Amount;
}
## Compliance Alignment
- **NIST SP 800-53:** SC-8 (Transmission Integrity) - Ensuring the amount credited matches the amount actually transmitted.
- **ISO/IEC 27001:** A.14.2.1 (Secure Development Policy) - Implementing specific coding standards to handle blockchain-specific transaction flags.
- **CIS Controls:** Control 16 (Application Software Security) - Mitigating flaws in application logic that lead to financial loss.
## Common Pitfalls to Avoid
- **Confusing Intent with Delivery:** Assuming the `Amount` field represents a guaranteed transfer. In XRPL, it represents a "limit" or "maximum."
- **Display Errors:** Using blockchain explorers that only show the `Amount` field, leading customer support teams to believe a larger deposit was made than actually occurred.
- **Neglecting Transaction Metadata:** Processing payments based on the transaction object alone without inspecting the `meta` (metadata) result object provided by the ledger.
## Resources
- **XRPL Official Documentation:** [xrpl[.]org/docs/concepts/payment-types/partial-payments]
- **API Reference:** [xrpl[.]org/docs/references/protocol/transactions/types/payment#payment-flags]
- **Tooling:** XRPL-JS SDK (Use `getBalanceChanges` for simplified accounting)