Old IDO & NFT Launchpads Upgrades (Agency Work)

CertiKFiles named in the report

CertiK reviewed Seedify (Old IDO & NFT Launchpads Upgrades (Agency Work)) on 3 Jan 2023: 15 findings, 0 critical; 11 marked fixed, 4 open.

No open critical findings
Open the reportOpen Seedify’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings15

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High102
Medium101
Low208
HighIncrementing only `buyInOneTier` can cause usersFixed

In `buyTokens()` it is checked if the `msg.sender` is whitelisted for the input `tier`. If they are not it reverts, but if they are it then increments `buyInOneTier[msg.sender]` by the input `amount`. The name implies that it is keeping track of the amount bought for tier one, however it keeps track of the amount bought by `msg.sender` in all tiers. This can cause issues if a user buys in different tiers. For example, if a user buys 100,000 tokens in tier 1 and also buys 100,000 tokens in tier 2. After the `refundThresholdTime` the user could call `refund(1,200000)`, which will pass all checks provided the `totalBUSDInTiers[0]` is at least 200,000. This happens because both buys increment `buyInOneTier[msg.sender]` so that it is 200,000 before `refund()` is called. It decrements `totalBUSDInTiers[0]` by 200,000 when it should only decrement by 100,000. If enough users try to refund, this can cause users to be unable to refund as when `totalBUSDIntiers[tier-1]` is decremented in `refund()` it may revert due to an underflow error as the proper amount is not subtracted from each tier.

HighPotential unintended UnderflowFixed

In the `refund()` function, the amount deducted from `totalBUSDReceivedInAllTier` would not be equal to the amount added to `totalBUSDReceivedInAllTier` whenever the value of `tokensPerBUSD` is changed before refunding and after buying the tokens. In the case when the value of `tokensPerBUSD` is decreased, the amount subtracted from the `totalBUSDReceivedInAllTier` would be more than the amount added and could lead to an underflow error even if the `projectOwner` has enough tokens to send to the `msg.sender`.

Medium`totalUserInTiers[]` not updated correctlyFixed

The `totalUserInTiers[]` should be capturing the number of members in these following arrays. - `whitelistTierOne` - `whitelistTierTwo` - `whitelistTierThree` - `whitelistTierFour` - `whitelistTierFive` - `whitelistTierSix` - `whitelistTierSeven` - `whitelistTierEight` - `whitelistTierNine` But the `totalUserInTiers[]` array is not updated anytime a new user is added with `addWhitelist()` function. In the `constructor()`, value at every concerned index is initialized to `2` without adding any user to these arrays the aforementioned arrays.

Low`buyTokens()` and `refund()` gas optimizationFixed

Both `buyTokens()` and `refund()` call `getWhitelist()` for each tier to determine which tier a user is in.

LowFunction Should Be Declared ExternalFixed

The function 'refund()` is never called internally within the contract.

LowIncorrect calculation for `fundUser[]`Fixed

In the function `refund()`, both the fields of `fundUser[msg.sender]` are subtracted from `fundUser[msg.sender]` to update the `fundUser[msg.sender]`, which will always amount to both fields of `fundUser[msg.sender]` equal to zero.

LowMissing ChecksFixed

The following checks are not made: - In the `constructor()` of `INOLaunchpadSmartContract`, it is not checked that `_busdPrice` is nonzero. If it is mistakingly set to zero, then the `nftPrice` will also be zero. - In the `constructor()` of `SeedifyFundBUSD`, it is not checked that `_projectOwner` is not the zero address. - In the `constructor()` of `SeedifyFundBUSD`, it is not checked if the `_saleStartTime` is less than the '_saleEndTime'. - In `seedifyFundBUSD`, the `maxAllocPerUserInTiers[i]` should be always greater than or equal to `minAllocaPerUserInTiers[i]`. In the functions `updateTierValues()`, `updateTeirUsersValue()`, and the `constructor()`, it is not checked that the `maxAllocPerUserInTiers[i]` is greater than or equal to `minAllocaPerUserInTiers[i]` for all `tiers` `i`. - In the `constructor()` of `seedifyFundBUSD`, it is not checked that if all the values in the `_tiersValue[]` array are not zero. - In the function `addWhitelist()` of `seedifyFundBUSD`, it is not checked that the input `_address` is not already whitelisted for the input `_tier`. This can cause issues if an address is added multiple times because it will cause the `maxAllocaPerUserInTiers` to be calculated incorrectly.

LowPotential Division By ZeroFixed

The `updateTierValues()` does not check if the input `_tiersValue[]` has the value '0' for any valid index, or not. Because of which `totalUserInTiers[i]` could possibly be '0' in the following expression: ```solidity=137 for (uint256 i = 0; i < 9; i++) { tiersMaxCap[i] = _tiersValue[i]; maxAllocaPerUserInTiers[i] = tiersMaxCap[i] / totalUserInTiers[i]; } ```

LowRedundant codeFixed

The variable `totalparticipants` in `SeedifyFundBUSD.sol` and 'totalSupply' in `INOLaunchPadSmartContract.sol` are declared and initialized in the constructor, but never used. In the contract SeedifyFundBUSD.sol, the following variables are declared but never used: - `buyInTwoTier` - `buyInThreeTier` - `buyInFourTier` - `buyInFiveTier` - `buyInSixTier` - `buyInSevenTier` - `buyInEightTier` - `buyInNineTier`

LowUnchecked ERC-20 `transfer()`/`transferFrom()` CaFixed

The return value of the transfer()/transferFrom() call is not checked in any case of the `refund()` function.

Show 1 more
LowVariables That Could Be Declared as ImmutableFixed

The following variables assigned in the constructor can be declared as `immutable`. - `projectOwner` Immutable state variables can be assigned during contract creation but will remain constant throughout the lifetime of a deployed contract. A big advantage of immutable variables is that reading them is significantly cheaper than reading from regular state variables since they will not be stored in storage.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (2)

  • contracts/SeedifyFund/SeedifyFundBUSD.sol
  • contracts/INOLaunchpadSmartContract.sol

Part of Seedify’s security record

Seedify
Audits9 audits by 2 firmsLast audit Oct 2025, by Hacken.
Critical findingsNo open critical findingsAcross the 9 reports, 1 critical finding was reported. It is marked fixed by the firm that reported it.
Open Seedify’s security record

Security firm

CertiK

1,044 projects reviewed · 1,375 reports · latest May 2025

See CertiK’s audits

Something 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