SCADA Info
Supply Block is SCADA's core innovation — a function that, when triggered, removes a portion of the bonus liquidity SCADA farms from trading and splits the retrieved tokens: 90% of SCADA is permanently burned, reducing total supply forever. The remaining portion is distributed as rewards to stakers and the caller who executed the block. Meanwhile, the paired WPLS is used to market-buy SCADA, creating upward price pressure. This process strengthens the liquidity floor while continuously shrinking the circulating supply — a self-reinforcing cycle that rewards holders over time.
TrustNet Score
The TrustNet Score evaluates crypto projects based on audit results, security, KYC verification, and social media presence. This score offers a quick, transparent view of a project's credibility, helping users make informed decisions in the Web3 space.
Real-Time Threat Detection
Real-time threat detection, powered by Cyvers.io,
is currently not
activated
for this project.
This advanced feature provides continuous monitoring and instant alerts to safeguard your assets from potential security threats. Real-time detection enhances your project's security by proactively identifying and mitigating risks.
For more information, click here.
Security Assessments
Summary and Final Words
No crucial issues found
The contract does not contain issues of high or medium criticality. This means that no known vulnerabilities were found in the source code.
Contract owner cannot mint
It is not possible to mint new tokens.
Contract owner cannot blacklist addresses.
It is not possible to lock user funds by blacklisting addresses.
Contract owner cannot set high fees
The fees, if applicable, can be a maximum of 25% or lower. The contract can therefore not be locked. Please take a look in the comment section for more details.
Contract cannot be locked
Owner cannot lock any user funds.
Token cannot be burned
There is no burning within the contract without any allowances
Ownership is renounced
The contract does not include owner functions that allow post-deployment modifications.
Contract is not upgradeable
The contract does not use proxy patterns or other mechanisms to allow future upgrades. Its behavior is locked in its current state.
Scope of Work
This audit encompasses the evaluation of the files listed below, each verified with a SHA-1 Hash. The team referenced above has provided the necessary files for assessment.
The auditing process consists of the following systematic steps:
- Specification Review: Analyze the provided specifications, source code, and instructions to fully understand the smart contract's size, scope, and functionality.
- Manual Code Examination: Conduct a thorough line-by-line review of the source code to identify potential vulnerabilities and areas for improvement.
- Specification Alignment: Ensure that the code accurately implements the provided specifications and intended functionalities.
- Test Coverage Assessment: Evaluate the extent and effectiveness of test cases in covering the codebase, identifying any gaps in testing.
- Symbolic Execution: Analyze the smart contract to determine how various inputs affect execution paths, identifying potential edge cases and vulnerabilities.
- Best Practices Evaluation: Assess the smart contracts against established industry and academic best practices to enhance efficiency, maintainability, and security.
- Actionable Recommendations: Provide detailed, specific, and actionable steps to secure and optimize the smart contracts.
A file with a different Hash has been intentionally or otherwise modified after the security review. A different Hash may indicate a changed condition or potential vulnerability that was not within the scope of this review.
Final Words
The following provides a concise summary of the audit report, accompanied by insightful comments from the auditor. This overview captures the key findings and observations, offering valuable context and clarity.
Smart Contract Analysis Statement
Contract Analysis
The SCADAToken contract implements an ERC20 token with a bounded buy/sell tax, an automated liquidity injection mechanism on Uniswap V2, and cross-chain mint/burn coupling with the SCADABridge. The contract is deployed and immutable; the team has acknowledged each finding below and provided on-chain or operational mitigations where applicable. Residual concerns are summarized as follows:
- The auto-LP swap and addLiquidityETH calls ship with zero slippage parameters. The auto-LP path is gated to the protocol's own SCADA/WETH main pair, so MEV exposure on a triggering trade is bounded by the round-trip tax cost (1.00 percent buy + 1.20 percent sell = 2.20 percent of swap notional) and capped per cycle by MAX_SWAP_TOKENS = 10,000 SCADA. Residual sandwich risk remains real on shallow-liquidity periods where a single auto-LP swap can produce price impact above the tax band; the operational mitigation is to monitor pool depth and ensure liquidity stays sufficient. The on-chain slippage hardening is recommended for any future redeployment.
- The LP-token transfer to the manager does not check the ERC-20 boolean return. The pair token is fetched live from the canonical Uniswap V2 factory, so it is always the canonical UniswapV2ERC20 implementation, which reverts on insufficient and unconditionally returns true. The originally High-rated extraLP corruption scenario is therefore unreachable on the deployed pair; this finding has been downgraded to Low.
- The auto-LP step fires inside the user's transfer to the main pair and the partial-failure path leaves orphan ETH inside the contract. Recovery is available through rescueETH (creator role, bounded, cannot rescue SCADA or the LP token), and the SCADA accounting drift on a failed addLiquidityETH catch arm is self-cleaning over multiple subsequent tax cycles because the auto-LP trigger sweeps the entire contract balance. The combined residual exposure is bounded loss-of-availability of orphan ETH until rescue, with no permanent loss of user funds; severity has been downgraded to Medium accordingly.
Initial Supply Custody
The 1,000,000 SCADA initial supply was minted in the SCADAToken constructor to the SCADAManager contract address (initialRecipient set to the deploying SCADAManager), not to an EOA wallet or team multisig. SCADAManager subsequently contributed the entire mint - together with deployer-funded WETH - as initial Uniswap V2 SCADA/WETH liquidity via the one-shot SCADAManager.initializeLiquidity() function. The resulting initial LP baseline is structurally retained by SCADAManager and cannot be withdrawn to the deployer or any admin. The post-bootstrap extra LP that the auto-tax mechanism subsequently accumulates is removed only in bounded portions by the permissionless supplyBlock cycle, with the unwound SCADA and WETH routed entirely through burn / staker reward / bounded caller incentive - never to the deployer; see the SCADAManager audit statement for the full LP-lock enumeration. SCADAToken itself has no recall, freeze, or clawback capability over its own supply held elsewhere, and the constructor mint is the only mint outside the SCADABridge user-driven unwrap path.
Ownership Privileges
The ownership of the contract has been delegated to the SCADAManager (which has itself renounced its Ownable owner via 0xe6308d...), while a separate immutable creator role retains permanent but bounded parameter-tuning powers. The owner retains full privileges including:
- Adjust the buy tax inside [0.10%, 2.00%]
- Adjust the sell tax inside [0.10%, 2.00%]
- Adjust the auto-swap threshold inside [10, 10,000] SCADA
- Mark addresses as AMM pairs or as fee-exempt, set the bridge once via a one-shot setter, and rescue accidentally received ETH or non-protocol ERC-20 tokens
- Cannot mint SCADA outside the bridge's user-driven unwrap path
- Cannot move user funds or freeze transfers
- Cannot raise the tax above the 2% hardcoded cap on either side
- Cannot un-set or change the bridge once configured
Security Features
The contract implements several positive security features:
- Hardcoded MIN/MAX tax constants enforced at the contract level - the creator cannot push fees outside a 0.10-2.00% band, and these bounds were verified by symbolic analysis.
- Immutable creator address and a one-shot bridge setter that locks the bridge address permanently after the first call.
- ReentrancyGuard on every user-facing entry point plus an internal inSwap flag that prevents the auto-LP path from re-entering itself.
- Explicit fee-exempt list covering the protocol's own contracts and the Uniswap V2 router, so internal protocol movements never accidentally pay tax.
Note - This Audit report consists of a security analysis of the SCADAToken smart contract. This analysis did not include economic analysis of the contract's tokenomics. Moreover, we only audited the main contract for the SCADAToken team. Other contracts associated with the project were audited separately by our team. We recommend investors do their own research before investing.
Files and details
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Findings and Audit result
medium Issues | 3 findings
Acknowledged
#1 medium Issue
Auto-LP fires inside the user's transfer to the main pair, exposing every triggering trade to MEV
The _update hook calls _swapAndAddLiq before completing the user's transfer to mainPair. The auto-LP path swaps half of the accumulated tax for ETH and adds liquidity into the same pair the user is selling into. Because both operations execute inside the user's transaction, a frontrunner can amplify the slippage cost extracted from the contract and the protocol always pays the bad side of its own price impact. Even with non-zero slippage parameters, this transaction-ordering amplification persists.
Acknowledged
#2 medium Issue
Bookkeeping inconsistency in _swapAndAddLiq leaves orphan ETH and corrupted collectedForLP, and the surrounding try/catch silently swallows router failures
If the swap to ETH succeeds but addLiquidityETH reverts (and the catch arm fires), the function sets collectedForLP = otherHalf - that is, only half of the original input is restored to bookkeeping. The other half has already been converted to ETH and is now sitting in the contract with no tracking. The orphan ETH is recoverable only through rescueETH by the creator. Combined with the silent try/catch in _swapTokensForETH, the result is that a failing router interaction can leak tax tokens into the contract balance without a clean recovery path and without distinct event signals that operators can react to. Visible in event logs as inconsistent collectedForLP deltas and a maintainability hazard for any future refactor.
Acknowledged
#3 medium Issue
No slippage protection in auto-LP swap and addLiquidityETH calls
_swapTokensForETH uses swapExactTokensForETHSupportingFeeOnTransferTokens with amountOutMin set to 0, and _swapAndAddLiq calls addLiquidityETH with both amountTokenMin and amountETHMin set to 0. The Uniswap documentation explicitly recommends amountOutMin > 0 for the fee-on-transfer variant, since the variant intentionally forgoes the K-invariant slippage check. Together these calls are fully sandwichable on every triggering sell, slowly leaking value to MEV searchers and contradicting the project's '100% efficient tax' claim.
low Issues | 6 findings
Acknowledged
#1 low Issue
Permissive bridgeBurn parameter accepts arbitrary 'from' address
The bridgeBurn function calls _burn(from, amount) without checking allowance, so the bridge can technically destroy any user's SCADA balance. Today this is safe because the only path that reaches bridgeBurn is wrap(), which always passes msg.sender as 'from'. However, the function design is more permissive than necessary and any future bridge variant could burn arbitrary balances without user consent.
Acknowledged
#2 low Issue
State changes in setAMMPair and setFeeExempt without distinct events
setFeeExempt mutates the isFeeExempt mapping silently with no event. setAMMPair emits AMMPairSet, but that same event is also used by setMainPair, making it impossible for off-chain indexers to distinguish the two paths. This complicates monitoring, dashboards, and after-the-fact incident response.
Pending
#3 low Issue
nonReentrant modifier is not the first modifier
Several functions order modifiers as 'onlyCreator nonReentrant'. None of the current access-control modifiers make external calls, so this is not directly exploitable, but the recommended best practice is to put nonReentrant first as defense-in-depth.
Acknowledged
#4 low Issue
Solidity 0.8.20 has known issues - prefer a newer patch version
Solidity 0.8.20 contains three documented compiler issues: VerbatimInvalidDeduplication, FullInlinerNonExpressionSplitArgumentEvaluationOrder, and MissingSideEffectsOnSelectorAccess. None of them apply to this codebase (no inline assembly, no verbatim, no selector arithmetic), but using the most recent patched compiler is preferred.
Pending
#5 low Issue
Empty or weak require strings, plus 'uint' alias instead of 'uint256'
Several require statements have no error string or only weak ones, and event signatures plus function parameters use the 'uint' alias instead of explicit 'uint256'. Pure style and gas issues, but on a 761 nSLOC contract these revert strings and inconsistent declarations add up to non-trivial bytecode and reduce readability.
Acknowledged
#6 low Issue
Unchecked ERC-20 transfer return value when sending LP tokens to the manager
After auto-LP, the contract calls IERC20(pairAddress).transfer(scadaManager, liquidity) without checking the boolean return value. The Uniswap V2 pair token is externally controlled. If transfer ever returns false without reverting (uncommon but allowed by the ERC-20 standard), the LP tokens stay in this contract while notifyNewLP is still invoked, so the manager would credit extraLP for liquidity it does not hold. The next supplyBlock then computes lpToRemove against an inflated extraLP and reverts on the actualLPBalance check, permanently disabling supplyBlock with no admin recovery path.
optimization Issues | 4 findings
Pending
#1 optimization Issue
scadaManager could be declared immutable
scadaManager is set in the constructor and never modified afterwards, but it is declared as a regular storage variable. Marking it immutable removes a storage slot and saves gas on every transfer that touches the AMM pair logic.
Pending
#2 optimization Issue
pairAddress is re-derived from the factory inside hot paths
Inside _swapAndAddLiq and getMainPairInfo the pair address is fetched from the factory at runtime via getPair(...). The factory does not change and the pair address is already cached in mainPair after setMainPair runs. The redundant external call is wasted gas in the hot auto-LP path.
Pending
#3 optimization Issue
swapTokensAtAmount initialized twice
swapTokensAtAmount is declared with an inline value of 10_000 * 1e18 and then immediately reassigned to the same value inside the constructor. The inline declaration writes a slot that is overwritten almost immediately, wasting an SSTORE at deployment.
Pending
#4 optimization Issue
Modifiers swapping and onlyManager are each invoked exactly once
The 'swapping' modifier is used only by _swapAndAddLiq, and the 'onlyManager' modifier is used only by managerBurn. Single-use modifiers add unnecessary indirection and a small gas overhead.
informational Issues | 6 findings
Pending
#1 informational Issue
Contract does not formally inherit from its declared interface
An ISCADAToken interface is declared in src/interfaces/ISCADAToken.sol, but SCADAToken does not inherit from it. As a result the compiler does not verify that the public surface stays in sync with the interface. A separate but related issue is that SCADAMiner.sol redeclares its own local ISCADAToken interface, creating a name collision and a real maintenance hazard.
Pending
#2 informational Issue
Empty require string in setMainPair
setMainPair has an explicit defense-in-depth check require(msg.sender == scadaManager) on top of the onlyOwner modifier, but the require has no revert string. The intent of the dual check (covering the case where ownership is ever transferred away from the manager) is not visible to a future maintainer.
Pending
#3 informational Issue
Function and parameter naming follows leading-underscore style instead of mixedCase
Several function parameters use leading underscores ('_bridge', '_creator', etc.) which deviates from the Solidity style guide's mixedCase convention. Pure style finding.
Pending
#4 informational Issue
Strict equality on ethReceived == 0 is intentional but flagged by detectors
_swapAndAddLiq uses 'if (ethReceived == 0)' as a recovery trigger when the router returns no ETH. The strict equality is correct here - any non-zero amount means a partial swap succeeded - but Slither and Decurity flag the pattern as a 'dangerous strict equality'. Documenting the intent prevents future false positives.
Acknowledged
#5 informational Issue
Centralization disclosure - the creator role retains permanent recovery and parameter powers (not renounced)
Unlike the SCADAManager and SCADAMiner contracts (which have renounced ownership to address(0)), the SCADAToken's creator role is persistent by design. The creator is set in the constructor as immutable and there is no path to remove or change it. The creator's powers are intentionally bounded by hardcoded constants but they still represent a centralization vector that should be disclosed explicitly to investors and users.
Acknowledged
#6 informational Issue
Centralization disclosure - rescueETH and rescueTokens allow the creator to extract any non-protocol asset from the contract
rescueETH and rescueTokens let the creator extract any ETH or any non-SCADA, non-LP ERC-20 from the contract to an arbitrary recipient. The bounds are sensible (cannot rescue SCADA, cannot rescue the LP token) but the functions are unrestricted otherwise. Combined with the unaccountedETH situation noted in M-02, the creator can effectively reclaim any orphan funds that the auto-LP path leaks.