IOP _ ThunderNFT 34943 - [Smart Contract - High] User cant withdraw asset from pool after asset_mana

Submitted on Sun Sep 01 2024 16:12:44 GMT-0400 (Atlantic Standard Time) by @jasonxiale for IOP | ThunderNFT

Report ID: #34943

Report type: Smart Contract

Report severity: High

Target: https://github.com/ThunderFuel/smart-contracts/tree/main/contracts-v1/pool

Impacts:

  • Permanent freezing of funds

Description

Brief/Intro

asset_manager.add_asset and asset_manager.remove_asset are used to control which asset are allowed in the pool. And when pool.deposit and pool.withdraw are called, the functions checks if the assetId is supported by asset_manager.is_asset_supported.

However there is an issue that after asset_manager.remove_asset is called, the corresponding asset in the pool can't be withdrawn.

Vulnerability Details

As shown in pool.withdraw, when a user calls the function to withdraw asset, the function will check if the asset is supported in pool#L112, and if not, the function will revert.

105     fn withdraw(asset: AssetId, amount: u64) {
106         let sender = msg_sender().unwrap();
107         let current_balance = _balance_of(sender, asset);
108         require(current_balance >= amount, PoolErrors::AmountHigherThanBalance);
109 
110         let asset_manager_addr = storage.asset_manager.read().unwrap().bits();
111         let asset_manager = abi(AssetManager, asset_manager_addr);
112         require(asset_manager.is_asset_supported(asset), PoolErrors::AssetNotSupported); <<<<<----- here checks if the assetId is supported by asset_manager
113 
114         let new_balance = current_balance - amount;
115         storage.balance_of.insert((sender, asset), new_balance);
116 
117         transfer(sender, asset, amount);
118 
119         log(Withdrawal {
120             address: sender,
121             asset,
122             amount,
123         });
124     }

Impact Details

Please consider a case that:

  1. the asset_manager's owner calls asset_manager.add_asset to add assetId_x

  2. Alice deposit some assetId_x by calling pool.deposit

  3. after a while, the asset_manager's owner calls asset_manager.remove_asset to remove the assetId_x

  4. When Alice calls pool.withdraw to withdraw her assetId_x, the function will revert in pool#L112

References

Add any relevant links to documentation or code

Proof of concept

Proof of Concept

Please generate a Rust test template under thunder_exchange folder, and puts the following code in thunder_exchange/tests/harness.rs and run cargo test -- --nocapture

As the code shows, the pool.withdraw will be revert with AssetNotSupported

Last updated

Was this helpful?