Skip to content

Commit eaffed1

Browse files
committed
deploy: b844c4d
1 parent c102148 commit eaffed1

7 files changed

Lines changed: 500 additions & 7 deletions

File tree

spec/guides/dispute-resolution/index.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,6 +2220,14 @@ <h2 id="failure-reasons">Failure Reasons</h2>
22202220
<td><code>grant_revoked</code></td>
22212221
<td>Revocation endpoint returned <code>{ revoked: true }</code></td>
22222222
</tr>
2223+
<tr>
2224+
<td><code>offline_cumulative_exceeded</code></td>
2225+
<td>Offline acceptance would exceed <code>PolicyGrant.offlineMaxCumulativePayment</code></td>
2226+
</tr>
2227+
<tr>
2228+
<td><code>offline_sba_replay</code></td>
2229+
<td>Same SBA / <code>budgetId</code> was already accepted at this verifier (local deduplication)</td>
2230+
</tr>
22232231
</tbody>
22242232
</table>
22252233
<h2 id="see-also">See Also</h2>

spec/protocol/PolicyGrant/index.html

Lines changed: 176 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1747,6 +1747,67 @@
17471747
</ul>
17481748
</nav>
17491749

1750+
</li>
1751+
1752+
<li class="md-nav__item">
1753+
<a href="#offline-cumulative-exposure" class="md-nav__link">
1754+
<span class="md-ellipsis">
1755+
1756+
Offline cumulative exposure
1757+
1758+
</span>
1759+
</a>
1760+
1761+
<nav class="md-nav" aria-label="Offline cumulative exposure">
1762+
<ul class="md-nav__list">
1763+
1764+
<li class="md-nav__item">
1765+
<a href="#risk" class="md-nav__link">
1766+
<span class="md-ellipsis">
1767+
1768+
Risk
1769+
1770+
</span>
1771+
</a>
1772+
1773+
</li>
1774+
1775+
<li class="md-nav__item">
1776+
<a href="#mitigation-offlinemaxcumulativepayment" class="md-nav__link">
1777+
<span class="md-ellipsis">
1778+
1779+
Mitigation: offlineMaxCumulativePayment
1780+
1781+
</span>
1782+
</a>
1783+
1784+
</li>
1785+
1786+
<li class="md-nav__item">
1787+
<a href="#per-verifier-scope" class="md-nav__link">
1788+
<span class="md-ellipsis">
1789+
1790+
Per-verifier scope
1791+
1792+
</span>
1793+
</a>
1794+
1795+
</li>
1796+
1797+
<li class="md-nav__item">
1798+
<a href="#error-code_2" class="md-nav__link">
1799+
<span class="md-ellipsis">
1800+
1801+
Error code
1802+
1803+
</span>
1804+
</a>
1805+
1806+
</li>
1807+
1808+
</ul>
1809+
</nav>
1810+
17501811
</li>
17511812

17521813
<li class="md-nav__item">
@@ -2793,6 +2854,67 @@
27932854
</ul>
27942855
</nav>
27952856

2857+
</li>
2858+
2859+
<li class="md-nav__item">
2860+
<a href="#offline-cumulative-exposure" class="md-nav__link">
2861+
<span class="md-ellipsis">
2862+
2863+
Offline cumulative exposure
2864+
2865+
</span>
2866+
</a>
2867+
2868+
<nav class="md-nav" aria-label="Offline cumulative exposure">
2869+
<ul class="md-nav__list">
2870+
2871+
<li class="md-nav__item">
2872+
<a href="#risk" class="md-nav__link">
2873+
<span class="md-ellipsis">
2874+
2875+
Risk
2876+
2877+
</span>
2878+
</a>
2879+
2880+
</li>
2881+
2882+
<li class="md-nav__item">
2883+
<a href="#mitigation-offlinemaxcumulativepayment" class="md-nav__link">
2884+
<span class="md-ellipsis">
2885+
2886+
Mitigation: offlineMaxCumulativePayment
2887+
2888+
</span>
2889+
</a>
2890+
2891+
</li>
2892+
2893+
<li class="md-nav__item">
2894+
<a href="#per-verifier-scope" class="md-nav__link">
2895+
<span class="md-ellipsis">
2896+
2897+
Per-verifier scope
2898+
2899+
</span>
2900+
</a>
2901+
2902+
</li>
2903+
2904+
<li class="md-nav__item">
2905+
<a href="#error-code_2" class="md-nav__link">
2906+
<span class="md-ellipsis">
2907+
2908+
Error code
2909+
2910+
</span>
2911+
</a>
2912+
2913+
</li>
2914+
2915+
</ul>
2916+
</nav>
2917+
27962918
</li>
27972919

