Repository navigation
Conversation
The maintainer review of the upstream spec PR landed with two comments, so the task is active again. Record both decisions (receiver authorizer with self-managed and facilitator-delegated modes; no x402 nonce storage in UptoProxy), the open points okarcz decided, and the choices that emerged while writing the spec.
The bound key is now `receiver_authorizer`: the facilitator's key (facilitator-delegated) or the resource server's own key (self-managed). Its require_auth already covered actual_amount, so only the name changes, in the argument and the upto_settled event. Single use is Soroban's auth nonce. The contract no longer stores (from, nonce): `nonce` is a signed payment ID, a second entry with the same ID is a second payment the client signed and settles. BREAKING CHANGE: `is_nonce_used` and error 7 (`NonceUsed`) are gone; the `facilitator` argument and event field are `receiver_authorizer`. New WASM, new testnet address.
The signer pool refuses source-account auth entries, which kept the suite from settling. The receiver authorizer now signs its own address-credential entry for the call, the self-managed shape. The NonceUsed scenario becomes "settles a reused payment ID under a new signature". 58/58 on testnet against CDPHI4JY…EA2X.
Contract README, ADR 0010 (D6 amended, D12 added), threat model, the 2026-11-12 testnet run, the new testnet address and the scheme_upto_stellar.md draft: both receiver authorizer modes, payload.receiverAuthorization, single use through the auth nonce.
The seller's own account is the receiver authorizer: it signs its entry for the actual amount without simulation, and the other facilitator relays it through its own channel and fee bump. The reused-payment-ID scenario now uses fresh terms, so a slow run can't push it past its deadline. 61/61 on testnet.
Record every settlement before submitting it, so concurrent /settle calls don't pay for a doomed duplicate. In self-managed mode /verify reads the client's nonce entry, since recording-mode simulation can't see it. A facilitator that doesn't relay self-managed payments refuses them at /verify. Name extra.receiverAuthorizer in /supported, keep retired delegated keys, note that the settlement record is per facilitator, key rotation, and the 61/61 run.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Task 0034 (merge
uptofor Stellar upstream): the maintainer review of our upstream spec PR asked for two changes. This PR makes both in UptoProxy, redeploys it on testnet, runs the e2e suite again and updates the docs and the spec draft. It is for our team's review first: nothing has been posted upstream, and nothing will be until we agree on it here.contracts/upto-proxy/src/lib.rs): the bound key is nowreceiver_authorizer, either the facilitator's key (facilitator-delegated mode) or the resource server's own key (self-managed mode), as in the SVMuptospec. Itsrequire_auth()already coveredactual_amount, so only the name changes, in the argument and theupto_settledevent.is_nonce_usedand error 7 (NonceUsed) are gone, andnoncestays as a signed payment ID. A second entry signed with the same ID is a second payment, and it settles.CDPHI4JYNSWNAQFXUAZAWTBUBYLZZRWFU6F6EJIHLSTAL6MJWXOVEA2X(WASMa3d7bd0a…f666), now indeploy/testnet.env.example.CAL7SBTO…V2VCis retired.contracts/upto-proxy/e2e): the signer pool refuses source-account auth entries, which had kept the suite from settling until 0015. The receiver authorizer now signs its own address-credential entry. A new scenario covers self-managed mode: the seller's account signs the receiver authorization and another facilitator relays it.contracts/upto-proxy/README.md, ADR 0010 with D6 amended and D12 added,docs/threat-model.md,docs/upto-proxy-testnet-report.md): updated for both changes.docs/scf/milestone 1 files keep the old address on purpose, since they record what milestone 1 delivered.lore/1-tasks/active/0034_FEATURE_upstream-upto-stellar/drafts/scheme_upto_stellar.md): both modes,extra.receiverAuthorizer,payload.receiverAuthorization, single use through the auth nonce, and rewritten verification, settlement, error and security sections.Please confirm
/verifycan't run the enforcing simulation (payments): the server signs only at/settle./verifysimulates in recording mode and checks the client's signature and auth nonce itself. A smart-wallet client whose__check_authfails is therefore caught only at settlement, which the spec now lists under the server's credit risk.G...andC...accounts. AC...authorizer is verified only by the enforcing simulation under the fee ceiling, as a smart-wallet client is. Our seller SDK will sign with aG...key first.(from, auth nonce), not the payment ID, before every settlement. Zero settlements need it because they never reach the chain. Non-zero ones need it so that concurrent/settlecalls on one payload don't pay for a duplicate that would fail. The record is per facilitator, so in self-managed mode a server could still charge a zero-settled entry through another facilitator, within its ceiling. In self-managed mode a zero/settlestill needspayload.receiverAuthorization.allowance_expiration_ledger, because the facilitator pays the rent on its nonce./verifywithinvalid_upto_stellar_payload_receiver_authorization, so the server learns before it serves. In self-managed mode/verifyreads the client's nonce entry withgetLedgerEntries, because a recording-mode simulation can't see it.Testing
pnpm contracts:test→ 40 passed, 0 failed;pnpm contracts:test:wasm→ both WASM tests pass (onlysettle_uptoexported, 3,727 bytes).pnpm contracts:e2eon testnet, 2026-11-12 20:58 UTC → 61/61, 29 transactions, new proxyCDPHI4JY…EA2X.Error(Auth, ExistingValue).cfed0770…7ad9, UPTOE2Eca1ec753…7ce8, TEST5ed0e7af…975f).pnpm format:check(tracked files),pnpm lint,pnpm typecheck,pnpm build,pnpm contracts:lint→ pass.pnpm testwas not run locally, because no package code changed; CI runs it.