Audit · firm’s term: audit report
QuillAudits reviewed TAC2.0 (Dayvidende) on 12 Nov 2024: 8 findings, 0 critical; all marked fixed.
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 | 0 | 0 | 2 |
| Medium | 0 | 0 | 3 |
| Low | 0 | 0 | 3 |
When a user buys DVE tokens then level one/two/three referral gets some percentage of DVE tokens. Now the problem is, when combining the level one/two/three referral DVE amount, it became substantially higher than the actual buy amount.Let's see this via example: 1. Suppose there are 100 DVE tokens are for sale and user1 bought all 100 tokens. 2. Level1 referral will get 10% of amount ie `10 DVE` tokens 3. Level1 referrer has 10 Level2 referrals & they get 5% of amount ie 5 \* 10 = `50 DVE` tokens 4. Now, each Level2 referrer has 10 referrals & they get 2.5% of amount ie 2.5 \* 10 \* 10 = `250 DVE` tokens 5. Total referral DVE tokens = 10(Level1) + 50(Level2) + 250(Level3) = 310 DVE tokens, whereas only 100 DVE tokens were sold Impact would be that referral amount will be substantially high than the actual amount ie a large amount of DVE tokens will be vested, which are not present in the contract
Users can buy DVE tokens using buyTokens(), which give some percentage of DVE tokens to the referral. Tokens that referral gets are vested over a period of 1 year.```solidity function buyTokens(address ref, uint256 amount) external whenNotPaused { require(ref != msg.sender, "Cannot refer yourself"); require(ref != address(0), "Referral have to be entered"); require(amount > 0, "Must purchase a positive number of tokens"); @> require(amount < DVE.balanceOf(address(this)), "There are not enough tokens left to purchase"); bool paymentSuccessful = BUSD.transferFrom(msg.sender, address(this), amount); require(paymentSuccessful, "Payment was not successful"); bool success = DVE.transfer(msg.sender, amount); require(success, "Sending failed"); giveReferrals(ref, amount); amountPurchsed = amountPurchsed + amount; emit BuyTokens(msg.sender, amount); } Now the problem is, tokens that are allocated to referrals will also be sold to new users because buyTokens() uses the `balanceOf(address(this))` while selling the DVE tokens. This doesn't separate/reserves the tokens that are already allocated/vested to the referrals. 1. Suppose there are 100 DVE tokens & user1 bought 50 DVE tokens. 2. His referrals get 5 DVE tokens, vested over 1 year period 3. Now, user2 should only be able to buy 45 DVE tokens but he can buy complete 50 DVE tokens ie including referral's 5 DVE tokens
`DVESale` contract is used for selling DVE tokens using buyTokens(). However there can be situations when some DVE tokens are left `unsold` then there is no withdraw function for owner to withdraw those extra DVE tokens from the contract.Impact would be such that unsold DVE tokens will be `stuck` in the contract
When a user buys DVE tokens then referrals receive some percentage of purchased DVE amount. Only first 10 level2 & level3 referrals should receive the referral DVE tokens. But due to wrong position of if-statement(which breaks the loop), 11 referrals recives the DVE token amount instead of 10.```solidity function giveReferrals(address l1Ref, uint256 amount) internal { ... address[] memory l2Refs = previousReferrals[l1Ref]; for (uint256 i = 0; i < l2Refs.length; i++) { address l2Ref = l2Refs[i]; addClaim(l2Ref, l2Amount); total += l2Amount; address[] memory l3Refs = previousReferrals[l2Ref]; for (uint256 j = 0; j < l3Refs.length; j++) { address l3Ref = l3Refs[j]; addClaim(l3Ref, l3Amount); total += l3Amount; // Safety check to prevent gas limit issues @> if (j >= 10) { break; } } // Safety check to prevent gas limit issues @> if (i >= 10) { break; } } } ``` Due to the `=` sign & nature of array, loop will run form 0 to 11 ie [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
AggregatorV3Interface(bnbUsdFeed).latestRoundData() returns a variable `updatedAt`, which is the last timestamp when price was updated. For bnb/usd price oracle, heartbeat is 27s ie after every 27s price of bnb is updated.```solidity function getLatestBnbToUsd() public view returns (uint256) { (, int256 price,,,) = AggregatorV3Interface(bnbUsdFeed).latestRoundData(); return uint256(price); // 8 decimals } ``` If stale price is not checked, code will execute with prices that don’t reflect the current pricing.
dividend mapping is not used in DVESale.sol```solidity mapping(address => uint256) public dividend;
When recalculateClaim() is called, it checks for address(0) & sale address. But when it calls calculateDividend() internally, it also checks the for address(0) & sale address.```solidity function recalculateClaim(address who) internal { // null user doesn't get dividends @> if (who == address(0) || who == sale) { return; } ... uint256 oldDividend = claim.unclaimed; @> uint256 newDividend = calculateDividend(who, claim); ... } ``` ```solidity function calculateDividend(address who, Claim storage claim) internal view returns (uint256 dividend) { // null and the sale contract don't get dividends @> if (who == address(0) || who == sale) { return 0; } ... } ```
Full DVE tokens can't be sold in DVESale:buyTokens() due to use of `<` instead of `<=````solidity function buyTokens(address ref, uint256 amount) external whenNotPaused { require(ref != msg.sender, "Cannot refer yourself"); require(ref != address(0), "Referral have to be entered"); require(amount > 0, "Must purchase a positive number of tokens"); @> require(amount < DVE.balanceOf(address(this)), "There are not enough tokens left to purchase"); bool paymentSuccessful = BUSD.transferFrom(msg.sender, address(this), amount); require(paymentSuccessful, "Payment was not successful"); .... } ```
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (4)
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