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.

SCADA Logo

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.

23.86
Poor Excellent

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

Select the audit
"Static Analysis Dynamic Analysis Symbolic Execution SWC Check Manual Review"
Contract address
N/A
Network N/A
License N/A
Compiler N/A
Type N/A
Language Solidity
Onboard date 2026/05/04
Revision date 2026/05/04

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:

  1. Specification Review: Analyze the provided specifications, source code, and instructions to fully understand the smart contract's size, scope, and functionality.
  2. Manual Code Examination: Conduct a thorough line-by-line review of the source code to identify potential vulnerabilities and areas for improvement.
  3. Specification Alignment: Ensure that the code accurately implements the provided specifications and intended functionalities.
  4. Test Coverage Assessment: Evaluate the extent and effectiveness of test cases in covering the codebase, identifying any gaps in testing.
  5. Symbolic Execution: Analyze the smart contract to determine how various inputs affect execution paths, identifying potential edge cases and vulnerabilities.
  6. Best Practices Evaluation: Assess the smart contracts against established industry and academic best practices to enhance efficiency, maintainability, and security.
  7. 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 SCADAManager contract implements the deflationary engine for SCADA, including the supplyBlock buyback-and-burn cycle, accumulation of LP tokens minted by the auto-tax mechanism, distribution of staker rewards via the SCADAMiner, and a small caller incentive that makes supplyBlock self-sustaining. The contract is deployed and immutable, and Ownable owner has been renounced on-chain (manager.owner() returns address(0), verified via transaction 0xe6308d...). The team has acknowledged each finding below and provided on-chain or operational mitigations. Residual concerns are summarized as follows:

  • supplyBlock spends the entire WETH balance for the buyback rather than only the WETH freed by removeLiquidity. The donation-grief vector is uneconomic in steady state: a donor consumes their own WETH into a buyback that benefits all SCADA holders (90 percent burn, capped sharePoolPercent to the miner reward pool, capped callerRewardPercent at 1 percent to the caller). A donor cannot extract more than the caller-reward fraction even if they call supplyBlock themselves. Severity downgraded to Low.
  • The router calls inside supplyBlock (removeLiquidity and the SCADA buyback) use zero slippage parameters. MEV exposure on the permissionless supplyBlock path is bounded by the round-trip tax cost (2.20 percent of swap notional against the protocol's own pair) and economically nudged toward private-mempool submission by the 1 percent caller reward, which a sandwiched caller would forfeit. The Flashbots / private-mempool submission is a caller-side recommendation rather than a contract-level guarantee. Severity retained at High to reflect residual risk on the public mempool, especially for shallow-liquidity periods or large extraLP withdrawals.
  • The contract has a payable receive() but no path to move ETH out. With ownership renounced, no extraction function can ever be added. Any ETH that lands here is permanently locked. Severity retained at Medium; operational mitigation is to monitor the manager address for any inbound ETH and treat it as an unrecoverable user error. The receive() removal is recommended for any future redeployment.
  • The staker-reward and caller-reward transfers do not check the boolean return value. The token transferred is SCADA itself, an OpenZeppelin-based ERC-20 stored as immutable inside the manager that reverts on failure and unconditionally returns true. The downstream miner concern is therefore not reachable on the deployed system; severity downgraded to Low.

Initial Liquidity Lock

The deployment sequence routes the entire 1,000,000 SCADA initial supply (minted to SCADAManager in the SCADAToken constructor) together with the WETH the deployer pre-funded via depositWETH() into a single Uniswap V2 SCADA/WETH LP through the one-shot initializeLiquidity() function. The LP tokens are minted to the SCADAManager contract itself, and the initialLP balance is snapshotted at the end of the call. After this:

  • initializeLiquidity() can never run a second time - the liquidityInitialized flag is set permanently to true, and Ownable.owner() has subsequently been renounced to address(0) via transaction 0xe6308d..., making every onlyOwner function permanently uncallable.
  • SCADAManager exposes no function - admin, creator, or permissionless - that transfers the LP token out of the contract, withdraws the underlying SCADA and WETH backing it, or grants a configurable spender any allowance on the pair token. The only allowance ever set on the LP token is a one-shot bounded approval inside supplyBlock that is consumed immediately by the subsequent removeLiquidity call.
  • supplyBlock can only act on a bounded fraction of LP that the auto-tax mechanism contributes after bootstrap (capped at 90 percent of the extraLP counter, which by construction excludes initialLP). The unwound SCADA and WETH are distributed entirely in SCADA via burn, staker reward, and the bounded caller incentive (at most 1 percent of the bought-back SCADA, paid in SCADA, not in LP or WETH). No actor - including the deployer - can withdraw LP tokens or the underlying WETH through this path.
  • There is no withdrawLP, rescueLP, transferLP, emergencyWithdraw, migrate, or setLPRecipient function in the contract. There is no delegatecall, no upgrade proxy, and no selfdestruct.

The initial LP baseline (the initialLP snapshot taken at the end of initializeLiquidity()) is therefore structurally retained by the SCADAManager contract for the life of the deployment. The post-bootstrap extra LP that the auto-tax mechanism subsequently accumulates is removed only in bounded portions by the permissionless supplyBlock cycle described above, and in every case the unwound SCADA and WETH are routed entirely through burn + staker reward + bounded caller incentive - never to the deployer or any admin. No role - admin, creator, or permissionless caller - can withdraw LP tokens or their underlying SCADA and WETH to themselves. A full enumeration of every LP-touching surface in SCADAManager.sol is available in section 1.3 of the audit report.

Ownership Privileges

The ownership of the contract has been renounced (manager.owner() returns address(0), verified on-chain via transaction 0xe6308d...). A separate immutable creator role retains permanent but bounded parameter-tuning powers, while a one-shot bridge setter locks the bridge address permanently after the first call. The owner retains full privileges including:

  • Adjust the supplyBlock LP threshold inside [0.0001%, 10%]
  • Adjust the staker share inside [1%, 50%] and the caller incentive inside [0.1%, 1%]
  • One-shot setter for the SCADABridge address (cannot be changed once set)
  • Cannot replace the SCADAMiner, set or change parameters that affect user balances, or recover the contract's ETH
  • Cannot mint or move SCADA outside the supplyBlock cycle
  • Cannot pause or freeze the deflationary cycle - supplyBlock is permissionless
  • Cannot withdraw the initial LP baseline or any unwound LP value to themselves or any other admin - initializeLiquidity() is one-shot and mints LP to the contract itself, and the only LP-affecting operation in the contract (the permissionless supplyBlock cycle) removes a bounded portion of post-bootstrap LP and routes the unwound value exclusively through burn / staker reward / bounded caller incentive (see Initial Liquidity Lock above)
  • Cannot replace the SCADAToken reference (it is set at construction and is immutable)

Security Features

The contract implements several positive security features:

  • The SCADAToken and creator references are stored as immutable, so they cannot be changed for the lifetime of the contract.
  • ReentrancyGuard on every state-mutating external function, plus a separate try/catch around the bridge collateral burn so a failing bridge cannot break the deflationary cycle.
  • supplyBlock is permissionless and gated by the readyForSupplyBlock predicate, so the deflationary cycle does not depend on any privileged account.
  • The Ownable owner has been renounced on-chain, freezing the configuration of the deployed instance.
  • The initial LP baseline (initialLP) is structurally retained by the SCADAManager contract - initializeLiquidity() is a one-shot function that mints LP to the contract itself and cannot be called a second time. The only LP-affecting operation in the contract is the permissionless supplyBlock cycle, which removes a bounded portion of post-bootstrap auto-LP and routes the unwound SCADA and WETH entirely through burn / staker reward / bounded caller incentive. No code path transfers LP tokens or unwound LP value to the deployer or any other admin.

Note - This Audit report consists of a security analysis of the SCADAManager smart contract. This analysis did not include economic analysis of the contract's tokenomics. Moreover, we only audited the main contract for the SCADAManager 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 | 2 findings

Acknowledged

#1 medium Issue
Contract accepts ETH but provides no withdrawal path - permanently locked ether
SCADAManager.sol
L286-287
Description

The contract has a payable receive() function but no path to move ETH out. supplyBlock works on WETH, removeLiquidity returns WETH (not ETH), and _buySCADA uses token-to-token swaps. There is no rescueETH function, no admin path, no permissionless drain. Owner is address(0) (renounced), so the path cannot be added later. Any ETH that lands on this contract - via selfdestruct, accidental transfer, or anything else - is permanently unrecoverable.

Acknowledged

#2 medium Issue
No slippage protection in initializeLiquidity, supplyBlock removeLiquidity, and _buySCADA
SCADAManager.sol
L132-141
L187-195
L259-265
Description

Three router calls ship with all minimum-out parameters set to zero. supplyBlock is permissionless and economically incentivized via callerRewardPercent, so MEV searchers can call it themselves and sandwich the embedded removeLiquidity and _buySCADA in a single bundle, capturing the arbitrage that should have gone to burning and stakers. _buySCADA uses the fee-on-transfer router variant, which the Uniswap docs explicitly recommend protecting with a non-zero amountOutMin since that variant skips the K-invariant slippage check.

low Issues | 9 findings

Pending

#1 low Issue
Strict greater-than comparison on actualLPBalance can revert valid supplyBlock calls
SCADAManager.sol
L180
Description

supplyBlock requires actualLPBalance to be strictly greater than lpToRemove. When the LP balance equals exactly lpToRemove (which can happen after a previous failed supplyBlock or specific accounting paths), the function reverts even though the call is mathematically valid.

Acknowledged

#2 low Issue
setRewardPercentages emits no event
SCADAManager.sol
L337-344
Description

setRewardPercentages mutates two protocol-critical splits (sharePoolPercent and callerRewardPercent) but emits no event. Off-chain reward dashboards or analytics cannot detect the change without polling state.

Acknowledged

#3 low Issue
nonReentrant modifier is not the first modifier
SCADAManager.sol
L120
L327
Description

initializeLiquidity and depositWETH list onlyOwner before nonReentrant. The current onlyOwner modifier does not make external calls, so this is not exploitable today, but the recommended best practice is to put nonReentrant first.

Pending

#4 low Issue
Empty require string in setLpBlockThreshold
SCADAManager.sol
L302
Description

setLpBlockThreshold uses a require with a comment but no revert string: 'require(threshold >= 1 && threshold <= 100_000); // 0.0001% - 10%'. This makes failure modes harder to debug from transaction traces.

Acknowledged

#5 low Issue
Solidity 0.8.20 has known issues - prefer a newer patch version
SCADAManager.sol
L1
Description

Solidity 0.8.20 contains three documented compiler issues (VerbatimInvalidDeduplication, FullInlinerNonExpressionSplitArgumentEvaluationOrder, MissingSideEffectsOnSelectorAccess). None apply to this codebase, but using the most recent patched compiler is preferred.

Acknowledged

#6 low Issue
burnCollateral wrapped in try/catch can silently desync the cross-chain peg invariant under persistent failure
SCADAManager.sol
L227-234
Description

supplyBlock wraps the burnCollateral call in a try/catch with a CollateralBurnSkipped event. This is a deliberate liveness choice - it prevents a failing bridge from blocking the deflationary cycle - but it means the documented peg invariant 'wscada in bridge equals SCADA totalSupply minus the 1M seed' becomes a soft target rather than a hard one. If burnCollateral fails repeatedly (paused wSCADA, future bridge upgrade, blacklisted recipient, etc.), the bridge accumulates excess wSCADA collateral that no longer corresponds to circulating SCADA on Ethereum. There is no on-chain reconciliation path.

Acknowledged

#7 low Issue
setMiner is not one-shot - mitigated for deployed instance by ownership renouncement
SCADAManager.sol
L309-313
Description

Unlike setScadaBridge, which has a one-shot guard, setMiner can be called repeatedly by the owner. Pre-renouncement, the owner could wait for extraLP to accumulate, replace scadaMiner with a malicious contract, then call permissionless supplyBlock to siphon the share-pool reward. Owner-only mutability of a contract reference that supplyBlock blindly calls is a centralization vector during the deployment window.

Acknowledged

#8 low Issue
Unchecked ERC-20 transfer return values for staker rewards and caller incentive (downgraded from H-01)
SCADAManager.sol
L215
L220
Description

supplyBlock calls scadaToken.transfer(scadaMiner, sharePoolReward) and scadaToken.transfer(msg.sender, callerReward) without checking the boolean return value. SCADA itself returns true, so the calls are currently safe. However, combined with the miner crediting accRewardPerShare based on the input amount (and not on actual balance change), any silent transfer failure or future change to the SCADA token would cause the miner to over-promise rewards, eventually leading to claim reverts and locked-out stakers.

Acknowledged

#9 low Issue
supplyBlock consumes the entire WETH balance for buyback, not just the WETH freed by removeLiquidity (downgraded from M-02)
SCADAManager.sol
L199-202
Description

After removeLiquidity returns (amountSCADA, amountWETH), the function spends the entire WETH balance of the contract for the buyback rather than only amountWETH. This conflates WETH freed by removeLiquidity, leftover WETH from depositWETH that initializeLiquidity did not consume, and any WETH donated or accidentally sent. An external party can grief the protocol by donating WETH right before someone calls supplyBlock, forcing a larger-than-intended buyback at potentially unfavorable prices, and the caller-reward calculation will then include a fraction of the donation.

optimization Issues | 1 findings

Pending

#1 optimization Issue
Multiple ERC-20 approve calls ignore the boolean return value
SCADAManager.sol
L101
L102
L108
L109
L184
Description

The constructor, resetApprovals, and supplyBlock all call IERC20.approve(...) without checking the return value. The current targets (SCADA, WETH, Uniswap pair) are well-behaved and return true, but using SafeERC20.forceApprove is the modern, standard pattern.

informational Issues | 4 findings

Pending

#1 informational Issue
Contract does not formally inherit from a matching interface
SCADAManager.sol
L32
Description

SCADAToken declares a local ISCADAManager interface in its own file with just notifyNewLP, but SCADAManager itself does not inherit from any interface. The compiler cannot verify that the manager's public surface matches what consumers expect.

Pending

#2 informational Issue
Strict equality on initialLP == 0 is intentional but flagged by detectors
SCADAManager.sol
L271
Description

readyForSupplyBlock uses 'if (initialLP == 0) return false;' to gate the predicate before liquidity is initialized. The strict equality is correct, but Slither flags it as a dangerous strict equality. Documenting the intent inline prevents future false positives during reviews.

Pending

#3 informational Issue
Function parameters use leading-underscore naming instead of mixedCase
SCADAManager.sol
L302
L310
Description

Several function parameters use leading underscores, deviating from the Solidity style guide's mixedCase convention. Pure style.

Pending

#4 informational Issue
Magic numbers in distribution math should be named constants
SCADAManager.sol
L176
L210
L211
L277
Description

supplyBlock and readyForSupplyBlock use literal numbers (9000, 10000, 1_000_000) for percentage and threshold math. Named constants improve readability and make accidental future changes less likely.