As of 24 Oct 2026, Zero Staking has 1 audit report on Trustblock, by Quantstamp, dated 19 Jun 2024. That report lists no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| Zero Staking | Security firm: Quantstamp | Date: | Scope: Repository at commit 5f93318 | No open critical findings | Open · certificate.quantstamp.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 2 |
| Medium | 0 | 0 | 2 |
| Low | 0 | 4 | 2 |
A user who unstakes his full staked balance with the flag `exit = true` can lose all his potential rewards because of the following lines: ``` // In StakingERC20.sol if (staker.amountStaked - amount == 0) { delete stakers[msg.sender]; } ``` This effectively deletes the accounting of the rewards owed to the staker, causing the user to lose all his rewards even when `staker.owedRewards` is non-zero. A similar vulnerability exists in `StakingERC721.sol`.
Open the reportThe `StakingERC721.stake()` function allows a malicious staker to exploit the stale `staker.lastUpdatedTimestamp` due to a reentrancy vulnerability. During the staking process, the `_stake()` function calls `_safeMint()`, which calls `checkOnERC721Received()`. This allows the staker to re-enter the staking contract during the minting process. Since the `staker.lastUpdatedTimestamp` is only updated at the end of the `stake()` function, the staker can re-enter the `stake()` or `unstake()` function to trigger multiple `_checkRewards` calculations, thereby unfairly increasing their pending rewards based on the `staker.lastUpdatedTimestamp`. Similar reentrancy risks exist in the `StakingERC20.stake()` function if ERC777 tokens are accepted as staking tokens. The ERC777 token standard was created to extend the capabilities available in ERC20 tokens and one of the features allows the ERC777 token contract to notify the sender and recipient when ERC777 tokens are sent or received, which a malicious staker can use to re-enter the staking function.
Open the reportIf the staked token and reward token are identical, the staked tokens may be incorrectly used to pay out rewards to other users. This occurs because there is no separation between the funds that are staked by users and the tokens that are sent to the contract to distribute as rewards. This lack of separation can lead to a situation where users' staked tokens are depleted to fulfill reward claims. Furthermore, if the staked token and reward tokens are identical, the function `withdrawLeftoverRewards()` can be used to withdraw staked funds.
Open the reportIf a user calls `claim()` too frequently, he may lose out on rewards due to rounding calculation in `_getPendingRewards()`. In particular, when a user claims at times `A` and `B`, where the `B - A` is less than `periodLength`, then the rewards that should have been accumulated (i.e. `(rewardsPerPeriod * staker.amountStaked * ((B - A) / periodLength))` is lost simply due to rounding. Similarly, when a user claims and then stakes within a period's length, the partially accumulated rewards will be lost due to rounding.
Open the reportThe contracts are not designed to accommodate deflationary tokens when accepting token transfers. If a user transfers funds that incur a fee on transfer during order submission, the contract will store that the user has deposited more funds than they sent. This can cause issues during withdrawal or vault deposit.
Open the reportIt is important to validate inputs, even if they only come from trusted addresses, to avoid human error. Specifically, in the following functions arguments of type `address` may be initialized with value `0x0`: Following is the list of places that can potentially benefit from stricter input validation: 1. `StakingERC20`: 1. the pending `rewards` of the `_baseClaim()` should not be zero. 2. the `amount` of the `unstake()` should not be zero. 2. `StakingERC721`: 1. the `tokenIds` length should be greater than zero and the `tokenIds` and `tokenUris` length should match in `stake()` function. 2. the `tokenIds` length should be greater than zero in the `unstake()` function. 3. `Match`: 1. the `matchFee` should be greater than zero in the `startMatch()` function; otherwise the `lockedFunds` will be zero and it will not be possible to end the match. 2. the list of `players` addresses should not contain duplicates; otherwise, a player can be charged `matchFee` more than once. 3. when ending a match via the `endMatch()` function, the authorized caller can specify any amount in `gameFee`. A compromised authorized party can set this value to be as much as 100%, stealing the users’ payouts. Consider adding either a state variable with a fixed and known game fee or add an upper bound validation check. 4. `OwnableOperable`: 1. when adding a new operator, the operator boolean should be previously `false` in the function `addOperator()`. 2. when removing an existing operator, the operator boolean should be previously `true` in the function `removeOperator()`.
Open the reportThe reports name a repository or files. Open a report to see its scope.
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.
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.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="zero-staking"></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