Skip to main content
Sigvex

Typographical Error Remediation

Replace accidental assignments with the intended compound operators and add invariant tests that catch overwrite-instead-of-accumulate bugs.

Typographical Error Remediation

Overview

A typo that compiles is a logic bug. The detector flags three shapes: assignment where accumulation was intended (= / legacy =+ instead of +=), identity assignments (x = x), and consecutive operations that cancel out. The fix itself is a one-character change; the real remediation work is confirming which behavior was intended and adding a test that would have caught the difference.

Related Detector: Typographical Error

Before (Vulnerable)

mapping(address => uint256) public balances;

function deposit() external payable {
    // Overwrites the balance — a second deposit erases the first
    balances[msg.sender] = msg.value;
}

After (Fixed)

mapping(address => uint256) public balances;

function deposit() external payable {
    balances[msg.sender] += msg.value;
}

The distinction is observable on-chain: the vulnerable version discards the previous balance, so a user depositing twice loses the first amount into the contract’s unaccounted balance. A conservation invariant makes the bug untestable-around:

// Invariant test: sum of credited balances equals total ETH received
function invariant_conservation() public view {
    assertEq(sumOfBalances(), address(this).balance);
}

For identity assignments, find the name that was actually meant — owner = owner; in a transferOwnership(address newOwner) body should be owner = newOwner;. The dropped parameter is the tell.

Alternative Mitigations

  • Fuzz and invariant testing: property-based tests over deposit/withdraw sequences catch overwrite-vs-accumulate errors that single-call unit tests miss.
  • Source linting in CI: Solidity 0.5.0+ rejects the literal =+ token sequence, and standard linters flag self-assignments; keep both in the pipeline so the mistake never reaches review.
  • Peer review focused on state writes: review every = against the question “should any prior value survive this write?”

Common Mistakes

  • Fixing the operator without checking history. If the buggy version was live, users may have lost balances already; the fixed contract may need a migration or reimbursement path, not just correct future behavior.
  • Assuming the assignment was the typo. Sometimes the overwrite is correct and the variable name is wrong — a setter writing to the wrong slot looks identical in a diff. Confirm intent before choosing which side to change.
  • Silencing the finding with a redundant read (x = x + 0) instead of fixing the logic. The detector’s job is to point at the suspicious write; make the write meaningful or remove it.

References