Description
The Soroban smart contract (contracts/src/lib.rs) uses panic!() for error conditions in deposit() and execute_rebalance(), while all other public functions consistently return Result<T, Error>. The inconsistency means on-chain callers (other contracts, SDK clients) cannot catch or recover from these panics — the transaction simply aborts with no structured error code.
Code Evidence
Inconsistent: deposit() uses panic!() — contracts/src/lib.rs
pub fn deposit(env: Env, portfolio_id: u64, amount: i64) {
if amount <= 0 {
panic!("Amount must be positive"); // ← Untyped panic
}
if let Some(true) = env.storage().instance().get(&DataKey::EmergencyStop) {
panic!("Emergency stop active"); // ← Untyped panic
}
// ...
}
Inconsistent: execute_rebalance() uses panic!()
pub fn execute_rebalance(env: Env, portfolio_id: u64) {
if let Some(true) = env.storage().instance().get(&DataKey::EmergencyStop) {
panic!("Emergency stop active"); // ← Untyped panic
}
// ...
}
Correct pattern used elsewhere in the same file
pub fn initialize(env: Env, admin: Address, reflector_address: Address) -> Result<(), Error> {
if env.storage().instance().has(&DataKey::Initialized) {
return Err(Error::AlreadyInitialized); // ← Typed error ✓
}
Ok(())
}
pub fn create_portfolio(...) -> Result<u64, Error> {
if !portfolio::validate_allocations(&target_allocations) {
return Err(Error::InvalidAllocation); // ← Typed error ✓
}
// ...
}
Why This Matters
In Soroban, panic!() terminates the contract call immediately with no error code. This means:
- Calling contracts cannot distinguish errors — a calling contract using
deposit() sees the same generic failure whether the amount was negative, the emergency stop was active, or an unrelated internal error occurred
- SDK clients cannot handle specific cases — frontend/backend code calling
deposit() via Stellar SDK must show a generic error rather than "Emergency stop is active — please wait"
- Inconsistency creates maintenance bugs — future contributors might assume all functions return typed errors and write error-handling code that never triggers for
deposit() and execute_rebalance()
Proposed Fix
1. Add missing error variants to contracts/src/types.rs
#[contracterror]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[repr(u32)]
pub enum Error {
// ... existing variants ...
InvalidAmount = 5, // amount <= 0
EmergencyStop = 6, // emergency stop is active
}
2. Update deposit() to return Result<(), Error>
pub fn deposit(env: Env, portfolio_id: u64, amount: i64) -> Result<(), Error> {
if amount <= 0 {
return Err(Error::InvalidAmount);
}
if let Some(true) = env.storage().instance().get(&DataKey::EmergencyStop) {
return Err(Error::EmergencyStop);
}
// ... rest of function ...
Ok(())
}
3. Update execute_rebalance() similarly
pub fn execute_rebalance(env: Env, portfolio_id: u64) -> Result<(), Error> {
if let Some(true) = env.storage().instance().get(&DataKey::EmergencyStop) {
return Err(Error::EmergencyStop);
}
// ...
Ok(())
}
4. Update contracts/src/test.rs to assert specific error codes
#[test]
fn test_deposit_rejects_negative_amount() {
// ...
let result = client.try_deposit(&portfolio_id, &-100i64);
assert_eq!(result, Err(Ok(Error::InvalidAmount)));
}
Files Affected
contracts/src/lib.rs — deposit() and execute_rebalance() (change signatures + replace panic!)
contracts/src/types.rs — add InvalidAmount and EmergencyStop error variants
contracts/src/test.rs — update tests to assert typed errors
Description
The Soroban smart contract (
contracts/src/lib.rs) usespanic!()for error conditions indeposit()andexecute_rebalance(), while all other public functions consistently returnResult<T, Error>. The inconsistency means on-chain callers (other contracts, SDK clients) cannot catch or recover from these panics — the transaction simply aborts with no structured error code.Code Evidence
Inconsistent:
deposit()uses panic!() —contracts/src/lib.rsInconsistent:
execute_rebalance()uses panic!()Correct pattern used elsewhere in the same file
Why This Matters
In Soroban,
panic!()terminates the contract call immediately with no error code. This means:deposit()sees the same generic failure whether the amount was negative, the emergency stop was active, or an unrelated internal error occurreddeposit()via Stellar SDK must show a generic error rather than "Emergency stop is active — please wait"deposit()andexecute_rebalance()Proposed Fix
1. Add missing error variants to
contracts/src/types.rs2. Update
deposit()to returnResult<(), Error>3. Update
execute_rebalance()similarly4. Update
contracts/src/test.rsto assert specific error codesFiles Affected
contracts/src/lib.rs—deposit()andexecute_rebalance()(change signatures + replace panic!)contracts/src/types.rs— addInvalidAmountandEmergencyStoperror variantscontracts/src/test.rs— update tests to assert typed errors