> For the complete documentation index, see [llms.txt](https://novacont.gitbook.io/nova-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://novacont.gitbook.io/nova-docs/audit-and-security/novacont-lite-security-review.md).

# NovaCont Lite Security Review

### Scope

* NovaCont\_Lite.tact

### Methodology

* Manual code review, conducted in two rounds: the first round examined the architecture and state-transition logic and findings were addressed by the developer; the second round verified the fixes at the source-code level.
* Static analysis: Misti

<table><thead><tr><th>Severity</th><th>Count</th><th width="250">Category</th></tr></thead><tbody><tr><td>Critical / High</td><td>0</td><td>None</td></tr><tr><td>Medium</td><td>9</td><td>SuboptimalSend — suggests using the more gas-efficient message() instead of send(), no functional risk</td></tr><tr><td>Low</td><td>29</td><td>PreferredStdlibApi (require -> throwUnless), PreferSenderFunction (context().sender -> sender()), EtaLikeSimplifications, UnusedMethodArgument. All gas optimization or style, no behavioral difference</td></tr></tbody></table>

Static analysis with Misti found no functional security vulnerabilities in the codebase. Everything flagged is at the level of gas optimization or API preference.

### Manual Review

Findings identified in the first review round, addressed by the developer, and verified at the source-code level:

#### CancelEscrow State-Mutation Ordering Bug \[Fixed]

In the initial version, the local "escrow\.state" variable was updated to "STATE\_CANCELLED" *before* the "escrow\.state == STATE\_CREATED" check was evaluated; this check therefore always evaluated to "false", since the variable had already been mutated. Only the "acceptTime == 0" condition was actually in effect, and this condition happened to be a safe proxy for the "STATE\_CREATED" state, so the bug carried no practical impact but the dead condition was a latent risk that could silently turn into a real bug in a future refactor. The original state is now captured beforehand in a "wasNotYetAccepted: Bool" variable, and this pre-captured value is used after the state mutation.

#### Silent Fund Loss Risk via SendIgnoreErrors \[Fixed]

All "send()" calls have been switched from "SendIgnoreErrors"  (which silently swallows a failed transfer) to "SendBounceIfActionFail". A failed transfer now bounces the transaction, keeping the state update consistent with the success of the transfer. Verified across every "send()" call in the codebase.

#### Centralization of Fund Distribution Logic \[Fixed]

In the initial version, the penalized-cancellation branch of "CancelEscrow" carried its own fund-splitting logic, independent of "distributeFunds". This duplication carried the risk that a fix applied to one path would not be reflected in the other (and indeed, the earlier bug remained confined to this one branch). "CancelEscrow" now routes through a single central function via "distributeFunds(escrowId, escrow, 5000 or 10000)". This eliminates the code duplication and guarantees that the STORAGE\_RESERVE calculation is consistent across every fund-distribution scenario.

#### Single Point of Failure in Dispute Resolution \[Fixed]

In the initial version, disputes were resolved through dependency on a single personal account. There is now a support pool managed via "AddSupport"/"RemoveSupport", with round-robin distribution through "nextSupportAssign". When a dispute is raised ("RaiseDispute"), it is assigned to a support member in sequence. The swap-with-last-element pattern in "RemoveSupport" correctly preserves index/count/nextAssign synchronization.

> Note: This is not a bug fix but an architectural resilience improvement. It reduces the centralization risk but does not eliminate it.

#### EscrowId Collision Risk \[Fixed]

In the initial version, the client could choose their own escrow ID, creating a collision risk if two different clients picked the same ID. "escrowId" is now assigned automatically and sequentially via "self.escrowCount".

<table><thead><tr><th>Finding</th><th>Status</th><th data-hidden></th></tr></thead><tbody><tr><td>Integer division rounding loss</td><td>Dust-level, no measurable impact</td><td></td></tr><tr><td>No maximum length check on description/evidenceUrl fields</td><td>Low priority, relevant for gas predictability</td><td></td></tr><tr><td>Event naming consistency (EscrowCreated vs. others)</td><td>Cosmetic, no functional risk</td><td></td></tr><tr><td>No minimum lower bound defined for agreedTon</td><td>The > STORAGE_RESERVE conditional checks in distributeFunds already implicitly prevent the risk of a negative/invalid transfer</td><td></td></tr></tbody></table>

### Conclusion

All six findings from the initial review (including one High and one Medium severity finding) have been verified as fixed in v1.1.0. Misti's static analysis found no functional security vulnerabilities in the codebase. Following this verification round, NovaCont Lite has reached a maturity level comparable to the main NovaCont contracts. An independent third-party audit is still recommended, but the rigor and speed of the internal review process are a positive signal.
