Security invariants
Each invariant maps to at least one test. All listed invariants have automated
coverage; the live replay transaction is recorded in deployments/README.md.
Verification gate
- I1 No
EnergyCreditLedgerstate change unlessVERIFIER.verifyAndEmitreturnedtruefor the submitted proof. ✅test_execute_invalidProofDoesNotChangeLedger - I2 A source transaction whose receipt status is not
1settles nothing. ✅test_execute_revertedSourceTxDoesNotSettle - I3 A verified transaction with no
EnergyProducedlog settles nothing. ✅test_execute_withoutEnergyLogIsRejected - I4 A log with the right signature but emitted by an address other than the
configured
energyMetersettles nothing. ✅test_execute_wrongEmitterDoesNotSettle - I5
chainKey != sourceChainKeyreverts even if the proof verifies. ✅test_execute_wrongChainIsRejected - I6 Malformed log shape (topics length, data length) reverts. ✅
test_execute_malformedTopicsAreRejected,test_execute_malformedDataIsRejected - I7
wattHours == 0orwattHours > MAX_WATT_HOURSreverts. ✅test_execute_zeroWattHoursIsRejected,test_execute_wattHoursAboveMaximumIsRejected
Replay
- I8 The same proof submitted twice: second call reverts
QueryAlreadyProcessed, ledger unchanged. ✅test_execute_replayIsRejectedand live replay transaction - I9 Two distinct proofs carrying the same
readingId: second revertsReadingAlreadySettled. ✅EnergyCreditLedgerTest.test_credit_rejectsReplayOfReadingId - I10
EnergyMeterrejects a reusedreadingIdat emission. ✅EnergyMeterTest.test_recordProduction_revertsOnReusedReadingId
Access control
- I11
EnergyCreditLedger.creditreverts for any caller withoutCONSUMER_ROLE. ✅test_credit_onlyConsumer - I12 Only an account with
DEFAULT_ADMIN_ROLEcan grantCONSUMER_ROLE; a caller without that role cannot write to the ledger. ✅test_onlyAdminCanGrantConsumerRole - I13
credit(address(0), ...)reverts. ✅test_credit_rejectsZeroProducer
Value integrity
- I14
balanceOf[producer]increases by exactlywattHours;totalCreditedtracks the sum. ✅test_credit_happyPath,test_credit_accumulatesAcrossReadings - I15 Event signature constant in
EnergyProofConsumerequalskeccak256("EnergyProduced(address,address,bytes32,uint32)"). ✅EnergyMeterTest.test_eventSignatureMatchesConsumerConstant
Griefing (accepted, non-issues)
- Anyone may call
executewith someone else’s valid proof. Effect: the rightful producer is credited, the caller pays gas. No mitigation needed. EnergyMeter.recordProductionis restricted toORACLE_ROLE. A recorded reading still has to be attested and proven before it can settle.