Summary
33 .unwrap() calls across the three contract crates (vault: 9, blend-adapter: 15, defindex-adapter: 9), none individually audited for whether they sit on genuinely infallible paths. Prior work removed panic!/.expect() in favor of typed errors, but .unwrap() panics identically on None/Err and was left out of that pass.
Motivation
A panic in a Soroban contract aborts the transaction, better than silent wrong behavior, but still means unexpected user-facing failures for a case a typed ContractError could have surfaced cleanly instead. Given the prior effort to move panic!/.expect() to typed errors, leaving .unwrap() unaudited is an inconsistency in that same effort, not a new problem.
Proposed Solution
Go through each .unwrap() call in vault/src/lib.rs, blend-adapter/src/lib.rs, defindex-adapter/src/lib.rs. For each: either replace with a typed ContractError return if the None/Err case is reachable by any caller input, or leave as-is with a short comment stating why it's genuinely infallible (e.g. unwrapping a value just checked with is_some() two lines above).
Scope
| Field |
Value |
| Area |
Contracts |
| Protocol affected |
Both |
| Network |
N/A |
| Breaking change? |
No (internal error handling only) |
Alternatives Considered
Leaving as-is: each individual .unwrap() may well be safe, but with no audit trail, that's an assumption, not a verified fact.
Acceptance Criteria
Summary
33
.unwrap()calls across the three contract crates (vault: 9, blend-adapter: 15, defindex-adapter: 9), none individually audited for whether they sit on genuinely infallible paths. Prior work removedpanic!/.expect()in favor of typed errors, but.unwrap()panics identically onNone/Errand was left out of that pass.Motivation
A panic in a Soroban contract aborts the transaction, better than silent wrong behavior, but still means unexpected user-facing failures for a case a typed
ContractErrorcould have surfaced cleanly instead. Given the prior effort to movepanic!/.expect()to typed errors, leaving.unwrap()unaudited is an inconsistency in that same effort, not a new problem.Proposed Solution
Go through each
.unwrap()call invault/src/lib.rs,blend-adapter/src/lib.rs,defindex-adapter/src/lib.rs. For each: either replace with a typedContractErrorreturn if theNone/Errcase is reachable by any caller input, or leave as-is with a short comment stating why it's genuinely infallible (e.g. unwrapping a value just checked withis_some()two lines above).Scope
Alternatives Considered
Leaving as-is: each individual
.unwrap()may well be safe, but with no audit trail, that's an assumption, not a verified fact.Acceptance Criteria
.unwrap()in the three crates is either replaced with a typed error or has a comment justifying it's infalliblecargo clippy --all-targets -- -D warningsandcargo testpass