# TreasureKey Security Assessment (WIP) # Findings ## Leftover dust tokens are not collectible https://github.com/treasurekey/treasurekey-contracts/blob/main/contracts/core/PirateBankBSC.sol#L208-L227 ```solidity= function processDividends(address token, uint amount) internal returns (uint dividendPayout) { dividendPayout = amount.mul(dividendRate).div(1000); uint wbnbAmount = 0; uint pirateAmount = 0; if (token == address(0)) { wbnbAmount = dividendPayout.div(2); pirateAmount = _swapFromBNB(tokenRouter[PIRATE], WBNB, dividendPayout.sub(wbnbAmount), PIRATE, address(this)); PANTHER_ROUTER.addLiquidityETH{value: wbnbAmount}(PIRATE, pirateAmount, 0, 0, address(this), block.timestamp); } else if (token == PIRATE) { return 0; } else { wbnbAmount = _swap(tokenRouter[token], token, dividendPayout, WBNB, address(this)); pirateAmount = _swap(tokenRouter[PIRATE], WBNB, wbnbAmount.div(2), PIRATE, address(this)); PANTHER_ROUTER.addLiquidity(WBNB, PIRATE, wbnbAmount.sub(wbnbAmount.div(2)), pirateAmount, 0, 0, address(this), block.timestamp); } uint256 pirateBNBAmount = ERC20(PIRATE_BNB).balanceOf(address(this)); ERC20(PIRATE_BNB).transfer(PIRATE_POOL, pirateBNBAmount); IStakingRewards(PIRATE_POOL).notifyRewardAmount(pirateBNBAmount); } ``` ### Issue Description There may be some dust of WBNB and/or PIRATE left on the balance of the contract after `addLiquidityETH`. There is no way to collect the leftover tokens. ### Recommendation Consider adding a `recoverToken` method that allows the owner to transfer tokens greater than the recorded amount. ```solidity= function recoverToken(address tokenAddress, uint tokenAmount) external onlyOwner{ if (tokenAddress == address(0)) { require(address(this).balance.sub(tokenAmount) >= tokenTotal[tokenAddress], "cannot recover token"); msg.sender.transfer(tokenAmount); } else { require(ERC20(tokenAddress).balanceOf(address(this)).sub(tokenAmount) >= tokenTotal[tokenAddress], "cannot recover token"); require(ERC20(tokenAddress).transfer(owner(), tokenAmount)); } } ``` --- ## `PirateBankBSC.sol#withdrawAll` should exclude principal for `processDividends` https://github.com/treasurekey/treasurekey-contracts/blob/main/contracts/core/PirateBankBSC.sol#L161-L173 ```solidity= if (token == address(0)) { // We naively send all BNB (minus dividends) since the owner of BNB is the owner uint payout = processDividends(token, totalBalance); msg.sender.transfer(totalBalance.sub(payout)); } else { // Transfer remaining funds to Treasure Key dev require(ERC20(token).transfer(owner(), earnings.sub(toReturn))); // Uses remaining funds to calculate dividend payouts uint remaining = totalBalance.sub(earnings.sub(toReturn)); uint payout = processDividends(token, remaining); // Transfer rest of funds to token owner minus dividends require(ERC20(token).transfer(tokenOwner[token], remaining.sub(payout))); } ``` ### Issue Description The current implementation of `PirateBankBSC.sol#withdrawAll` is including the principal in `processDividends`. As an example, consider the scenario of: - Principal: **100 PIRATE** - Earnings: **10 PIRATE** - Token Return Ratio: **50%** - Dividend Rate: **5%** The expected total dividend should be: $10 \times (1 - 0.5) \times 0.05 = 0.25$ While in the current implementation, it is: $( 100 - (10 - 10 \times 0.5)) \times 0.05=4.75$ ### Recommendation Change to: ```solidity= if (token == address(0)) { // We naively send all BNB (minus dividends) since the owner of BNB is the owner uint payout = processDividends(token, earnings); msg.sender.transfer(totalBalance.sub(payout)); } else { // Uses remaining funds to calculate dividend payouts uint remaining = earnings.sub(toReturn); uint payout = processDividends(token, remaining); // Transfer remaining funds minus dividends to Treasure Key dev require(ERC20(token).transfer(owner(), remaining.sub(payout))); // Transfer principal and toReturn to token owner require(ERC20(token).transfer(tokenOwner[token],totalBalance.sub(earnings).add(toReturn))); } ``` --- ## Unused function https://github.com/treasurekey/treasurekey-contracts/blob/main/contracts/core/PirateBankBSC.sol#L253-L257 ```solidity= function _approveTokenIfNeeded(address token) private { if (ERC20(token).allowance(address(this), address(PANTHER_ROUTER)) == 0) { ERC20(token).approve(address(PANTHER_ROUTER), uint(~0)); } } ``` ### Issue Description `_approveTokenIfNeeded(address token) private` is unused. ### Recommendation Consider removing the unused function.