Summary
The function KittyConnect.sol::_updateOwnershipInfo()
neglects to remove the transferred item from the array KittyConnect.sol::s_ownerToCatsTokenId
.
Vulnerability Details
Upon transfer of an item to another address via KittyConnect.sol::safeTransferFrom()
, the item is correctly added to the receiver's address mapping. However, it remains in the sender's mapping, resulting in inaccurate data.
Impact
It will show incorrect information when calling the getter KittyConnect.sol::getCatsTokenIdOwnedBy()
.
Proof of Code
Code
function test_tokenIsNotRemoved() public {
address someUser = makeAddr("someUser");
address otherUser = makeAddr("otherUser");
string
memory catImageIpfsHash = "ipfs://QmbxwGgBGrNdXPm84kqYskmcMT3jrzBN8LzQjixvkz4c62";
vm.prank(partnerA);
kittyConnect.mintCatToNewOwner(
someUser,
catImageIpfsHash,
"Hehe",
"Hehe",
block.timestamp
);
vm.prank(someUser);
kittyConnect.approve(otherUser, 0);
vm.prank(partnerA);
kittyConnect.safeTransferFrom(someUser, otherUser, 0);
uint256[] memory userTokenIDs = kittyConnect.getCatsTokenIdOwnedBy(
someUser
);
uint256 tokenStillThere = userTokenIDs[0];
assertEq(tokenStillThere, 0);
}
Tools Used
Manual review.
Recommendations
Update the array accordingly in function KittyConnect.sol::_updateOwnershipInfo()
:
function _updateOwnershipInfo(
address currCatOwner,
address newOwner,
uint256 tokenId
) internal {
s_catInfo[tokenId].prevOwner.push(currCatOwner);
s_catInfo[tokenId].idx = s_ownerToCatsTokenId[newOwner].length;
s_ownerToCatsTokenId[newOwner].push(tokenId);
+ uint256[] memory userTokenIds = s_ownerToCatsTokenId[msg.sender];
+ uint256 lastItem = userTokenIds[userTokenIds.length - 1];
+ s_ownerToCatsTokenId[msg.sender].pop();
+ if (idx < (userTokenIds.length - 1)) {
+ s_catInfo[lastItem].idx = idx;
+ s_ownerToCatsTokenId[msg.sender][idx] = lastItem;
}
}