Files
xrpl-dev-portal/concept-partial-payments.html
2017-06-09 12:43:13 -07:00

283 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>Partial Payments - Ripple Developer Portal</title>
<!-- favicon -->
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<!-- jQuery -->
<script src="assets/vendor/jquery-1.11.1.min.js"></script>
<!-- Custom Stylesheets. ripple.css includes bootstrap, font stuff -->
<link href="assets/css/ripple.css" rel="stylesheet" />
<link href="assets/css/devportal.css" rel="stylesheet" />
<!-- Bootstrap JS -->
<script src="assets/vendor/bootstrap.min.js"></script>
<!-- syntax highlighting -->
<link rel="stylesheet" href="assets/vendor/docco.min.css" />
<script src="assets/vendor/highlight.min.js"></script>
<!-- syntax selection js -->
<script src="assets/js/multicodetab.js"></script>
<script>
$(document).ready(function() {
$(".multicode").minitabs();
hljs.initHighlighting();
make_code_expandable();
});
</script>
<script src="assets/js/expandcode.js"></script>
<script src="assets/js/fixsidebarscroll.js"></script>
<!-- fontawesome icons -->
<link rel="stylesheet" href="assets/vendor/fontawesome/css/font-awesome.min.css" />
</head>
<body class="page page-template page-template-template-dev-portal page-template-template-dev-portal-php sidebar-primary wpb-js-composer js-comp-ver-3.6.2 vc_responsive">
<header role="banner" class="banner navbar navbar-default navbar-fixed-top initial_header">
<div class="container">
<div class="navbar-header">
<a href="index.html" class="navbar-brand"><img src="assets/img/ripple-logo-color.png" class="logo"></a>
</div><!-- /.navbar-header -->
<div class="nav">
<div class="draft-warning">DRAFT PAGE</div>
</div><!-- /.nav -->
</div><!-- /.container -->
<div class="subnav dev_nav">
<div class="container">
<ul id="menu-dev-menu" class="menu">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">References <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="reference-rippleapi.html">RippleAPI</a></li>
<li><a href="reference-rippled.html">rippled</a></li>
<li><a href="reference-transaction-format.html">Transaction Format</a></li>
<li><a href="reference-ledger-format.html">Ledger Format</a></li>
<li><a href="reference-data-api.html">Ripple Data API v2</a></li>
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorials <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="tutorial-multisign.html">How to Multi-Sign</a></li>
<li><a href="tutorial-paychan.html">Payment Channels Tutorial</a></li>
<li><a href="concept-issuing-and-operational-addresses.html">Issuing and Operational Addresses</a></li>
<li><a href="tutorial-reliable-transaction-submission.html">Reliable Transaction Submission</a></li>
<li><a href="tutorial-rippleapi-beginners-guide.html">RippleAPI Beginners Guide</a></li>
<li><a href="tutorial-rippled-setup.html">rippled Setup</a></li>
<li><a href="tutorial-gateway-guide.html">Gateway Guide</a></li>
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">RCL Features <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="concept-accounts.html">Accounts</a></li>
<li><a href="concept-amendments.html">Amendments</a></li>
<li><a href="concept-fee-voting.html">Fee Voting</a></li>
<li><a href="concept-fees.html">Fees (Disambiguation)</a></li>
<li><a href="concept-freeze.html">Freeze</a></li>
<li><a href="concept-partial-payments.html">Partial Payments</a></li>
<li><a href="concept-paths.html">Paths</a></li>
<li><a href="concept-reserves.html">Reserves</a></li>
<li><a href="concept-stand-alone-mode.html">Stand-Alone Mode</a></li>
<li><a href="concept-transaction-cost.html">Transaction Cost</a></li>
<li><a href="concept-transfer-fees.html">Transfer Fees</a></li>
<li><a href="concept-noripple.html">Understanding the NoRipple flag</a></li>
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Gateway Bulletins <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="gb-2015-06.html">GB-2015-06: Corrections to Autobridging</a></li>
<li><a href="gb-2015-05.html">GB-2015-05: Historical Ledger Query Migration</a></li>
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Tools <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="ripple-api-tool.html">WebSocket API Tool</a></li>
<li><a href="data-api-v2-tool.html">Data API v2 Tool</a></li>
<li><a href="tool-jsonrpc.html">rippled JSON-RPC Tool</a></li>
</ul>
</li>
<li><a href="https://github.com/ripple/ripple-dev-portal" title="GitHub">Site Source</a></li>
</ul><!-- /#dev-menu -->
</div><!-- /.subnav .container -->
</div><!-- /.subnav -->
</header>
<div class="wrap container" role="document">
<aside class="sidebar" role="complementary">
<div class="dev_nav_wrapper">
<div id="cont">
<h5>In this category:</h5>
<ul class="dev_nav_sidebar">
<li class="level-1"><a href="index.html">Category: RCL Features</a></li>
<li class="level-2"><a href="concept-accounts.html">Accounts</a></li>
<li class="level-2"><a href="concept-amendments.html">Amendments</a></li>
<li class="level-2"><a href="concept-fee-voting.html">Fee Voting</a></li>
<li class="level-2"><a href="concept-fees.html">Fees (Disambiguation)</a></li>
<li class="level-2"><a href="concept-freeze.html">Freeze</a></li>
<li class="level-2"><a href="concept-partial-payments.html">Partial Payments</a></li>
<li class="level-2"><a href="concept-paths.html">Paths</a></li>
<li class="level-2"><a href="concept-reserves.html">Reserves</a></li>
<li class="level-2"><a href="concept-stand-alone-mode.html">Stand-Alone Mode</a></li>
<li class="level-2"><a href="concept-transaction-cost.html">Transaction Cost</a></li>
<li class="level-2"><a href="concept-transfer-fees.html">Transfer Fees</a></li>
<li class="level-2"><a href="concept-noripple.html">Understanding the NoRipple flag</a></li>
</ul>
<hr />
<h5>In this page:</h5>
<ul class="dev_nav_sidebar" id="dactyl_toc_sidebar">
<li class="level-1"><a href="#partial-payments">Partial Payments</a></li>
<li class="level-2"><a href="#semantics">Semantics</a></li>
<li class="level-3"><a href="#without-partial-payments">Without Partial Payments</a></li>
<li class="level-3"><a href="#with-partial-payments">With Partial Payments</a></li>
<li class="level-3"><a href="#partial-payment-limitations">Partial Payment Limitations</a></li>
<li class="level-3"><a href="#the-delivered-amount-field">The delivered_amount Field</a></li>
<li class="level-2"><a href="#partial-payments-exploit">Partial Payments Exploit</a></li>
<li class="level-3"><a href="#avoiding-the-exploit">Avoiding the Exploit</a></li>
</ul>
</div>
</div>
</aside>
<main class="main" role="main">
<div class='content'>
<h1 id="partial-payments">Partial Payments</h1>
<p>In the default case, the <code>Amount</code> field of a <a href="reference-transaction-format.html#payment">Payment transaction</a> in the Ripple Consensus Ledger specifies the exact amount to deliver, after charging for exchange rates and <a href="concept-transfer-fees.html">transfer fees</a>. The "Partial Payment" flag (<a href="reference-transaction-format.html#payment-flags"><strong>tfPartialPayment</strong></a>) allows a payment to succeed by reducing the amount received instead of increasing the amount sent. Partial payments are useful for <a href="tutorial-gateway-guide.html#bouncing-payments">returning payments</a> without incurring additional costs to oneself.</p>
<p>The amount of XRP used for the <a href="concept-transaction-cost.html">transaction cost</a> is always deducted from the senders account, regardless of the type of transaction.</p>
<p>Partial payments can be used to exploit naive integrations with the Ripple Consensus Ledger to steal money from exchanges and gateways. The <a href="#partial-payments-exploit">Partial Payments Exploit</a> section of this document describes how this exploit works and how you can avoid it.</p>
<h2 id="semantics">Semantics</h2>
<h3 id="without-partial-payments">Without Partial Payments</h3>
<p>When sending a Payment that does not use the Partial Payment flag, the <code>Amount</code> field of the transaction specifies the exact amount to deliver, and the <code>SendMax</code> field specifies the maximum amount and currency to send. If a payment cannot deliver the full <code>Amount</code> without exceeding the <code>SendMax</code> parameter, or the full amount cannot be delivered for any other reason, the transaction fails. If the <code>SendMax</code> field is omitted from the transaction instructions, it is considered to be equal to the <code>Amount</code>. In this case, the payment can only succeed if the total amount of fees is 0.</p>
<p>In other words:</p>
<pre><code>Amount + (fees) = (sent amount) ≤ SendMax
</code></pre>
<p>In this formula, "fees" refers to <a href="concept-transfer-fees.html">transfer fees</a> and currency exchange rates. The "sent amount" and the delivered amount (<code>Amount</code>) may be denominated in different currencies and converted by consuming Offers in the Ripple Consensus Ledger's decentralized exchange.</p>
<p class="devportal-callout note"><strong>Note:</strong> The <code>Fee</code> field of the transaction refers to the XRP <a href="concept-transaction-cost.html">transaction cost</a>, 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.</p>
<h3 id="with-partial-payments">With Partial Payments</h3>
<p>When sending a Payment that has the Partial Payment flag enabled, the <code>Amount</code> field of the transaction specifies a maximum amount to deliver. Partial payments can succeed at sending <em>some</em> of the intended value despite limitations including fees, lack of liquidity, insufficient space in the receiving account's trust lines, or other reasons.</p>
<p>The optional <code>DeliverMin</code> field specifies a minimum amount to deliver. The <code>SendMax</code> 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 <code>DeliverMin</code> field without exceeding the <code>SendMax</code> amount. If the <code>DeliverMin</code> field is not specified, a partial payment can succeed by delivering any positive amount.</p>
<p>In other words:</p>
<pre><code>Amount ≥ (Delivered Amount) = SendMax - (Fees) ≥ DeliverMin &gt; 0
</code></pre>
<h3 id="partial-payment-limitations">Partial Payment Limitations</h3>
<p>Partial Payments have the following limitations:</p>
<ul>
<li>A partial payment cannot provide the XRP to fund an address; this case returns the <a href="reference-transaction-format.html#transaction-results">result code</a> <code>telNO_DST_PARTIAL</code>.</li>
<li>Direct XRP-to-XRP payments cannot be partial payments; this case returns the <a href="reference-transaction-format.html#transaction-results">result code</a> <code>temBAD_SEND_XRP_PARTIAL</code>.<ul>
<li>However, issuance-to-XRP payments or XRP-to-issuance payments <em>can</em> be partial payments.</li>
</ul>
</li>
</ul>
<h3 id="the-delivered-amount-field">The <code>delivered_amount</code> Field</h3>
<p>To help understand how much a partial payment actually delivered, the metadata of a successful Payment transaction includes a <code>delivered_amount</code> field. This field describes the amount actually delivered, in the <a href="reference-rippled.html#specifying-currency-amounts">same format</a> as the <code>Amount</code> field.</p>
<p>For non-partial payments, the <code>delivered_amount</code> field of the transaction metadata is equal to the <code>Amount</code> field of the transaction. When a payment delivers an issued currency, the <code>delivered_amount</code> may be slightly different than the <code>Amount</code> field due to rounding.</p>
<p>The delivered amount is <strong>not available</strong> for transactions that meet <strong>both</strong> of the following criteria:</p>
<ul>
<li>Is a partial payment</li>
<li>Is included in a validated ledger before 2014-01-20</li>
</ul>
<p>If both conditions are true, then <code>delivered_amount</code> contains the string value <code>unavailable</code> 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 an issued currency and the <code>issuer</code> of the <code>Amount</code> is the same account as the <code>Destination</code> address, the delivered amount may be divided among multiple <code>AffectedNodes</code> members representing trust lines to different counterparties.</p>
<h2 id="partial-payments-exploit">Partial Payments Exploit</h2>
<p>If a financial institution's integration with the Ripple Consensus Ledger assumes that the <code>Amount</code> 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.</p>
<p>To exploit a vulnerable financial institution, a malicious actor does something like this:</p>
<ol>
<li>The malicious actor sends a Payment transaction to the institution. This transaction has a large <code>Amount</code> field and has the <strong>tfPartialPayment</strong> flag enabled.</li>
<li>The partial payment succeeds (result code <code>tesSUCCESS</code>) but actually delivers a very small amount of the currency specified.</li>
<li>The vulnerable institution reads the transaction's <code>Amount</code> field without looking at the <code>Flags</code> field or <code>delivered_amount</code> metadata field.</li>
<li>The vulnerable institution credits the malicious actor in an external system, such as the institution's own ledger, for the full <code>Amount</code>, despite only receiving a much smaller <code>delivered_amount</code> in the Ripple Consensus Ledger.</li>
<li>The malicious actor withdraws as much of the balance as possible to another system before the vulnerable institution notices the discrepancy.<ul>
<li>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.</li>
<li>In the case of an exchange, the malicious actor can also withdraw an XRP balance directly back into the Ripple Consensus Ledger.</li>
</ul>
</li>
</ol>
<p>In the case of a merchant, the order of operations is slightly different, but the concept is the same:</p>
<ol>
<li>The malicious actor requests to buy a large amount of goods or services.</li>
<li>The vulnerable merchant invoices the malicious actor for the price of those goods and services.</li>
<li>The malicious actor sends a Payment transaction to the merchant. This transaction has a large <code>Amount</code> field and has the <strong>tfPartialPayment</strong> flag enabled.</li>
<li>The partial payment succeeds (result code <code>tesSUCCESS</code>) but delivers only a very small amount of the currency specified.</li>
<li>The vulnerable merchant reads the transaction's <code>Amount</code> field without looking at the <code>Flags</code> field or <code>delivered_amount</code> metadata field.</li>
<li>The vulnerable merchant treats the invoice as paid and provides the goods or services to the malicious actor, despite only receiving a much smaller <code>delivered_amount</code> in the Ripple Consensus Ledger.</li>
<li>The malicious actor uses, resells, or absconds with the goods and services before the merchant notices the discrepancy.</li>
</ol>
<h3 id="avoiding-the-exploit">Avoiding the Exploit</h3>
<p>The simplest and most effective way to avoid partial payment exploits is to use the <code>delivered_amount</code> field of the transaction metadata, not the <code>Amount</code> field, when processing incoming transactions. This way, an institution is never mistaken about how much it <em>actually</em> received.</p>
<p>Additional proactive business practices can also avoid or mitigate the likelihood of this and similar exploits. For example:</p>
<ul>
<li>Add additional sanity checks to your business logic for processing withdrawals. Never process a withdrawal if the total balance you hold in the Ripple Consensus Ledger does not match your expected assets and obligations.</li>
<li>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.</li>
</ul>
</div>
</main>
</div>
<footer class="content-info" role="contentinfo">
<div class="container">
<div class="row">
<section class="col-sm-3 widget nav_menu-3 widget_nav_menu">
<h4>Resources<hr></h4>
<ul id="menu-resources" class="menu">
<li class="menu-insights"><a href="https://ripple.com/insights/">Insights</a></li>
<li class="menu-events"><a href="https://ripple.com/events/">Events</a></li>
<li class="menu-collateral"><a href="https://ripple.com/collateral/">Collateral</a></li>
<li class="menu-press-center"><a href="https://ripple.com/press-center/">Press Center</a></li>
<li class="menu-media-kit"><a href="https://ripple.com/media-kit/">Media Kit</a></li>
<li class="menu-xrp-portal"><a href="https://ripple.com/xrp-portal/">XRP Portal</a></li>
</ul>
</section>
<section class="col-sm-3 widget nav_menu-5 widget_nav_menu">
<h4>Regulators<hr></h4>
<ul id="menu-compliance-regulatory-relations" class="menu">
<li class="menu-compliance"><a href="https://ripple.com/compliance/">Compliance</a></li>
<li class="menu-policy-framework"><a href="https://ripple.com/policy-framework/">Policy Framework</a></li>
</ul>
</section>
<section class="col-sm-3 widget nav_menu-4 widget_nav_menu">
<h4>Support<hr></h4>
<ul id="menu-dev-footer-menu" class="menu">
<li class="menu-contact-us"><a href="https://ripple.com/contact/">Contact Us</a></li>
<li class="active menu-developer-center"><a href="https://ripple.com/build/">Developer Center</a></li>
<li class="menu-knowledge-center"><a href="https://ripple.com/learn/">Knowledge Center</a></li>
<li class="menu-ripple-forum"><a target="_blank" href="https://forum.ripple.com/">Ripple Forum</a></li>
</ul>
</section>
<section class="col-sm-3 widget nav_menu-2 widget_nav_menu">
<h4>About<hr></h4>
<ul id="menu-company-footer" class="menu">
<li class="menu-our-company"><a href="https://ripple.com/company/">Our Company</a></li>
<li class="menu-careers"><a href="https://ripple.com/company/careers/">Careers</a></li>
</ul>
</section>
<div class="col-sm-12 absolute_bottom_footer">
<div class="col-sm-8">
<span>&copy; 2013 - 2016 Ripple Labs, Inc. All Rights Reserved.</span>
<span><a href="/terms-of-use/">Terms</a></span>
<span><a href="/privacy-policy/">Privacy</a></span>
</div>
</div><!-- /.absolute_bottom_footer -->
</div><!-- /.row -->
</div><!-- /.container -->
</footer>
</body>
</html>