Contract fails to deliver promised returns, but doesn't lose value
Description
Brief/Intro
royalty_manager.register_royalty_info is used to set RoyaltyInfo by the owner/admin of NFT token, however, in current implementation, there is an issue that when a NFT has both owner and admin, the RoyaltyInfo can only be set by the owner.
Vulnerability Details
According to royalty_manager.register_royalty_info, the RoyaltyInfo can be set by NFT's owner or admin. But there is a flow in royalty_manager#L55-L65, if the NFT has an owner, and the msg_sender is not the owner, the function will revert even the msg_sender is the NFT's amdin
48 fn register_royalty_info(49 collection: ContractId,50 receiver: Identity,51 fee: u6452){53let ownable =abi(Ownable, collection.into());5455if(ownable.owner().is_some()){<<<--- In thisif branch,if the msg_sender is not the NFT's owner, the functionwillrevert.56letcaller = msg_sender().unwrap();57let collection_owner = ownable.owner().unwrap();58require(caller == collection_owner, RoyaltyManagerErrors::CallerMustBeOwnerOrAdmin);59}elseif(ownable.admin().is_some()){60let caller =msg_sender().unwrap();61let collection_admin = ownable.admin().unwrap();62require(caller == collection_admin, RoyaltyManagerErrors::CallerMustBeOwnerOrAdmin);63}else{64revert(111)65}6667require(fee <=storage.fee_limit.read(), RoyaltyManagerErrors::FeeHigherThanLimit);6869let info = RoyaltyInfo {70 collection: collection,71 receiver: receiver,72 fee: fee73};7475let option_info: Option<RoyaltyInfo>= Option::Some(info);76storage.royalty_info.insert(collection, option_info);7778log(RoyaltyRegistryEvent {79 royalty_info: info80});81}
Impact Details
If a NFT has both owner and admin, the admin can't call royalty_manager.register_royalty_info.
References
Add any relevant links to documentation or code
Proof of concept
Proof of Concept
POC
please use the follow code as NFT contract
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 shown above, tx will revert when the royalty_manager.register_royalty_info is called by wallet_3, which is set as admin for ERCOwnerAndAdmin. And if the royalty_manager.register_royalty_info is called by wallet_1 (which is set as owner of ERCOwnerAndAdmin), the function will not revert.