EverGrow EGC security record

As of 3 Nov 2026, EverGrow EGC has 2 audit reports by 1 security firm on Trustblock; the latest is by CertiK, dated 4 Sep 2024. Those reports list no open critical findings. It also holds 3 deployed contracts on 1 chain.

Critical findings
No open critical findings
Across 2 reports.
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.

Audits2

Newest first

AuditSecurity firmDateScopeCritical findingsReport
LUCROSecurity firm: CertiKDate: Scope: 2 addresses on BNB ChainNo open critical findingsOpen · skynet.certik.com
EGC Staking - AuditSecurity firm: CertiKDate: Scope: 1 address on BNB ChainNo open critical findingsOpen · skynet.certik.com

Findings12

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

SeverityOpenAcknowledgedFixed
Critical000
High024
Medium000
Low024
HighInstant Reward Claim After Package AlterationLUCRO · CertiK · 4 Sep 2024Fixed

In the `alterPackage` function, when `totalStaked` is 0, the `tokensPerSecond` value is recalculated using `endTime - block.timestamp`. However, `packages[packageId].lastUpdate` is not updated during this process. Since `packages[packageId].lastUpdate` remains unchanged, a user can stake and immediately claim rewards in the same transaction, right after the `alterPackage` function is called. When the first user stakes into the contract, the `stake` function calculates the `totalExcluded` field for this user within the package as follows: ```solidity packages[i].totalExcluded[user] = getTotalExcluded(user, i); ``` Immediately after staking, if the user calls the `unstake` function, it triggers the `_cleanupPackages` function: ```solidity uint256 timeSince = timeSinceUpdated(i); ... uint256 tokensPerSecond = packages[i].tokensPerSecond; // determine the number of tokens owed to holders uint256 amountOwed = tokensPerSecond * timeSince; // fetch difference between total distributed and total to distribute uint256 max_extra_rewards = packages[i].totalToDistribute - packages[i].totalDistributed; // if the amount owed is greater than this value, clamp it if (amountOwed > max_extra_rewards) { amountOwed = max_extra_rewards; } // increase dividendsPerShare by this value unchecked { packages[i].totalDistributed += amountOwed; packages[i].dividendsPerShare += (amountOwed * PRECISION) / totalStaked; } // update timing on package packages[i].lastUpdate = block.timestamp; unchecked { ++i; } } ``` In this process, `tokensPerSecond` is recalculated in the `alterPackage` function as `(totalDistribute - totalDistributed) / (endTime - block.timestamp)`. Since `timeSince` equals `block.timestamp - lastUpdate`, which is non-zero, the `amountOwed` (calculated as `tokensPerSecond * timeSince`) also results in a non-zero value. Consequently, `dividendsPerShare` increases by this non-zero `amountOwed`. When calculating the pending rewards: ```solidity function pendingRewards( address user, uint256 packageId ) public view returns (uint256) { if (userInfo[user].amount == 0) { return 0; } uint256 userExcluded = packages[packageId].totalExcluded[user]; uint256 currentNonExcluded = getTotalExcluded(user, packageId); ... uint256 pending = currentNonExcluded <= userExcluded ? 0 : currentNonExcluded - userExcluded; return pending > remainingDistribution ? remainingDistribution : pending; } ``` Due to the increase in `dividendsPerShare`, `currentNonExcluded` is guaranteed to be greater than `userExcluded`, which was calculated during the `stake` function. As a result, if the admin alters the packages when `totalStaked` is 0, the first staker is able to stake and claim rewards from this contract within the same transaction.

Open the report
HighPausing Centralization RiskLUCRO · CertiK · 4 Sep 2024Fixed

In the contract `EverGrowStaking`, the role `owner` has the authority to update the status of the `setPause` function and further pause/resume the functionality of the `unstake` function. Any compromise to the private key of the `owner` may allow hackers to take advantage of this authority and prevent external user access to the function `unstake` to withdraw the staking tokens.

Open the report
HighInstant Reward Claim After Package AlterationEGC Staking - Audit · CertiK · 28 Aug 2024Fixed

