Feat(soroban/permissions): add delegate status getter#166
Conversation
…exhausted, and paused states
📝 WalkthroughWalkthroughThe permissions contract adds a paused status, a delegate status view, stricter allowance checks, and owner authentication for allowance decreases. Tests were updated for the new status reporting and allowance behavior. ChangesPermissions lifecycle and status reporting
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@contracts/permissions/src/lib.rs`:
- Around line 117-119: The permission grant validation currently treats zero
per-tx limits as valid, which can make a delegation appear active even though it
can never authorize any spend. Update the validation and active-state logic in
the relevant grant construction and evaluation paths (including the branch
around limit_total/limit_per_tx and the corresponding code near can_spend) so
that limit_per_tx must be greater than zero, or otherwise ensure active is false
when no positive spend amount is possible. Apply the same fix in both matching
locations referenced by the existing grant logic.
- Around line 344-348: The pending decrease flow in the permission update path
allows queued decrements to become stuck because `decrease_permission` only
checks `record.limit_total` and does not reserve allowance during the delay.
Update the logic around `decrease_permission` and the execution check in the
permission apply path so a queued decrement cannot later fail when `new_limit <
record.spent`; instead, validate or account for the current spent amount at
queue time, and ensure any rejected or invalid pending decrement is cleared so
it does not block future decreases.
- Around line 280-286: The `get_delegate_status` API currently unwraps the
storage lookup for `DataKey::Permission`, which panics when no delegation
exists. Update `get_delegate_status` to handle the missing `PermissionRecord`
case the same way `can_spend` does by returning an inactive `DelegateStatusView`
with the appropriate reason instead of aborting. Keep the existing behavior for
present records, and use the
`get_delegate_status`/`PermissionRecord`/`DelegateStatusView` flow to locate the
change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: bb486ce1-f610-4bb2-8c5c-d311e2671ab9
📒 Files selected for processing (3)
contracts/permissions/src/integration_tests.rscontracts/permissions/src/lib.rscontracts/permissions/src/test.rs
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@contracts/permissions/src/lib.rs`:
- Around line 201-214: The delegate status logic is using the raw allowance
state and does not reflect pending decrements, so update get_delegate_status
(and the shared delegate status path it uses in the affected range) to subtract
the PendingDecrement amount just like can_spend does. Use the existing
PendingDecrement key lookup and effective remaining calculation so the returned
status reports the adjusted remaining value and marks the delegate inactive when
the effective allowance is exhausted.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 6b7c4b11-3a69-4785-bd1d-1c1e81d475c6
📒 Files selected for processing (2)
contracts/permissions/src/lib.rscontracts/permissions/src/test.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- contracts/permissions/src/test.rs
| let pend_key = DataKey::PendingDecrement(owner.clone(), delegate.clone()); | ||
| let pending_amount = match env.storage().persistent().get::<DataKey, PendingAllowanceDecrement>(&pend_key) { | ||
| Some(p) => p.amount, | ||
| None => 0, | ||
| }; | ||
|
|
||
| let remaining = record.limit_total - record.spent; | ||
| if amount > remaining { | ||
| let effective_remaining = if remaining > pending_amount { | ||
| remaining - pending_amount | ||
| } else { | ||
| 0 | ||
| }; | ||
|
|
||
| if amount > effective_remaining { |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Account for pending decrements in delegate status.
can_spend reserves pending_amount, but get_delegate_status ignores it. If a pending decrease equals the remaining allowance, every positive spend is rejected while the status still returns active: true and the raw remaining.
Proposed fix
- let key = DataKey::Permission(owner, delegate);
+ let key = DataKey::Permission(owner.clone(), delegate.clone());
let record: PermissionRecord = match env.storage().persistent().get(&key) {
Some(r) => r,
None => {
return DelegateStatusView {
active: false,
@@
- let remaining = if record.spent >= record.limit_total {
+ let raw_remaining = if record.spent >= record.limit_total {
0
} else {
record.limit_total - record.spent
};
+
+ let pend_key = DataKey::PendingDecrement(owner.clone(), delegate.clone());
+ let pending_amount = match env.storage().persistent().get::<DataKey, PendingAllowanceDecrement>(&pend_key) {
+ Some(p) => p.amount,
+ None => 0,
+ };
+
+ let remaining = if raw_remaining > pending_amount {
+ raw_remaining - pending_amount
+ } else {
+ 0
+ };
@@
- if record.spent >= record.limit_total {
+ if remaining == 0 {
return DelegateStatusView {
active: false,
reason: symbol_short!("exhausted"),
remaining,Also applies to: 309-359
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@contracts/permissions/src/lib.rs` around lines 201 - 214, The delegate status
logic is using the raw allowance state and does not reflect pending decrements,
so update get_delegate_status (and the shared delegate status path it uses in
the affected range) to subtract the PendingDecrement amount just like can_spend
does. Use the existing PendingDecrement key lookup and effective remaining
calculation so the returned status reports the adjusted remaining value and
marks the delegate inactive when the effective allowance is exhausted.
|
Resolve conflicts |
Summary
Type of change
Test plan
pnpm typecheckpnpm testChecklist
closes #100
Summary by CodeRabbit
New Features
Bug Fixes
Tests