Description
Parent issue: #1187 (LEDGER PoV)
Builds on: #1203 (the LEDGER-PoV contract), #1250 (explicit-deposit certificates / newCertDeposits)
This issue discharges the five Certs-side module parameters of the LEDGER-PoV contract (the parameter block of module LEDGER-PoV in src/Ledger/Dijkstra/Specification/Ledger/Properties/PoV.lagda.md, frozen by #1203) as theorems, with statements matching the contract verbatim.
Implementation: PR #1210 (stacked on #1203's branch; retarget to master once #1203 merges).
The five target statements
All vocabulary from Ledger.Dijkstra.Specification.Certs:
CERTS-rewards-pov — a CERTS run preserves the rewards balance:
Γ ⊢ s ⇀⦇ dCerts ,CERTS⦈ s' → coinFromRewards s ≡ coinFromRewards s'
CERTS-deposits-pov — closed-form deposit accounting, under PoolDepositsRegistered s:
coinFromDeposits s + newCertDeposits (PParamsOf Γ) (dom (PoolsOf s)) dCerts ≡ coinFromDeposits s' + refundCertDeposits (PParamsOf Γ) dCerts
CERTS-deposits-registered — a CERTS run preserves PoolDepositsRegistered.
CERTS-new-thread — newCertDeposits over an appended certificate list splits at a CERTS-run boundary, the second half charged against the run's final pool set (what lets per-step accounting compose across a batch).
refundCertDeposits-++ — refundCertDeposits distributes over _++_.
Decomposition
In Dijkstra, CERTS is a plain reflexive–transitive closure of the single-certificate rule CERT — the withdrawal and direct-deposit handling formerly attached to the Conway-era CERTS (the old PRE-CERT/POST-CERT phases) lives at the ENTITIES layer and is proved inside #1203 (Entities.Properties.{PoV,ApplyToRewardsPoV}). So each fact is an induction over the closure whose step case is a per-CERT lemma, plus fold algebra for the deposit folds:
- Per-step accounting — case split over the eight
DELEG/POOL/GOVCERT rules. _∪⁺_ additions add their deposit to the pot total (getCoin-∪⁺-singleton, new in Ledger.Prelude); removals split off the entry whose value the rule's membership premise pins down (getCoin-remove); POOL-reg adds through a left-biased union, so it needs the key fresh in the pot — the rule's premise gives freshness in pools, and PoolDepositsRegistered transports it to the pot. That is the invariant's only use, and it is preserved because POOL-reg extends pot and pool map by the same key.
- Pool-set threading —
newCertDeposits folds a pair accumulator (coin so far, pool keys registered so far); nextPools/CERT-poolSet identify the accumulator's evolution with dom (PoolsOf -) across a CERT step, up to ≡ᵉ, absorbed by a congruence lemma (the fold consumes the set only through membership tests). Since the fold's per-step function is local to Certs, the fold lemmas reach it through newCertDeposits itself via seed certificates (a fold state (d , P) is definitionally the fold from (0 , P) over one delegate/regdrep certificate carrying deposit d).
Modules
| Module |
Purpose |
Certs.Properties.PoVLemmas |
per-CERT-step lemmas (CERT-rewards-pov, CERT-deposits-pov, CERT-deposits-registered, CERT-poolSet) and fold lemmas (newCertDeposits-∷/-cong, shift lemmas, refundCertDeposits-++) |
Certs.Properties.PoV |
the five CERTS-level facts, statements matching the LEDGER-PoV parameters verbatim |
Ledger.Prelude (additions) |
getCoin-∪⁺-singleton, getCoin-remove, dom-∪ˡ-singleton and supporting ∪⁺ lemmas |
Acceptance criteria
References
History (2026-08-05): this body was rewritten. The previous version predated #1250 and #1203's contract restatement: it targeted a single CERTS-pov lemma with the withdrawal/direct-deposit flows attached to CERTS and an applyToRewards fold decomposition — that machinery now lives at the ENTITIES layer inside #1203, and the three agda-sets bridging assumptions it listed are the ApplyToRewards-PoV parameters there, no longer in this issue's scope.
Description
Parent issue: #1187 (LEDGER PoV)
Builds on: #1203 (the
LEDGER-PoVcontract), #1250 (explicit-deposit certificates /newCertDeposits)This issue discharges the five Certs-side module parameters of the
LEDGER-PoVcontract (the parameter block ofmodule LEDGER-PoVinsrc/Ledger/Dijkstra/Specification/Ledger/Properties/PoV.lagda.md, frozen by #1203) as theorems, with statements matching the contract verbatim.Implementation: PR #1210 (stacked on #1203's branch; retarget to
masteronce #1203 merges).The five target statements
All vocabulary from
Ledger.Dijkstra.Specification.Certs:CERTS-rewards-pov— aCERTSrun preserves the rewards balance:Γ ⊢ s ⇀⦇ dCerts ,CERTS⦈ s' → coinFromRewards s ≡ coinFromRewards s'CERTS-deposits-pov— closed-form deposit accounting, underPoolDepositsRegistered s:coinFromDeposits s + newCertDeposits (PParamsOf Γ) (dom (PoolsOf s)) dCerts ≡ coinFromDeposits s' + refundCertDeposits (PParamsOf Γ) dCertsCERTS-deposits-registered— aCERTSrun preservesPoolDepositsRegistered.CERTS-new-thread—newCertDepositsover an appended certificate list splits at aCERTS-run boundary, the second half charged against the run's final pool set (what lets per-step accounting compose across a batch).refundCertDeposits-++—refundCertDepositsdistributes over_++_.Decomposition
In Dijkstra,
CERTSis a plain reflexive–transitive closure of the single-certificate ruleCERT— the withdrawal and direct-deposit handling formerly attached to the Conway-eraCERTS(the oldPRE-CERT/POST-CERTphases) lives at theENTITIESlayer and is proved inside #1203 (Entities.Properties.{PoV,ApplyToRewardsPoV}). So each fact is an induction over the closure whose step case is a per-CERTlemma, plus fold algebra for the deposit folds:DELEG/POOL/GOVCERTrules._∪⁺_additions add their deposit to the pot total (getCoin-∪⁺-singleton, new inLedger.Prelude); removals split off the entry whose value the rule's membership premise pins down (getCoin-remove);POOL-regadds through a left-biased union, so it needs the key fresh in the pot — the rule's premise gives freshness inpools, andPoolDepositsRegisteredtransports it to the pot. That is the invariant's only use, and it is preserved becausePOOL-regextends pot and pool map by the same key.newCertDepositsfolds a pair accumulator (coin so far, pool keys registered so far);nextPools/CERT-poolSetidentify the accumulator's evolution withdom (PoolsOf -)across aCERTstep, up to≡ᵉ, absorbed by a congruence lemma (the fold consumes the set only through membership tests). Since the fold's per-step function is local toCerts, the fold lemmas reach it throughnewCertDepositsitself via seed certificates (a fold state(d , P)is definitionally the fold from(0 , P)over onedelegate/regdrepcertificate carrying depositd).Modules
Certs.Properties.PoVLemmasCERT-step lemmas (CERT-rewards-pov,CERT-deposits-pov,CERT-deposits-registered,CERT-poolSet) and fold lemmas (newCertDeposits-∷/-cong, shift lemmas,refundCertDeposits-++)Certs.Properties.PoVCERTS-level facts, statements matching theLEDGER-PoVparameters verbatimLedger.Prelude(additions)getCoin-∪⁺-singleton,getCoin-remove,dom-∪ˡ-singletonand supporting∪⁺lemmasAcceptance criteria
LEDGER-PoVCerts-side parameters are provable by direct substitution (statements verbatim); verified by a drop-in instantiation ofLEDGER-PoV.--safe, with no deferred module parameters on the Certs side.Certs.Properties(reachable from theLedger.Dijkstraroot).Ledger.Properties.PoVtoopenthese proofs in place of its parameters — the Certs analogue of [Dijkstra] Rewire LEDGER-pov to consume the proved PoV modules and drop the discharged parameters #1277.References
module LEDGER-PoVparameters insrc/Ledger/Dijkstra/Specification/Ledger/Properties/PoV.lagda.md([Dijkstra] CIP-159-11c: Prove LEDGER preservation of value (#1187) #1203).Entities.Properties.PoV(module ENTITIES-PoV, inside [Dijkstra] CIP-159-11c: Prove LEDGER preservation of value (#1187) #1203).PoolDepositsRegistered:src/Ledger/Dijkstra/Specification/Certs.lagda.md([Dijkstra] Explicit deposits in certificate deregistration #1250).History (2026-08-05): this body was rewritten. The previous version predated #1250 and #1203's contract restatement: it targeted a single
CERTS-povlemma with the withdrawal/direct-deposit flows attached toCERTSand anapplyToRewardsfold decomposition — that machinery now lives at theENTITIESlayer inside #1203, and the three agda-sets bridging assumptions it listed are theApplyToRewards-PoVparameters there, no longer in this issue's scope.