In the `alterPackage` function, when `totalStaked` is 0, the `tokensPerSecond` value is recalculated using `endTime - block.timestamp`. However, `packages[packageId].lastUpdate` is not updated during this process. Since `packages[packageId].lastUpdate` remains unchanged, a user can stake and immediately claim rewards in the same transaction, right after the `alterPackage` function is called. When the first user stakes into the contract, the `stake` function calculates the `totalExcluded` field for this user within the package as follows: ```solidity packages[i].totalExcluded[user] = getTotalExcluded(user, i); ``` Immediately after staking, if the user calls the `unstake` function, it triggers the `_cleanupPackages` function: ```solidity uint256 timeSince = timeSinceUpdated(i); ... uint256 tokensPerSecond = packages[i].tokensPerSecond; // determine the number of tokens owed to holders uint256 amountOwed = tokensPerSecond * timeSince; // fetch difference between total distributed and total to distribute uint256 max_extra_rewards = packages[i].totalToDistribute - packages[i].totalDistributed; // if the amount owed is greater than this value, clamp it if (amountOwed > max_extra_rewards) { amountOwed = max_extra_rewards; } // increase dividendsPerShare by this value unchecked { packages[i].totalDistributed += amountOwed; packages[i].dividendsPerShare += (amountOwed * PRECISION) / totalStaked; } // update timing on package packages[i].lastUpdate = block.timestamp; unchecked { ++i; } } ``` In this process, `tokensPerSecond` is recalculated in the `alterPackage` function as `(totalDistribute - totalDistributed) / (endTime - block.timestamp)`. Since `timeSince` equals `block.timestamp - lastUpdate`, which is non-zero, the `amountOwed` (calculated as `tokensPerSecond * timeSince`) also results in a non-zero value. Consequently, `dividendsPerShare` increases by this non-zero `amountOwed`. When calculating the pending rewards: ```solidity function pendingRewards( address user, uint256 packageId ) public view returns (uint256) { if (userInfo[user].amount == 0) { return 0; } uint256 userExcluded = packages[packageId].totalExcluded[user]; uint256 currentNonExcluded = getTotalExcluded(user, packageId); ... uint256 pending = currentNonExcluded <= userExcluded ? 0 : currentNonExcluded - userExcluded; return pending > remainingDistribution ? remainingDistribution : pending; } ``` Due to the increase in `dividendsPerShare`, `currentNonExcluded` is guaranteed to be greater than `userExcluded`, which was calculated during the `stake` function. As a result, if the admin alters the packages when `totalStaked` is 0, the first staker is able to stake and claim rewards from this contract within the same transaction.

Open the report
HighPausing Centralization RiskEGC Staking - Audit · CertiK · 28 Aug 2024Fixed

In the contract `EverGrowStaking`, the role `owner` has the authority to update the status of the `setPause` function and further pause/resume the functionality of the `unstake` function. Any compromise to the private key of the `owner` may allow hackers to take advantage of this authority and prevent external user access to the function `unstake` to withdraw the staking tokens.

Open the report
LowMissing Update on `dividendsPerShare` of the ExpiLUCRO · CertiK · 4 Sep 2024Fixed

The `endPackage` function allows the `admin` role to terminate both active and expired packages. When determining the time elapsed since the last update, it invokes the `timeSinceUpdated(packageId)` function: ```solidity function timeSinceUpdated(uint256 packageId) public view returns (uint256) { if (packageId >= packageNonce || packageHasEnded(packageId)) { return 0; } ... } ``` If a package has expired, `packageHasEnded(packageId)` will return `true`, as `packages[packageId].endTime <= block.timestamp`: ```solidity function packageHasEnded(uint256 packageId) public view returns (bool) { return packages[packageId].endTime <= block.timestamp || packages[packageId].totalDistributed >= packages[packageId].totalToDistribute || packages[packageId].hasEnded; } ``` Given the logic above, `timeSinceUpdated(packageId)` will return `0` for an expired package. Consequently, in the following code snippet, `amountOwed` is calculated as `0`. This means that the `dividendsPerShare` for the expired package is not updated. As a result, any rewards that should have been accrued between `packages[packageId].lastUpdate` and `packages[packageId].endTime` will not be reflected in the `dividendsPerShare` field. Therefore, stakers who had staked when the package was active but unstaked after the package expired and was ended by the admin will receive no rewards from this package. ```solidity uint256 tSince = timeSinceUpdated(packageId); uint256 amountOwed = tSince * packages[packageId].tokensPerSecond; // fetch difference between total distributed and total to distribute uint256 max_extra_rewards = packages[packageId].totalToDistribute - packages[packageId].totalDistributed; // if the amount owed is greater than this value, clamp it if (amountOwed > max_extra_rewards) { amountOwed = max_extra_rewards; } // alter staking info for package, if and only if there are stakers if (totalStaked > 0) { // increase dividendsPerShare by this value unchecked { packages[packageId].totalDistributed += amountOwed; packages[packageId].dividendsPerShare += (amountOwed * PRECISION) / totalStaked; } ... ``` We would like to discuss this finding with the team to ensure that this design is intentional and correct.