27982920
<li class="md-nav__item">
@@ -3053,14 +3175,26 @@ <h3 id="policygrant-payload">PolicyGrant (payload)</h3>
30533175
<td>offlineMaxSinglePayment</td>
30543176
<td>string</td>
30553177
<td>optional</td>
3056-
<td>PA-signed per-transaction cap (in <code>offlineMaxSinglePaymentCurrency</code> minor units) for offline merchant acceptance. Offline merchants MUST reject SBAs whose <code>maxAmountMinor</code> exceeds this value. Cumulative budget is not enforced offline.</td>
3178+
<td>PA-signed per-transaction cap (in <code>offlineMaxSinglePaymentCurrency</code> minor units) for offline merchant acceptance. Offline merchants MUST reject SBAs whose <code>maxAmountMinor</code> exceeds this value. Cumulative offline exposure across merchants is only bounded when <code>offlineMaxCumulativePayment</code> is present; see <strong>Offline cumulative exposure</strong> below.</td>
30573179
</tr>
30583180
<tr>
30593181
<td>offlineMaxSinglePaymentCurrency</td>
30603182
<td>string</td>
30613183
<td>optional</td>
30623184
<td>Currency of <code>offlineMaxSinglePayment</code> (e.g. <code>"XRP"</code>).</td>
30633185
</tr>
3186+
<tr>
3187+
<td>offlineMaxCumulativePayment</td>
3188+
<td>string</td>
3189+
<td>optional</td>
3190+
<td>PA-signed maximum total amount (in <code>offlineMaxCumulativePaymentCurrency</code> minor units) that offline verifiers MAY cumulatively accept for this grant across all offline transactions at this verifier. Merchants SHOULD sum accepted amounts per <code>grantId</code> and reject when the next acceptance would exceed this cap. See <strong>Offline cumulative exposure</strong> below.</td>
3191+
</tr>
3192+
<tr>
3193+
<td>offlineMaxCumulativePaymentCurrency</td>
3194+
<td>string</td>
3195+
<td>optional</td>
3196+
<td>Currency of <code>offlineMaxCumulativePayment</code> (e.g. <code>"XRP"</code>). If absent while <code>offlineMaxCumulativePayment</code> is present, implementations SHOULD use <code>offlineMaxSinglePaymentCurrency</code>.</td>
3197+
</tr>
30643198
</tbody>
30653199
</table>
30663200
<hr />
@@ -3078,6 +3212,10 @@ <h2 id="example">Example</h2>
30783212
<span class="w"> </span><span class="nt">&quot;destinationAllowlist&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;rChargingStation1&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;rTollBooth42&quot;</span><span class="p">],</span>
30793213
<span class="w"> </span><span class="nt">&quot;merchantCredentialIssuer&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;rPAMerchantRegistry&quot;</span><span class="p">,</span>
30803214
<span class="w"> </span><span class="nt">&quot;merchantCredentialType&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;6D7063703A617070726F7665642D6D65726368616E74&quot;</span><span class="p">,</span>
3215+
<span class="w"> </span><span class="nt">&quot;offlineMaxSinglePayment&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;5000000&quot;</span><span class="p">,</span>
3216+
<span class="w"> </span><span class="nt">&quot;offlineMaxSinglePaymentCurrency&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;XRP&quot;</span><span class="p">,</span>
3217+
<span class="w"> </span><span class="nt">&quot;offlineMaxCumulativePayment&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;15000000&quot;</span><span class="p">,</span>
3218+
<span class="w"> </span><span class="nt">&quot;offlineMaxCumulativePaymentCurrency&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;XRP&quot;</span><span class="p">,</span>
30813219
<span class="w"> </span><span class="nt">&quot;maxSpend&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
30823220
<span class="w"> </span><span class="nt">&quot;perTxMinor&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;5000&quot;</span><span class="p">,</span>
30833221
<span class="w"> </span><span class="nt">&quot;perSessionMinor&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;20000&quot;</span>
@@ -3525,6 +3663,43 @@ <h3 id="error-code_1">Error Code</h3>
35253663
</tbody>
35263664
</table>
35273665
<hr />
3666+
<h2 id="offline-cumulative-exposure">Offline cumulative exposure</h2>
3667+
<h3 id="risk">Risk</h3>
3668+
<p>Without a cumulative offline cap, an agent can present SBAs to many offline merchants in
3669+
sequence. Each merchant enforces only <code>offlineMaxSinglePayment</code> per transaction. The <strong>total</strong>
3670+
offline spend can therefore exceed <code>budgetMinor</code> until the gateway reconciles on-chain.</p>
3671+
<h3 id="mitigation-offlinemaxcumulativepayment">Mitigation: <code>offlineMaxCumulativePayment</code></h3>
3672+
<p>When the PA includes <code>offlineMaxCumulativePayment</code>, offline verifiers that enforce this field
3673+
MUST maintain a running total of amounts already accepted for each <code>grantId</code> (in the grant's
3674+
offline minor units) and MUST reject a new SBA if accepting it would make the cumulative total
3675+
exceed <code>offlineMaxCumulativePayment</code>.</p>
3676+
<p>Currency for the cumulative cap is <code>offlineMaxCumulativePaymentCurrency</code>, or
3677+
<code>offlineMaxSinglePaymentCurrency</code> if the former is absent.</p>
3678+
<p>Operators SHOULD set <code>offlineMaxCumulativePayment</code><code>budgetMinor</code> (or lower, to reflect risk
3679+
tolerance). Operators SHOULD size <code>offlineMaxSinglePayment</code> with the <strong>expected number of
3680+
offline touchpoints</strong> per grant in mind — a small per-tx cap with many merchants can still
3681+
produce large aggregate exposure if no cumulative field is used.</p>
3682+
<h3 id="per-verifier-scope">Per-verifier scope</h3>
3683+
<p>The cumulative total is tracked <strong>per offline verifier</strong> (per device). Distinct merchants do
3684+
not share state; a fleet-wide cumulative bound requires synchronized infrastructure outside
3685+
the scope of this specification. The PA SHOULD set <code>offlineMaxCumulativePayment</code> assuming
3686+
worst-case fan-out across independent verifiers when modeling exposure.</p>
3687+
<h3 id="error-code_2">Error code</h3>
3688+
<table>
3689+
<thead>
3690+
<tr>
3691+
<th>Code</th>
3692+
<th>Meaning</th>
3693+
</tr>
3694+
</thead>
3695+
<tbody>
3696+
<tr>
3697+
<td><code>OFFLINE_CUMULATIVE_EXCEEDED</code></td>
3698+
<td>Acceptance would exceed <code>PolicyGrant.offlineMaxCumulativePayment</code></td>
3699+
</tr>
3700+
</tbody>
3701+
</table>
3702+
<hr />
35283703
<h2 id="summary">Summary</h2>
35293704
<p>PolicyGrant establishes the <strong>policy boundary</strong> for machine payments.</p>
35303705
<p>It ensures that downstream SBA artifacts are always derived from a <strong>validated policy evaluation</strong>.</p>

