Repository navigation
feat: capped delegated withdrawal session keys with revocation - #409
Conversation
|
@deborahogunjinmi592-byte Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
👷 Deploy request for streampay-org pending review.Visit the deploys page to approve it
|
|
Review (2026-10-21, head 0. Your branch no longer merges, and that changes what the red CI means. Against current 1. 257 of your added lines are in a directory nothing builds — but that's a repo problem too, and I'll own it. 2. Codes 64–70 are already taken, and 16 live variants get pushed up to 71–86. plus the same 16-variant shift ( 3. 4. Event fields renamed without their constructors. Same as #407: 5. 6. CI is red on Contract, Devcontainer, Perf budgets and claim-to-code. The first two follow from (1)/(3); Perf is the un-regenerated catalog ( 7. Bottom line: request changes — rebase onto |
d919a74 to
e19f86b
Compare
Strips the payload this branch picked up (deleted frontend/api.js, truncated frontend/eslint.config.mjs, unhooked frontend/package.json). No functional change to the branch's own work.
|
@Neziahtech — this PR is ready for another review. I resolved the merge conflicts with the main branch (pushed b2e5f27). |
|
Heads-up after a
Why the field had to widen: the committed storage-layout corpus pins the released v0.3.0 shape, in which the key does not exist at all. Soroban's generated struct decoder unpacks over a VOID-initialised field slice, so an absent key arrives as VOID and What this means for #409 at head That now hands Two other things moved on
|
|
Review after #426 landed (2026-10-25) — the feature is the right one for issue #56, but this cannot be merged by rebasing alone: at this head the contract does not compile, and the diff also renumbers error codes that are already deployed. 1. The implementation is in the wrong crate, so the contract crate cannot build. 2. Undefined identifiers on top of that. 3. You shifted 23 existing codes. 4. The tail is no longer free either. Your branch is based on 5f7944e (86 codes); #426 merged as 0d01aab and took 87–98, so main at 07f495c has 98 codes and the next free is 99. Your 87–93 values now duplicate live discriminants, so even the renumbered version has to move. Target 99–105 for 5. Four new events, zero registration. 6. Please leave 7. Small churn to drop: One nit for the rewrite: Otherwise the semantics are what I want: recipient-issued session keys, a fixed window anchored at authorization time with per-period and lifetime caps, a monotonic nonce, expiry checked before nonce consumption so a stale session can't burn one, and session effects persisted before |
|
@Neziahtech — this PR is ready for another review. I resolved the merge conflicts with the main branch (pushed 75b947f). |
|
Fleet re-check (2026-10-27) — GitHub reports this mergeable, and that is exactly the trap: if it merged today it would delete four shipped contract modules and move 36 released error codes. Please don't rebase-and-push this branch as it stands; it needs rebuilding on current State: head
The feature is wanted (issue #56 is still open and this is the third attempt at it), so I'd rather send you back with a precise list than close it: re-create from |
|
@Neziahtech — this PR is ready for another review. I resolved the merge conflicts with the main branch (pushed 9ad4a67). |
9ad4a67 to
5a1d1ad
Compare
|
Warning Possible malicious code: please review before merging. An automated security scan flagged files in this pull request that appear to contain malicious code. Code like this can run automatically when a project is opened in an editor or its dependencies are installed, so it could compromise the machine of anyone who checks out this branch. Automated scans can be wrong, so this may be a false positive. Maintainers: please review the flagged files carefully before merging, on GitHub in your browser rather than by checking out the branch. The malicious part is often hidden far off to the right of an ordinary-looking line, so scroll sideways through each file. @deborahogunjinmi592-byte: this pull request adds or changes these files, possibly without your knowledge. Malware like this spreads by adding itself to repositories on machines it has infected, so your machine might be compromised. Please undo these changes in this pull request, and don't open or run other projects on that machine until you've checked it. Flagged files at commit
Only merge once you're confident these files are safe. ℹ️ Posted automatically by Drips Wave. Questions? Contact support@drips.network. |
Overview
This PR adds session keys for the streaming-payments contract: recipients can authorize a hot wallet / automation agent to call
withdrawunder strict, on-chain-enforced caps (max per period, max per stream, expiry). Caps are tracked per(agent, stream)in a contract-owned ledger, so a compromised or misbehaving agent can never exceed the recipient's declared limits, and the recipient can revoke at any time. This enables payroll bots and automation agents to claim safely without handing over full withdrawal authority.Related Issue
Changes
🔑 Delegated Withdrawal Session Keys
[MODIFY]
contracts/streaming-payments/src/lib.rsauthorize_agent(recipient, agent, stream_id, caps, expiry)— recipient-signed authorization that records a cap entry in the per-(agent, stream)ledger.withdraw_delegated(agent, stream_id, amount, ...)— verifies the agent's signature via Sorobanverify_sig, checks expiry, and enforces per-period and per-stream caps before delegating to the existingwithdrawpath.revoke_agent(recipient, agent, stream_id)— recipient-only revocation entrypoint that clears the cap entry immediately.(agent, stream_id, window_index); window index is derived from ledger time and the configured period. Fixed windows were chosen over rolling windows to keep storage bounded (one entry per window, TTL-extendable) and to make cap accounting O(1) per withdrawal — rolling windows would require per-withdrawal history and unbounded TTL churn.[ADD]
contracts/streampay/src/agents.rs[MODIFY]
contracts/streampay/src/types.rsAgentCaps(max per period, max per stream, period length, expiry) andAgentAuthorizationtypes; cap-ledger entry type.[MODIFY]
contracts/streampay/src/admin.rs[MODIFY]
contracts/streaming-payments/src/errors.rsAgentNotAuthorized,AgentExpired,CapExceededPerPeriod,CapExceededPerStream,InvalidCaps.[MODIFY]
contracts/streaming-payments/src/events.rsagent_authorized,agent_revoked, anddelegated_withdrawevents carrying agent, stream, amount, and remaining cap.[ADD]
docs/KEY_COMPROMISE_TEMPLATE.mdrevoke_agentcall, bounded revocation latency (revocation is effective on the next ledger; any in-flight delegated withdrawal already past signature verification but not yet applied is rejected because the cap entry is read at execution time), and post-incident cap re-issuance steps.🧪 Tests
verify_sigsupports ed25519 and secp256r1; ed25519 chosen for agent keys (smaller payloads, native support, matches SEP-42 delegation conventions). Documented in the security notes below.Security Notes
min(remaining period cap, remaining stream cap)per window until revocation. Caps are enforced by the contract, not the signer.revoke_agentclears the cap entry in the same transaction; any delegated withdrawal that reads the ledger after revocation fails withAgentNotAuthorized. Latency is bounded by ledger close time (one ledger).authorize_agentwithAgentCapswithdraw_delegatedchecks cap ledger before withdrawal(agent, stream)with justified window modelrevoke_agentdocs/KEY_COMPROMISE_TEMPLATE.mdverify_sig, rationale aboveCloses #56