Open the report
LowPotential Incorrect Reward Token Balance CheckLUCRO · CertiK · 4 Sep 2024Fixed

The `_claim` function uses `IERC20(packages[packageId].rewardToken).balanceOf(address(this))` to determine the total reward token balance held by the contract. It then compares this balance with the user's pending reward (`pending`) to ensure that the pending reward does not exceed the total reward balance transferred into the contract by the admin. ```solidity uint256 pending = pendingRewards(user, packageId); if (pending == 0) { return; } uint256 max_balance = IERC20(packages[packageId].rewardToken).balanceOf(address(this)); if (pending > max_balance) { pending = max_balance; } ``` However, if the `rewardToken` is the same as the staking token, then this balance represents both the reward tokens and the staking tokens. Using this balance to compare with the user's pending reward does not ensure that the pending reward is less than the actual reward token balance allocated by the package. As a result, some users may receive more reward tokens than expected from this contract, while other users might not be able to reclaim their staked tokens.

Open the report
LowMissing Update on `dividendsPerShare` of the ExpiEGC Staking - Audit · CertiK · 28 Aug 2024Fixed

The `endPackage` function allows the `admin` role to terminate both active and expired packages. When determining the time elapsed since the last update, it invokes the `timeSinceUpdated(packageId)` function: ```solidity function timeSinceUpdated(uint256 packageId) public view returns (uint256) { if (packageId >= packageNonce || packageHasEnded(packageId)) { return 0; } ... } ``` If a package has expired, `packageHasEnded(packageId)` will return `true`, as `packages[packageId].endTime <= block.timestamp`: ```solidity function packageHasEnded(uint256 packageId) public view returns (bool) { return packages[packageId].endTime <= block.timestamp || packages[packageId].totalDistributed >= packages[packageId].totalToDistribute || packages[packageId].hasEnded; } ``` Given the logic above, `timeSinceUpdated(packageId)` will return `0` for an expired package. Consequently, in the following code snippet, `amountOwed` is calculated as `0`. This means that the `dividendsPerShare` for the expired package is not updated. As a result, any rewards that should have been accrued between `packages[packageId].lastUpdate` and `packages[packageId].endTime` will not be reflected in the `dividendsPerShare` field. Therefore, stakers who had staked when the package was active but unstaked after the package expired and was ended by the admin will receive no rewards from this package. ```solidity uint256 tSince = timeSinceUpdated(packageId); uint256 amountOwed = tSince * packages[packageId].tokensPerSecond; // fetch difference between total distributed and total to distribute uint256 max_extra_rewards = packages[packageId].totalToDistribute - packages[packageId].totalDistributed; // if the amount owed is greater than this value, clamp it if (amountOwed > max_extra_rewards) { amountOwed = max_extra_rewards; } // alter staking info for package, if and only if there are stakers if (totalStaked > 0) { // increase dividendsPerShare by this value unchecked { packages[packageId].totalDistributed += amountOwed; packages[packageId].dividendsPerShare += (amountOwed * PRECISION) / totalStaked; } ... ``` We would like to discuss this finding with the team to ensure that this design is intentional and correct.

Open the report
LowPotential Incorrect Reward Token Balance CheckEGC Staking - Audit · CertiK · 28 Aug 2024Fixed

The `_claim` function uses `IERC20(packages[packageId].rewardToken).balanceOf(address(this))` to determine the total reward token balance held by the contract. It then compares this balance with the user's pending reward (`pending`) to ensure that the pending reward does not exceed the total reward balance transferred into the contract by the admin. ```solidity uint256 pending = pendingRewards(user, packageId); if (pending == 0) { return; } uint256 max_balance = IERC20(packages[packageId].rewardToken).balanceOf(address(this)); if (pending > max_balance) { pending = max_balance; } ``` However, if the `rewardToken` is the same as the staking token, then this balance represents both the reward tokens and the staking tokens. Using this balance to compare with the user's pending reward does not ensure that the pending reward is less than the actual reward token balance allocated by the package. As a result, some users may receive more reward tokens than expected from this contract, while other users might not be able to reclaim their staked tokens.

Open the report

Contracts3

AddressChainSource code
0xae57fc660ce2dc2e713099b832f3550b89afcaf5Chain: BNB ChainSource code: Verified source
0x7a14676e237de4455da09a5236e54cdf4aa6fe9cChain: BNB ChainSource code: Verified source
0x08fea38af56bfcce8123bb08e4e416f073b4a7efChain: BNB ChainSource code: Verified source

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="evergrow-1"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

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