Skip to content

[Bug]: remove_asset uses exact string match while add_asset uses case-insensitive match for the same asset identity #93

Description

@ndii-dev

Context

GlobeWallet::add_asset vs. GlobeWallet::remove_asset, contracts/globe-wallet/src/lib.rs. Since issue #29, add_asset treats asset codes as equal case-insensitively for duplicate detection. remove_asset was never updated to match.

Problem

// add_asset's duplicate check:
if Self::codes_match_case_insensitive(&assets.get(i).unwrap().code, &asset.code) {
    return Err(WalletError::AssetAlreadyAdded);
}

// remove_asset's lookup:
if a.code == asset_code { // exact match only
    found = true;
} else {
    new_assets.push_back(a);
}

The registry treats "USDC" and "usdc" as the same asset for the purpose of preventing a second registration, but as different assets for the purpose of removal.

Reproduction steps

#[test]
fn test_remove_asset_case_mismatch_fails_to_find_registered_asset() {
    let (env, _cid, admin, client) = setup();
    let user = Address::generate(&env);
    client.add_asset(&user, &usdc(&env)); // registers "USDC"

    // A client that passes through user input verbatim (e.g. a lowercase
    // ticker typed into a search/filter box before calling remove) can't
    // remove the asset it just displayed as present.
    let result = client.try_remove_asset(&user, &String::from_str(&env, "usdc"));
    assert_eq!(result, Err(Ok(WalletError::AssetNotFound))); // asset IS registered, just under different casing
    assert_eq!(client.get_assets(&user).len(), 1); // still there, unremoved
}

Impact

Lower severity than the other issues in this batch — no fund loss — but a real, confusing correctness bug: a user (or an integration built against get_assets's returned casing vs. whatever casing a different code path happens to use) can be unable to remove an asset they can clearly see is registered, with an error (AssetNotFound) that gives no hint the real problem is casing rather than the asset genuinely being absent.

Suggested fix

Use codes_match_case_insensitive in remove_asset's lookup, the same way add_asset already does for its duplicate check — one canonicalization rule for asset-code identity, applied consistently everywhere that identity is compared.

Definition of done

  • remove_asset uses case-insensitive matching to find the asset to remove
  • Test proving an asset registered as "USDC" can be removed by passing "usdc" (or any case variant)
  • Test proving remove_asset still correctly returns AssetNotFound for a code that genuinely isn't registered under any casing
  • cargo test --workspace output pasted

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignbugSomething isn't workingvery hardDifficulty: very hard

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions