Skip to content

fix(escrow): implement InsufficientBalance and remove NotExpired - #70

Open
Devadakene wants to merge 1 commit into
MergeFi:mainfrom
Devadakene:fix/escrow-unused-errors
Open

fix(escrow): implement InsufficientBalance and remove NotExpired#70
Devadakene wants to merge 1 commit into
MergeFi:mainfrom
Devadakene:fix/escrow-unused-errors

Conversation

@Devadakene

Copy link
Copy Markdown

Closes #48

Overview

This PR addresses the presence of two unused error variants in the Escrow contract's public ABI: Error::NotExpired and Error::InsufficientBalance.

After investigating the git history, it was confirmed that both variants were dead scaffolding introduced in the initial commit (d17fc888) and were never actually wired up in the contract logic.

As part of this cleanup:

  1. InsufficientBalance has been implemented as a genuine defense-in-depth check in the release and refund operational flows.
  2. NotExpired has been removed from the ABI as it serves no purpose.

Changes

1. Enforcing InsufficientBalance Check

The escrow's release and refund operations previously trusted the original escrow.amount recorded at the time of funding without verifying the contract's actual on-chain token balance before transferring.

While Soroban's token_client.transfer inherently panics on insufficient funds, explicitly verifying the balance allows the contract to fail gracefully with a typed Error::InsufficientBalance. This is a meaningful defense-in-depth addition that aligns with the maintenance-pool contract's approach. It guarantees the solvency invariant (balance covers obligations) is proactively verified at runtime at the exact moment of payment.

Files modified: contracts/escrow/src/lib.rs

  • Added explicit balance validation token_client.balance(&contract_address) < escrow.amount to the release function.
  • Added explicit balance validation token_client.balance(&contract_address) < escrow.amount to the refund function.

2. Removing NotExpired

NotExpired was determined to be a relic with no structural purpose, given that early refunds are protected natively by require_auth panics rather than typed error results.

To clean up the ABI, NotExpired has been removed entirely.

Files modified: contracts/escrow/src/error.rs

  • Removed NotExpired = 10.
  • Note: An explicit comment has been left in its place documenting that this removal is an ABI-breaking change for any external client matching on specific error codes, ensuring the rationale is preserved for downstream integrations.

3. Testing

Tests were added to explicitly verify that the contract properly intercepts and rejects payouts with Error::InsufficientBalance when the token balance is artificially drained.

Files modified: contracts/escrow/src/test.rs

  • Added test_release_rejects_if_contract_balance_insufficient: Simulates draining the contract balance prior to an admin release and asserts Error::InsufficientBalance is returned.
  • Added test_refund_rejects_if_contract_balance_insufficient: Simulates draining the contract balance prior to a post-deadline permissionless refund and asserts Error::InsufficientBalance is returned.

Acceptance Criteria Met

  • Investigation into NotExpired/InsufficientBalance origin concluded and documented.
  • InsufficientBalance is fully wired into release and refund as a genuine defensive balance check.
  • NotExpired variant removed with an explicitly documented rationale in the source.
  • Comprehensive unit tests added.

- Wired InsufficientBalance into release and refund as a defensive check against the contract's actual token balance, making the solvency invariant enforced at runtime.

- Removed NotExpired as it was confirmed to be unused scaffolding.

- Added tests to verify InsufficientBalance check.
@vercel

vercel Bot commented Aug 18, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the chonilius' projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

escrow: dead NotExpired/InsufficientBalance error variants suggest a missing defensive balance check in release()/refund()

1 participant