spec/protocol/mpcp/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,6 +2300,8 @@ <h3 id="step-3-verify-expiration">Step 3 — Verify Expiration</h3>
23002300
<li><code>SBA.expiresAt</code></li>
23012301
</ul>
23022302
<p>If any artifact is expired → <strong>reject settlement</strong>.</p>
2303+
<p>Comparisons use the verifier's wall clock; deployments SHOULD apply a clock drift tolerance as
2304+
described in <a href="../verification/#clock-synchronization-and-drift">Verification — Clock synchronization and drift</a>.</p>
23032305
<hr />
23042306
<h3 id="step-4-submit-and-return-receipt">Step 4 — Submit and Return Receipt</h3>
23052307
<p>If all verification steps succeed, the gateway submits the XRPL transaction:</p>
@@ -2723,6 +2725,10 @@ <h1 id="error-codes">Error Codes</h1>
27232725
<td><code>subjectCredentialIssuer</code> is set but the agent does not hold a matching on-chain credential</td>
27242726
</tr>
27252727
<tr>
2728+
<td>OFFLINE_CUMULATIVE_EXCEEDED</td>
2729+
<td>Offline acceptance would exceed <code>PolicyGrant.offlineMaxCumulativePayment</code></td>
2730+
</tr>
2731+
<tr>
27262732
<td>SCOPE_UNSUPPORTED</td>
27272733
<td>Authorization scope is not supported by the verifier</td>
27282734
</tr>

0 commit comments

Comments
 (0)