| Severity | Previous | This Report | Status |
|---|---|---|---|
| High | 2 | 0 | ✅ All fixed |
| Medium | 1 | 0 | ✅ All fixed |
| Low | 1 | 1 | ⚠️ Mitigated — batch function added |
| Informational | 60 | 40 | ✅ Missing-inheritance cleared; remainder accepted |
Contracts: DogPlanetCoreMining.sol, DOGEVerseRewarder.sol
Precision-loss issues were present in reward calculations (updatePool() and _calculateMetaRewards()) and the week-window rollover in claimBySig().
The previous pattern computed a product then divided by supply before applying the precision multiplier, causing intermediate truncation:
// OLD — precision loss from intermediate division: uint256 dpcReward = (rate * blocks * totalMinted) / divisor; accDpcPerShare += (dpcReward * ACC_PRECISION) / totalMinted;
Fixed by merging expressions so ACC_PRECISION is applied before any division. The totalMinted terms cancel:
// NEW — no intermediate truncation: accDpcPerShare += (rate * blocks * ACC_PRECISION) / divisor;
In DOGEVerseRewarder.claimBySig(), the week-window rollover was changed from a divide-then-multiply pattern to a single modulo expression:
weekStart = block.timestamp - (delta % WEEK_DURATION);
Contracts: DogPlanetMetaNFT.sol, DogPlanetSales.sol, DropMinterPass.sol
All three contracts had receive() and fallback() stubs that reverted but were still marked payable, meaning ETH sent would be accepted by the EVM before reverting — a potential locked-ether vector.
All stubs have been removed entirely. ETH is now rejected at the EVM level — no payable entry points exist anywhere in these contracts.
Contract: DropMinterPass.sol
The previous mint() function performed external calls (burnFrom(), mintWithHash()) before updating internal state variables (minted, mintedBy, totalDpsBurned).
Fixed by applying the Checks-Effects-Interactions pattern: all state variables are updated before any external call is made.
Contract: DogPlanetSales.sol
Added withdrawBatchNFTs(address to, uint256 limit) with a hard cap of 1–200 tokens per transaction.
Callers should use this for large inventories. The original withdrawAllNFTs is retained for backwards compatibility with a documented gas warning.
Both functions are pre-finalization, admin-role-gated only.
Contracts: Multiple
Created six shared interface files in contracts/interfaces/:
| Interface File | Implementing Contract |
|---|---|
IBurnableERC20.sol | DogPlanetCore, DogPlanetSpark |
IDogPlanetCore.sol | DogPlanetCore |
IDogPlanetSpark.sol | DogPlanetSpark |
IMiningContract.sol | DogPlanetCoreMining |
ICoreEvolve.sol | DOGEVerseCore721 |
IDOGEVerseCore721.sol | DOGEVerseCore721 |
Updated ICodexRegistry.sol to use uint32 for canonicalIndex (matching the implementation).
Added latestHash() to CodexRegistry to satisfy the full interface.
Removed all duplicate inline interface declarations from contract files.
Updated all implementing contracts with explicit is Interface inheritance declarations.
Contracts: DogPlanetCore, DogPlanetSpark, DogPlanetMetaNFT, DogPlanetSales, DropMinterPass, DogPlanetNFT
Removed leading underscores from all function parameters across the codebase
(_minter → newMinter, _enabled → enabled, _price → newPrice, _newBaseURI → newBaseURI, _miningContract → newMiningContract)
to comply with Solidity naming standards.
Contract: DogPlanetMetaNFT.sol
Added require(newMiningContract != address(0), "Zero address") to setMiningContract().
DOGEVerseRewarder.claimBySig — block.timestamp % WEEK_DURATION is flagged as weak PRNG.
This is a false positive: the expression calculates a deterministic time-window offset. No randomness is involved.
RemixVault.getTokenRemixInfo — strict equality check is an intentional identity verification
confirming a specific history record belongs to the queried token, not a comparison that can be gamed.
DOGEVerseCore721.evolveWithRarity and RemixVault — calls to codexRegistry.getEntry() intentionally
discard the versions array and canonicalIndex; only the rarity header is needed. Return values are syntactically captured with empty slots (h, , ).
DogPlanetSales, DogPlanetCoreMining, DogPlanetToken, and RemixVault require external calls per token.
These are owner-only or user-bounded batch operations required by the burn-to-mint architecture.
The per-call gas cost is unavoidable without moving off-chain or using Merkle proofs.
nonReentrant, or have no funds that could be drained.
FactionQuestBook, RemixVault, RewardVault, DOGEVerseRewarder use block.timestamp for deadline and window comparisons.
The ±15-second miner manipulation window does not create exploitable edge cases for these reward and deadline windows.
DogPlanetSales._removeToken uses a swap-and-pop pattern inside loops called by both withdrawal functions.
Mitigated by the 1–200 batch cap on withdrawBatchNFTs. withdrawAllNFTs retains a documented gas warning.
FactionQuestBook.DOMAIN_SEPARATOR() — all-caps naming is the EIP-712 standard convention adopted by Uniswap, OpenZeppelin, and the broader ecosystem.
Renaming would break integrations expecting the standard name.
| Date | Report | Findings | Notes |
|---|---|---|---|
| 2026-03-26 | SLITHER_AUDIT_20260326 | 64 | Initial post-development audit |
| 2026-03-27 | SLITHER_AUDIT_20260327 | 41 | All High/Medium fixed; interface architecture completed |
This report is published by Dog Planet AS for full public transparency.
Dog Planet AS remains committed to continuous security improvements.
A full independent third-party audit will be completed and published before any major protocol upgrades or significant liquidity events.
Last updated: March 27, 2026