Audit · firm’s term: audit report
QuillAudits reviewed Yugcoins (TRG) on 4 Nov 2022: 16 findings, 0 critical; 11 marked fixed, 5 open.
Report hosted on quillaudits.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 1 | 0 | 2 |
| Medium | 1 | 0 | 4 |
| Low | 3 | 0 | 5 |
performUpkeep() is a public function which can be called by anyone but contains a critical function distributeRewardsAndRugLoser(). This can be exploited by anyone to Rug losers quickly in short span of time by directly calling the performUpKeep function, resulting in the game to get over earlier than expected. This could also result in Denial of service and unfair manipulation of the game.
setsTrg() lacks access control and can be called by anyone to change the sTrg address to any address.
_buyAndBurnToken() function in susceptible to Frontrun attack. This is because the _amountOutMin parameter is set to 0. This is not recommended as this results in 100% slippage and can be frontrunned by attackers and bots especially in a low liquidity pool. Similarly _rugLoser() function is susceptible to frontrun attack (see line: 242). For example, a sandwich attack is possible(which consists of a frontrun and a backrun) to snipe funds from a swap by placing a buy order(with higher gas price) before the user's order and a sell order after the user's order. This would result in the attacker buying at a low price, which results in a costlier trade for the user and then selling at a slightly higher price after the user's trade. This attack is significant especially in the trades that are larger in size/amount. So here it would mean the transfers of large amounts of THERUGGAME tokens while buying and selling them.
The rewards to the stakers of TRG tokens, in the STRG contract are sent in terms of TRG tokens. But the STRG contract does not hold the TRG tokens that are expected to be given for reward. This is because, according to the current logic, the TRG tokens are sent after the stakers have staked some amount of tokens. Only after this, the dividendPerToken variable in TRG contract is updated, thus giving non-zero rewards. But these TRG tokens are sent by the admin, which brings in centralization for providing the rewards to the stakers. If the TRG tokens are not sent to STRG contract(after the stakers have staked), then the stakers will get no rewards. Also note that currently it is not possible to send TRG tokens to the STRG contract before any stakers come in. This is because the totalStaked is 0, thus giving a panic on line: 42 in TRG contract. Another issue is that if the TRG tokens are manually sent to the STRG contract each time by the admin for allocating a pool of rewards to the users, an attacker can front run this transaction to deposit a large amount of tokens and then backrun it with withdrawal of his stake, thus sandwiching a substantial amount of rewards, which is unfair to the current stakers(See sandwich attacks).
In function bribe the following if statement is incorrect and Insufficient. bool isRugged = IERC20(pair).balanceOf(factory) == 0; This is not a foolproof way to check if a token in the game has been rugged or not. This is because even if the token is Rugged according the flow, still the factory contract can be sent tokens thus setting the isRugged variable to false even if it should have been true.
Draft EIPs. The following EIPs are still in Draft status. Due to their nature as drafts, the details of these contracts may change and we cannot guarantee their stability. Minor releases of OpenZeppelin Contracts may contain breaking changes for the contracts in this directory, which will be duly announced in the changelog. The EIPs included here are used by projects in production and this may make them less likely to change significantly.”
pendingRewards() amount is an unsigned integer member of UserInfo struct and can never be less than zero. if (user.amount <= 0) return 0; pendingRewards() The same goes for emergencyWithdraw() function. if (user.amount <= 0) revert NotEnoughDeposit(); emergencyWithdraw() Also in the claimReward() function, userRewards is checked if its less than or equal to zero. But the following less than zero statement is not required as pendingRewards() returns an unsigned integer which can never be less than zero. if (userReward <= 0) revert NotEnoughRewards(); claimReward()
getWinner() always shows some winner. This can be misleading. Bcoz this winner may not necessarily be the winner of this round and points can change
The afterBalance variable holds the value of the token after the beforeBalance is subtracted from the current balance. This is the balance change, not afterBalance; it is slightly misleading and does not convey the intended message.
ERC20Permit is not needed to be inherited as ERC20Votes already inherits it.
The solidity pragma version is kept unlocked in STRG.sol
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (8)
350 projects reviewed · 459 reports · latest Apr 2025
See QuillAudits’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us