{-# OPTIONS --safe #-}

open import Data.Integer using () renaming (+_ to pos)
import      Data.Integer as 
open import Data.Integer.Properties using (module ≤-Reasoning; +-mono-≤; neg-mono-≤; +-identityˡ)
                                    renaming (nonNegative⁻¹ to nonNegative⁻¹ℤ)
open import Data.Nat.GeneralisedArithmetic using (iterate)
open import Data.Rational using (; floor; _*_; _÷_; _/_; _⊓_; _≟_; ≢-nonZero)
open import Data.Rational.Literals using (number; fromℤ)
open import Data.Rational.Properties using (nonNegative⁻¹; pos⇒nonNeg; ⊓-glb)
open import stdlib.Data.Rational.Properties using (0≤⇒0≤floor; ÷-0≤⇒0≤; fromℕ-0≤; *-0≤⇒0≤; fromℤ-0≤)

open import Data.Integer.Tactic.RingSolver using (solve-∀)

open import Agda.Builtin.FromNat

open import Ledger.Prelude hiding (iterate; _/_; _*_; _⊓_; _≟_; ≢-nonZero)
open Filter using (filter)
open import Ledger.Conway.Specification.Abstract
open import Ledger.Conway.Specification.Transaction
open import Ledger.Prelude.Numeric.UnitInterval using (fromUnitInterval; UnitInterval-*-0≤)

open Number number renaming (fromNat to fromℕ)

module Ledger.Conway.Specification.Epoch
  (txs : _) (open TransactionStructure txs)
  (abs : AbstractFunctions txs) (open AbstractFunctions abs)
  where

open import Ledger.Conway.Specification.Certs govStructure
open import Ledger.Conway.Specification.Enact govStructure
open import Ledger.Conway.Specification.Gov txs
open import Ledger.Conway.Specification.Ledger txs abs
open import Ledger.Conway.Specification.PoolReap txs abs
open import Ledger.Conway.Specification.Ratify txs
open import Ledger.Conway.Specification.Rewards txs abs
open import Ledger.Conway.Specification.Utxo txs abs


record EpochState : Type where


  constructor ⟦_,_,_,_,_⟧ᵉ'


  field
    acnt       : Acnt
    ss         : Snapshots
    ls         : LState
    es         : EnactState
    fut        : RatifyState


record HasEpochState {a} (A : Type a) : Type a where
  field EpochStateOf : A  EpochState
open HasEpochState ⦃...⦄ public

instance
  HasSnapshots-EpochState : HasSnapshots EpochState
  HasSnapshots-EpochState .SnapshotsOf = EpochState.ss

  HasLState-EpochState : HasLState EpochState
  HasLState-EpochState .LStateOf = EpochState.ls

  HasEnactState-EpochState : HasEnactState EpochState
  HasEnactState-EpochState .EnactStateOf = EpochState.es

  HasDeposits-EpochState : HasDeposits EpochState
  HasDeposits-EpochState .DepositsOf = DepositsOf  LStateOf

  HasTreasury-EpochState : HasTreasury EpochState
  HasTreasury-EpochState .TreasuryOf = Acnt.treasury  EpochState.acnt

  HasReserves-EpochState : HasReserves EpochState
  HasReserves-EpochState .ReservesOf = Acnt.reserves  EpochState.acnt

  HasPParams-EpochState : HasPParams EpochState
  HasPParams-EpochState .PParamsOf = PParamsOf  EnactStateOf

  HasRatifyState-EpochState : HasRatifyState EpochState
  HasRatifyState-EpochState .RatifyStateOf = EpochState.fut

  HasPState-EpochState : HasPState EpochState
  HasPState-EpochState .PStateOf = PStateOf  CertStateOf  LStateOf


PoolDelegatedStake : Type
PoolDelegatedStake = KeyHash  Coin

record NewEpochState : Type where
  field
    lastEpoch   : Epoch
    bprev       : BlocksMade
    bcur        : BlocksMade
    epochState  : EpochState
    ru          : Maybe RewardUpdate
    pd          : PoolDelegatedStake


record HasNewEpochState {a} (A : Type a) : Type a where
  field NewEpochStateOf : A  NewEpochState
open HasNewEpochState ⦃...⦄ public
record HasLastEpoch     {a} (A : Type a) : Type a where field LastEpochOf     : A  Epoch
open HasLastEpoch     ⦃...⦄ public

instance
  HasLastEpoch-NewEpochState : HasLastEpoch NewEpochState
  HasLastEpoch-NewEpochState .LastEpochOf = NewEpochState.lastEpoch

  HasEpochState-NewEpochState : HasEpochState NewEpochState
  HasEpochState-NewEpochState .EpochStateOf = NewEpochState.epochState

  HasEnactState-NewEpochState : HasEnactState NewEpochState
  HasEnactState-NewEpochState .EnactStateOf = EnactStateOf  EpochStateOf

  Hastreasury-NewEpochState : HasTreasury NewEpochState
  Hastreasury-NewEpochState .TreasuryOf = TreasuryOf  EpochStateOf

  HasLState-NewEpochState : HasLState NewEpochState
  HasLState-NewEpochState .LStateOf = LStateOf  EpochStateOf

  HasGovState-NewEpochState : HasGovState NewEpochState
  HasGovState-NewEpochState .GovStateOf = GovStateOf  LStateOf

  HasCertState-NewEpochState : HasCertState NewEpochState
  HasCertState-NewEpochState .CertStateOf = CertStateOf  LStateOf

  HasDReps-NewEpochState : HasDReps NewEpochState
  HasDReps-NewEpochState .DRepsOf = DRepsOf  CertStateOf

  HasRewards-NewEpochState : HasRewards NewEpochState
  HasRewards-NewEpochState .RewardsOf = RewardsOf  CertStateOf

  HasPParams-NewEpochState : HasPParams NewEpochState
  HasPParams-NewEpochState .PParamsOf = PParamsOf  EpochStateOf

  unquoteDecl HasCast-EpochState HasCast-NewEpochState = derive-HasCast
    ( (quote EpochState     , HasCast-EpochState)
     [ (quote NewEpochState  , HasCast-NewEpochState)])

toRwdAddr : Credential  RwdAddr
toRwdAddr x = record { net = NetworkId ; stake = x }

getStakeCred : TxOut  Maybe Credential
getStakeCred (a , _ , _ , _) = stakeCred a

open GovActionState using (returnAddr)

opaque


  createRUpd :   BlocksMade  EpochState  Coin  RewardUpdate
  createRUpd slotsPerEpoch b es total =
    record  { Δt = Δt₁
            ; Δr = 0 - Δr₁ + Δr₂
            ; Δf = 0 - pos feeSS
            ; rs = rs


            ; flowConservation = flowConservation
            ; Δt-nonnegative = Δt-nonneg
            ; Δf-nonpositive = Δf-nonpos


            }
    where
      prevPp : PParams
      prevPp = PParamsOf es

      reserves : Reserves
      reserves = ReservesOf es

      pstakego : Snapshot
      pstakego = (SnapshotsOf es) .Snapshots.go

      feeSS : Fees
      feeSS = FeesOf (SnapshotsOf es)

      stake : Stake
      stake = StakeOf pstakego

      delegs : StakeDelegs
      delegs = StakeDelegsOf pstakego

      poolParams : Pools
      poolParams = PoolsOf pstakego

      blocksMade : 
      blocksMade = ∑[ m  b ] m

      ρ η τ : 
      ρ = fromUnitInterval (prevPp .PParams.monetaryExpansion)
      η = fromℕ blocksMade ÷₀ (fromℕ slotsPerEpoch * ActiveSlotCoeff)
      τ = fromUnitInterval (prevPp .PParams.treasuryCut)

      Δr₁ rewardPot Δt₁ R : 
      Δr₁ = floor (1  η * ρ * fromℕ reserves)
      rewardPot = pos feeSS + Δr₁
      Δt₁ = floor (fromℤ rewardPot * τ)
      R = rewardPot - Δt₁

      circulation : Coin
      circulation = total - reserves

      rs : Rewards
      rs = reward prevPp b (posPart R) poolParams stake delegs circulation

      Δr₂ : 
      Δr₂ = R - pos (∑[ c  rs ] c)


      -- Proofs
      -- Note: Overloading of + and - seems to interfere with
      -- the ring solver.
      lemmaFlow :  (t₁ r₁ f z : )
         (t₁ ℤ.+ (0 ℤ.- r₁ ℤ.+ ((f ℤ.+ r₁ ℤ.- t₁) ℤ.- z)) ℤ.+ (0 ℤ.- f) ℤ.+ z)  0
      lemmaFlow = solve-∀
      flowConservation :
        let t₁ = Δt₁
            r₁ = Δr₁
            f  = pos feeSS
            z  = pos (∑[ c  rs ] c)
         in
            (t₁ ℤ.+ (0 ℤ.- r₁ ℤ.+ ((f ℤ.+ r₁ ℤ.- t₁) ℤ.- z)) ℤ.+ (0 ℤ.- f) ℤ.+ z)  0
      flowConservation = lemmaFlow Δt₁ Δr₁ (pos feeSS) (pos (∑[ c  rs ] c))

      ÷₀-0≤⇒0≤ :  (x y : )  0  x  0  y  0  (x ÷₀ y)
      ÷₀-0≤⇒0≤ x y 0≤x 0≤y with y  0
      ... | (yes y≡0) = nonNegative⁻¹ 0
      ... | (no y≢0)  = ÷-0≤⇒0≤ x y {{≢-nonZero y≢0}} 0≤x 0≤y

      η-nonneg : 0  η
      η-nonneg = ÷₀-0≤⇒0≤ _ _ (fromℕ-0≤ blocksMade)
        (*-0≤⇒0≤ _ _
          (fromℕ-0≤ slotsPerEpoch)
          (nonNegative⁻¹ ActiveSlotCoeff {{pos⇒nonNeg ActiveSlotCoeff}}))

      min1η-nonneg : 0  1  η
      min1η-nonneg = ⊓-glb (nonNegative⁻¹ 1) η-nonneg

      Δr₁-nonneg : 0  Δr₁
      Δr₁-nonneg = 0≤⇒0≤floor _
        (*-0≤⇒0≤ (1  η * ρ) (fromℕ reserves)
          (UnitInterval-*-0≤ (1  η) (prevPp .PParams.monetaryExpansion) min1η-nonneg)
          (fromℕ-0≤ reserves))

      rewardPot-nonneg : 0  rewardPot
      rewardPot-nonneg = +-mono-≤ (nonNegative⁻¹ℤ (pos feeSS)) Δr₁-nonneg

      Δt-nonneg : 0  Δt₁
      Δt-nonneg = 0≤⇒0≤floor _
        (UnitInterval-*-0≤ (fromℤ rewardPot) (prevPp .PParams.treasuryCut)
          (fromℤ-0≤ rewardPot rewardPot-nonneg))

      Δf-nonpos : (0 - pos feeSS)  0
      Δf-nonpos = begin
          0 - pos feeSS ≡⟨ +-identityˡ _ 
          ℤ.- pos feeSS ≤⟨ neg-mono-≤ (ℤ.+≤+ z≤n) 
          0             
        where open ≤-Reasoning


applyRUpd : RewardUpdate  EpochState  EpochState
applyRUpd rewardUpdate $\begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#8552}{\htmlId{8552}{\htmlClass{Bound}{\text{treasury}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8563}{\htmlId{8563}{\htmlClass{Bound}{\text{reserves}}}}\, \end{pmatrix}
                       \\ \,\href{Ledger.Conway.Specification.Epoch.html#8600}{\htmlId{8600}{\htmlClass{Bound}{\text{ss}}}}\,
                       \\ \begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#8632}{\htmlId{8632}{\htmlClass{Bound}{\text{utxo}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8639}{\htmlId{8639}{\htmlClass{Bound}{\text{fees}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8646}{\htmlId{8646}{\htmlClass{Bound}{\text{deposits}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8657}{\htmlId{8657}{\htmlClass{Bound}{\text{donations}}}}\, \end{pmatrix}
                         \\ \,\href{Ledger.Conway.Specification.Epoch.html#8697}{\htmlId{8697}{\htmlClass{Bound}{\text{govSt}}}}\,
                         \\ \begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#8734}{\htmlId{8734}{\htmlClass{Bound}{\text{voteDelegs}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8747}{\htmlId{8747}{\htmlClass{Bound}{\text{stakeDelegs}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8761}{\htmlId{8761}{\htmlClass{Bound}{\text{rewards}}}}\, \end{pmatrix} \\ \,\href{Ledger.Conway.Specification.Epoch.html#8774}{\htmlId{8774}{\htmlClass{Bound}{\text{pState}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8783}{\htmlId{8783}{\htmlClass{Bound}{\text{gState}}}}\, \end{pmatrix} \end{pmatrix}
                       \\ \,\href{Ledger.Conway.Specification.Epoch.html#8822}{\htmlId{8822}{\htmlClass{Bound}{\text{es}}}}\,
                       \\ \,\href{Ledger.Conway.Specification.Epoch.html#8850}{\htmlId{8850}{\htmlClass{Bound}{\text{fut}}}}\,
                       \end{pmatrix}$ = $\begin{pmatrix} \begin{pmatrix} \,\href{Prelude.html#3279}{\htmlId{8887}{\htmlClass{Function}{\text{posPart}}}}\, \,\htmlId{8895}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Conway.Specification.Epoch.html#76}{\htmlId{8896}{\htmlClass{InductiveConstructor}{\text{pos}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#8552}{\htmlId{8900}{\htmlClass{Bound}{\text{treasury}}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{8909}{\htmlClass{Field Operator}{\text{+}}}}\, \,\href{Ledger.Conway.Specification.Rewards.html#6247}{\htmlId{8911}{\htmlClass{Function}{\text{Δt}}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{8914}{\htmlClass{Field Operator}{\text{+}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#76}{\htmlId{8916}{\htmlClass{InductiveConstructor}{\text{pos}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#9471}{\htmlId{8920}{\htmlClass{Function}{\text{unregRU'}}}}\,\,\htmlId{8928}{\htmlClass{Symbol}{\text{)}}}\,
                               \\ \,\href{Prelude.html#3279}{\htmlId{8963}{\htmlClass{Function}{\text{posPart}}}}\, \,\htmlId{8971}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Conway.Specification.Epoch.html#76}{\htmlId{8972}{\htmlClass{InductiveConstructor}{\text{pos}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#8563}{\htmlId{8976}{\htmlClass{Bound}{\text{reserves}}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{8985}{\htmlClass{Field Operator}{\text{+}}}}\, \,\href{Ledger.Conway.Specification.Rewards.html#6250}{\htmlId{8987}{\htmlClass{Function}{\text{Δr}}}}\,\,\htmlId{8989}{\htmlClass{Symbol}{\text{)}}}\, \end{pmatrix}
                             \\ \,\href{Ledger.Conway.Specification.Epoch.html#8600}{\htmlId{9024}{\htmlClass{Bound}{\text{ss}}}}\,
                             \\ \begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#8632}{\htmlId{9062}{\htmlClass{Bound}{\text{utxo}}}}\, \\ \,\href{Prelude.html#3279}{\htmlId{9069}{\htmlClass{Function}{\text{posPart}}}}\, \,\htmlId{9077}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Conway.Specification.Epoch.html#76}{\htmlId{9078}{\htmlClass{InductiveConstructor}{\text{pos}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#8639}{\htmlId{9082}{\htmlClass{Bound}{\text{fees}}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{9087}{\htmlClass{Field Operator}{\text{+}}}}\, \,\href{Ledger.Conway.Specification.Rewards.html#6253}{\htmlId{9089}{\htmlClass{Function}{\text{Δf}}}}\,\,\htmlId{9091}{\htmlClass{Symbol}{\text{)}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8646}{\htmlId{9095}{\htmlClass{Bound}{\text{deposits}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8657}{\htmlId{9106}{\htmlClass{Bound}{\text{donations}}}}\, \end{pmatrix}
                               \\ \,\href{Ledger.Conway.Specification.Epoch.html#8697}{\htmlId{9151}{\htmlClass{Bound}{\text{govSt}}}}\,
                               \\ \begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#8734}{\htmlId{9194}{\htmlClass{Bound}{\text{voteDelegs}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8747}{\htmlId{9207}{\htmlClass{Bound}{\text{stakeDelegs}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8761}{\htmlId{9221}{\htmlClass{Bound}{\text{rewards}}}}\, \,\href{Axiom.Set.Map.Dec.html#2046}{\htmlId{9229}{\htmlClass{Function Operator}{\text{∪⁺}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#9403}{\htmlId{9232}{\htmlClass{Function}{\text{regRU}}}}\, \end{pmatrix} \\ \,\href{Ledger.Conway.Specification.Epoch.html#8774}{\htmlId{9242}{\htmlClass{Bound}{\text{pState}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#8783}{\htmlId{9251}{\htmlClass{Bound}{\text{gState}}}}\, \end{pmatrix} \end{pmatrix}
                             \\ \,\href{Ledger.Conway.Specification.Epoch.html#8822}{\htmlId{9293}{\htmlClass{Bound}{\text{es}}}}\,
                             \\ \,\href{Ledger.Conway.Specification.Epoch.html#8850}{\htmlId{9327}{\htmlClass{Bound}{\text{fut}}}}\, \end{pmatrix}$
  where
    open RewardUpdate rewardUpdate using (Δt; Δr; Δf; rs)
    regRU     = rs  dom rewards
    unregRU   = rs  dom rewards 
    unregRU'  = ∑[ x  unregRU ] x


open RwdAddr using (stake)
opaque


  calculatePoolDelegatedStake
    : Snapshot
     PoolDelegatedStake
  calculatePoolDelegatedStake ss =
      -- Shelley spec: the output map must contain keys appearing in both
      -- sd and the pool parameters.
      sd  dom (PoolsOf ss)
    where
      -- stake credentials delegating to each pool
      stakeCredentialsPerPool : Rel KeyHash Credential
      stakeCredentialsPerPool = (StakeDelegsOf ss ˢ) ⁻¹ʳ

      -- delegated stake per pool
      sd : KeyHash  Coin
      sd = aggregate₊ ((stakeCredentialsPerPool ∘ʳ (StakeOf ss ˢ)) ᶠˢ)


  stakeFromGADeposits
    : GovState
     UTxOState
     Stake
  stakeFromGADeposits govSt utxoSt = aggregateBy
     (mapˢ  (gaid , addr)  (gaid , addr) , stake addr) govSt')
     (mapFromPartialFun  (gaid , _)  lookupᵐ? deposits (GovActionDeposit gaid)) govSt')
     where
       open UTxOState utxoSt

       govSt' :  (GovActionID × RwdAddr)
       govSt' = mapˢ (map₂ returnAddr) (fromList govSt)


  calculateVDelegDelegatedStake
    : Epoch
     UTxOState
     GovState
     GState
     DState
     VDeleg  Coin
  calculateVDelegDelegatedStake currentEpoch utxoSt govSt gState dState
    = aggregate₊ (((activeVoteDelegs ˢ) ⁻¹ʳ
                  ∘ʳ (stakePerCredential ∪⁺ stakeFromGADeposits govSt utxoSt) ˢ) ᶠˢ)
    where
      open UTxOState utxoSt
      open DState dState
      open GState gState

      -- active DReps
      activeDReps :  Credential
      activeDReps = dom (filterᵐ  (_ , e)  currentEpoch  e) dreps)

      -- active vote delegations
      activeVoteDelegs : VoteDelegs
      activeVoteDelegs = voteDelegs ∣^ ((mapˢ vDelegCredential activeDReps)
                                          vDelegNoConfidence    vDelegAbstain )

      -- stake per delegated credential
      stakePerCredential : Stake
      stakePerCredential = mapFromFun  c  cbalance (utxo ∣^' λ txout  getStakeCred txout  just c))
                                      (dom activeVoteDelegs)



  calculatePoolDelegatedStakeForVoting
    : Snapshot
     UTxOState
     GovState
     GState
     DState
     KeyHash  Coin
  calculatePoolDelegatedStakeForVoting ss utxoSt govSt gState dState
    = calculatePoolDelegatedStake ss ∪⁺ (stakeFromDeposits  dom (PoolsOf ss))
    where
      stakeFromDeposits : KeyHash  Coin
      stakeFromDeposits = aggregate₊ (((StakeDelegsOf ss ˢ) ⁻¹ʳ
                                      ∘ʳ (stakeFromGADeposits govSt utxoSt ˢ)) ᶠˢ)


  mkStakeDistrs
    : Snapshot
     Epoch
     UTxOState
     GovState
     GState
     DState
     StakeDistrs
  mkStakeDistrs ss currentEpoch utxoSt govSt gState dState =
    $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#10505}{\htmlId{12179}{\htmlClass{Function}{\text{calculateVDelegDelegatedStake}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12131}{\htmlId{12209}{\htmlClass{Bound}{\text{currentEpoch}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12144}{\htmlId{12222}{\htmlClass{Bound}{\text{utxoSt}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12151}{\htmlId{12229}{\htmlClass{Bound}{\text{govSt}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12157}{\htmlId{12235}{\htmlClass{Bound}{\text{gState}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12164}{\htmlId{12242}{\htmlClass{Bound}{\text{dState}}}}\,
    \\ \,\href{Ledger.Conway.Specification.Epoch.html#11516}{\htmlId{12255}{\htmlClass{Function}{\text{calculatePoolDelegatedStakeForVoting}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12128}{\htmlId{12292}{\htmlClass{Bound}{\text{ss}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12144}{\htmlId{12295}{\htmlClass{Bound}{\text{utxoSt}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12151}{\htmlId{12302}{\htmlClass{Bound}{\text{govSt}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12157}{\htmlId{12308}{\htmlClass{Bound}{\text{gState}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12164}{\htmlId{12315}{\htmlClass{Bound}{\text{dState}}}}\, \end{pmatrix}$


private variable
  e lastEpoch : Epoch
  fut fut' : RatifyState
  poolReapState : PoolReapState
  eps eps' eps'' : EpochState
  ls : LState
  es₀ : EnactState
  mark set go : Snapshot
  feeSS : Fees
  lstate : LState
  ss ss' : Snapshots
  ru : RewardUpdate
  mru : Maybe RewardUpdate
  pd : PoolDelegatedStake


getOrphans : EnactState  GovState  GovState
getOrphans es govSt = proj₁ $ iterate step ([] , govSt) (length govSt)
  where
    step : GovState × GovState  GovState × GovState
    step (orps , govSt) =
      let
        isOrphan? a prev = ¬? (hasParent? es govSt a prev)
        (orps' , govSt') = partition
           (_ , record {action = a ; prevAction = prev})  isOrphan? (a .gaType) prev)
          govSt
      in
        (orps ++ orps' , govSt')


record EPOCH-Updates0 : Type where
  constructor EPOCHUpdates0
  field
    es             : EnactState
    govSt'         : GovState
    payout         : Withdrawals
    gState'        : GState
    utxoSt'        : UTxOState
    totWithdrawals : Coin

EPOCH-updates0 : RatifyState  LState  EPOCH-Updates0
EPOCH-updates0 fut ls =
    EPOCHUpdates0 es govSt' payout gState' utxoSt' totWithdrawals
  where
    open LState ls public
    open CertState certState using (gState) public
    open RatifyState fut renaming (es to esW)

    es : EnactState
    es = record esW { withdrawals =  }

    tmpGovSt : GovState
    tmpGovSt = filter  x  proj₁ x  mapˢ proj₁ removed) govSt

    orphans :  (GovActionID × GovActionState)
    orphans  = fromList (getOrphans es tmpGovSt)

    removed' :  (GovActionID × GovActionState)
    removed' = removed  orphans

    govSt' : GovState
    govSt' = filter  x  proj₁ x  mapˢ proj₁ removed') govSt

    removedGovActions :  (RwdAddr × DepositPurpose × Coin)
    removedGovActions =
      flip concatMapˢ removed' λ (gaid , gaSt) 
        mapˢ
          (returnAddr gaSt ,_)
          ((DepositsOf utxoSt   GovActionDeposit gaid ) ˢ)

    govActionReturns : RwdAddr  Coin
    govActionReturns =
      aggregate₊ (mapˢ  (a , _ , d)  a , d) removedGovActions ᶠˢ)

    payout : RwdAddr  Coin
    payout = govActionReturns ∪⁺ WithdrawalsOf esW

    gState' : GState
    gState' =
      $\begin{pmatrix} \,\htmlId{14538}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Class.ToBool.html#342}{\htmlId{14539}{\htmlClass{Function Operator}{\text{if}}}}\, \,\href{Data.List.Base.html#4681}{\htmlId{14542}{\htmlClass{Function}{\text{null}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#13961}{\htmlId{14547}{\htmlClass{Function}{\text{govSt'}}}}\, \,\href{Class.ToBool.html#342}{\htmlId{14554}{\htmlClass{Function Operator}{\text{then}}}}\, \,\href{Axiom.Set.Map.html#6068}{\htmlId{14559}{\htmlClass{Function}{\text{mapValues}}}}\, \,\htmlId{14569}{\htmlClass{Symbol}{\text{(}}}\,\,\htmlId{14570}{\htmlClass{Number}{\text{1}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{14572}{\htmlClass{Field Operator}{\text{+\_}}}}\,\,\htmlId{14574}{\htmlClass{Symbol}{\text{)}}}\, \,\htmlId{14576}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Conway.Specification.Certs.html#1569}{\htmlId{14577}{\htmlClass{Field}{\text{DRepsOf}}}}\, \,\href{Ledger.Conway.Specification.Certs.html#4337}{\htmlId{14585}{\htmlClass{Function}{\text{gState}}}}\,\,\htmlId{14591}{\htmlClass{Symbol}{\text{)}}}\, \,\href{Class.ToBool.html#342}{\htmlId{14593}{\htmlClass{Function Operator}{\text{else}}}}\, \,\href{Ledger.Conway.Specification.Certs.html#1569}{\htmlId{14598}{\htmlClass{Field}{\text{DRepsOf}}}}\, \,\href{Ledger.Conway.Specification.Certs.html#4337}{\htmlId{14606}{\htmlClass{Function}{\text{gState}}}}\,\,\htmlId{14612}{\htmlClass{Symbol}{\text{)}}}\,
      \\ \,\href{Ledger.Conway.Specification.Certs.html#1484}{\htmlId{14622}{\htmlClass{Field}{\text{CCHotKeysOf}}}}\, \,\href{Ledger.Conway.Specification.Certs.html#4337}{\htmlId{14634}{\htmlClass{Function}{\text{gState}}}}\, \,\href{Axiom.Set.Map.html#10678}{\htmlId{14641}{\htmlClass{Function Operator}{\text{∣}}}}\, \,\href{Ledger.Conway.Specification.Enact.html#1366}{\htmlId{14643}{\htmlClass{Function}{\text{ccCreds}}}}\, \,\htmlId{14651}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Conway.Specification.Enact.html#484}{\htmlId{14652}{\htmlClass{Field}{\text{EnactState.cc}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#13631}{\htmlId{14666}{\htmlClass{Function}{\text{es}}}}\,\,\htmlId{14668}{\htmlClass{Symbol}{\text{)}}}\,
      \end{pmatrix}$

    utxoSt' : UTxOState
    utxoSt' = record utxoSt
      { deposits = DepositsOf utxoSt  mapˢ (proj₁  proj₂) removedGovActions 
      ; donations = 0
      }

    totWithdrawals : Coin
    totWithdrawals = ∑[ x  WithdrawalsOf esW ] x

record EPOCH-Updates : Type where
  constructor EPOCHUpdates
  field
    es             : EnactState
    govSt'         : GovState
    dState''       : DState
    gState'        : GState
    utxoSt'        : UTxOState
    acnt''         : Acnt

EPOCH-updates
  : RatifyState  LState  DState  Acnt  EPOCH-Updates
EPOCH-updates fut ls dState' acnt' =
    EPOCHUpdates (u0 .es) (u0 .govSt') dState'' (u0 .gState') (u0 .utxoSt') acnt''
  where
    open LState
    open EPOCH-Updates0

    u0 = EPOCH-updates0 fut ls

    refunds : Credential  Coin
    refunds = pullbackMap (u0 .payout) toRwdAddr (dom (RewardsOf dState'))

    dState'' : DState
    dState'' = record dState' { rewards = RewardsOf dState' ∪⁺ refunds }

    unclaimed : Coin
    unclaimed = getCoin (u0 .payout) - getCoin refunds

    acnt'' : Acnt
    acnt'' = record acnt'
      { treasury =
          TreasuryOf acnt'  u0 .totWithdrawals + DonationsOf ls + unclaimed
      }


data _⊢_⇀⦇_,EPOCH⦈_ :   EpochState  Epoch  EpochState  Type where


  EPOCH :


     {acnt : Acnt} {utxoSt'' : UTxOState} {acnt' dState' pState'} 


    let
      EPOCHUpdates es govSt' dState'' gState' utxoSt' acnt'' =
        EPOCH-updates fut ls dState' acnt'

      stakeDistrs : StakeDistrs
      stakeDistrs = mkStakeDistrs (Snapshots.mark ss') e utxoSt'
                                  govSt' (GStateOf ls) (DStateOf ls)

      Γ : RatifyEnv
      Γ = $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#16144}{\htmlId{16337}{\htmlClass{Bound}{\text{stakeDistrs}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12345}{\htmlId{16351}{\htmlClass{Generalizable}{\text{e}}}}\, \\ \,\href{Ledger.Conway.Specification.Certs.html#1569}{\htmlId{16355}{\htmlClass{Field}{\text{DRepsOf}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12454}{\htmlId{16363}{\htmlClass{Generalizable}{\text{ls}}}}\, \\ \,\href{Ledger.Conway.Specification.Certs.html#1484}{\htmlId{16368}{\htmlClass{Field}{\text{CCHotKeysOf}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12454}{\htmlId{16380}{\htmlClass{Generalizable}{\text{ls}}}}\, \\ \,\href{Ledger.Prelude.Base.html#889}{\htmlId{16385}{\htmlClass{Field}{\text{TreasuryOf}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#15959}{\htmlId{16396}{\htmlClass{Bound}{\text{acnt}}}}\, \\ \,\href{Ledger.Conway.Specification.Certs.html#1646}{\htmlId{16403}{\htmlClass{Field}{\text{PoolsOf}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12454}{\htmlId{16411}{\htmlClass{Generalizable}{\text{ls}}}}\, \\ \,\href{Ledger.Conway.Specification.Gov.Actions.html#1325}{\htmlId{16416}{\htmlClass{Field}{\text{VoteDelegsOf}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12454}{\htmlId{16429}{\htmlClass{Generalizable}{\text{ls}}}}\, \end{pmatrix}$

    in
        ls  ss ⇀⦇ tt ,SNAP⦈ ss'
       Γ   $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#16050}{\htmlId{16490}{\htmlClass{Bound}{\text{es}}}}\, \\ \,\href{Class.HasEmptySet.html#287}{\htmlId{16495}{\htmlClass{Field}{\text{∅}}}}\, \\ \,\href{Agda.Builtin.Bool.html#192}{\htmlId{16499}{\htmlClass{InductiveConstructor}{\text{false}}}}\, \end{pmatrix}$ ⇀⦇ govSt' ,RATIFIES⦈ fut'
       _   $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#16077}{\htmlId{16548}{\htmlClass{Bound}{\text{utxoSt'}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#15959}{\htmlId{16558}{\htmlClass{Bound}{\text{acnt}}}}\, \\ \,\href{Ledger.Conway.Specification.Certs.html#4537}{\htmlId{16565}{\htmlClass{Field}{\text{DStateOf}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12454}{\htmlId{16574}{\htmlClass{Generalizable}{\text{ls}}}}\, \\ \,\href{Ledger.Conway.Specification.Certs.html#4645}{\htmlId{16579}{\htmlClass{Field}{\text{PStateOf}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12454}{\htmlId{16588}{\htmlClass{Generalizable}{\text{ls}}}}\, \end{pmatrix}$ ⇀⦇ e ,POOLREAP⦈ $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#15973}{\htmlId{16611}{\htmlClass{Bound}{\text{utxoSt''}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#15996}{\htmlId{16622}{\htmlClass{Bound}{\text{acnt'}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#16002}{\htmlId{16630}{\htmlClass{Bound}{\text{dState'}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#16010}{\htmlId{16640}{\htmlClass{Bound}{\text{pState'}}}}\, \end{pmatrix}$
      ──────────────────────────────────────────────
      _  $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#15959}{\htmlId{16715}{\htmlClass{Bound}{\text{acnt}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12545}{\htmlId{16722}{\htmlClass{Generalizable}{\text{ss}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12454}{\htmlId{16727}{\htmlClass{Generalizable}{\text{ls}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12468}{\htmlId{16732}{\htmlClass{Generalizable}{\text{es₀}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12367}{\htmlId{16738}{\htmlClass{Generalizable}{\text{fut}}}}\, \end{pmatrix}$ ⇀⦇ e ,EPOCH⦈ $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#16085}{\htmlId{16759}{\htmlClass{Bound}{\text{acnt''}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12548}{\htmlId{16768}{\htmlClass{Generalizable}{\text{ss'}}}}\, \\ \begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#15973}{\htmlId{16776}{\htmlClass{Bound}{\text{utxoSt''}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#16053}{\htmlId{16787}{\htmlClass{Bound}{\text{govSt'}}}}\, \\ \begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#16060}{\htmlId{16798}{\htmlClass{Bound}{\text{dState''}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#16010}{\htmlId{16809}{\htmlClass{Bound}{\text{pState'}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#16069}{\htmlId{16819}{\htmlClass{Bound}{\text{gState'}}}}\, \end{pmatrix} \end{pmatrix} \\ \,\href{Ledger.Conway.Specification.Epoch.html#16050}{\htmlId{16835}{\htmlClass{Bound}{\text{es}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12371}{\htmlId{16840}{\htmlClass{Generalizable}{\text{fut'}}}}\, \end{pmatrix}$


data _⊢_⇀⦇_,NEWEPOCH⦈_ :   NewEpochState  Epoch  NewEpochState  Type where

  NEWEPOCH-New :  {bprev bcur : BlocksMade} 
    let
      eps' = applyRUpd ru eps
      ss   = EpochState.ss eps''
      pd'  = calculatePoolDelegatedStake (Snapshots.set ss)
    in
       e  lastEpoch + 1
       _  eps' ⇀⦇ e ,EPOCH⦈ eps''
      ──────────────────────────────────────────────
      _  $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#12347}{\htmlId{17242}{\htmlClass{Generalizable}{\text{lastEpoch}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#16950}{\htmlId{17254}{\htmlClass{Bound}{\text{bprev}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#16956}{\htmlId{17262}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12424}{\htmlId{17269}{\htmlClass{Generalizable}{\text{eps}}}}\, \\ \,\href{Agda.Builtin.Maybe.html#173}{\htmlId{17275}{\htmlClass{InductiveConstructor}{\text{just}}}}\, \,\href{Ledger.Conway.Specification.Epoch.html#12566}{\htmlId{17280}{\htmlClass{Generalizable}{\text{ru}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12613}{\htmlId{17285}{\htmlClass{Generalizable}{\text{pd}}}}\, \end{pmatrix}$ ⇀⦇ e ,NEWEPOCH⦈ $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#12345}{\htmlId{17308}{\htmlClass{Generalizable}{\text{e}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#16956}{\htmlId{17312}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Axiom.Set.Map.html#2671}{\htmlId{17319}{\htmlClass{Function}{\text{∅ᵐ}}}}\,  \\ \,\href{Ledger.Conway.Specification.Epoch.html#12433}{\htmlId{17325}{\htmlClass{Generalizable}{\text{eps''}}}}\, \\ \,\href{Agda.Builtin.Maybe.html#194}{\htmlId{17333}{\htmlClass{InductiveConstructor}{\text{nothing}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17054}{\htmlId{17343}{\htmlClass{Bound}{\text{pd'}}}}\, \end{pmatrix}$

  NEWEPOCH-Not-New :  {bprev bcur : BlocksMade} 
     e  lastEpoch + 1
      ──────────────────────────────────────────────
      _  $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#12347}{\htmlId{17490}{\htmlClass{Generalizable}{\text{lastEpoch}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17374}{\htmlId{17502}{\htmlClass{Bound}{\text{bprev}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17380}{\htmlId{17510}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12424}{\htmlId{17517}{\htmlClass{Generalizable}{\text{eps}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12586}{\htmlId{17523}{\htmlClass{Generalizable}{\text{mru}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12613}{\htmlId{17529}{\htmlClass{Generalizable}{\text{pd}}}}\, \end{pmatrix}$ ⇀⦇ e ,NEWEPOCH⦈ $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#12347}{\htmlId{17552}{\htmlClass{Generalizable}{\text{lastEpoch}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17374}{\htmlId{17564}{\htmlClass{Bound}{\text{bprev}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17380}{\htmlId{17572}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12424}{\htmlId{17579}{\htmlClass{Generalizable}{\text{eps}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12586}{\htmlId{17585}{\htmlClass{Generalizable}{\text{mru}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12613}{\htmlId{17591}{\htmlClass{Generalizable}{\text{pd}}}}\, \end{pmatrix}$

  NEWEPOCH-No-Reward-Update :  {bprev bcur : BlocksMade} 
    let
      ss  = EpochState.ss eps'
      pd' = calculatePoolDelegatedStake (Snapshots.set ss)
    in
       e  lastEpoch + 1
       _  eps ⇀⦇ e ,EPOCH⦈ eps'
      ──────────────────────────────────────────────
      _  $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#12347}{\htmlId{17887}{\htmlClass{Generalizable}{\text{lastEpoch}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17630}{\htmlId{17899}{\htmlClass{Bound}{\text{bprev}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17636}{\htmlId{17907}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12424}{\htmlId{17914}{\htmlClass{Generalizable}{\text{eps}}}}\, \\ \,\href{Agda.Builtin.Maybe.html#194}{\htmlId{17920}{\htmlClass{InductiveConstructor}{\text{nothing}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12613}{\htmlId{17930}{\htmlClass{Generalizable}{\text{pd}}}}\, \end{pmatrix}$ ⇀⦇ e ,NEWEPOCH⦈ $\begin{pmatrix} \,\href{Ledger.Conway.Specification.Epoch.html#12345}{\htmlId{17953}{\htmlClass{Generalizable}{\text{e}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17636}{\htmlId{17957}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Axiom.Set.Map.html#2671}{\htmlId{17964}{\htmlClass{Function}{\text{∅ᵐ}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#12428}{\htmlId{17969}{\htmlClass{Generalizable}{\text{eps'}}}}\, \\ \,\href{Agda.Builtin.Maybe.html#194}{\htmlId{17976}{\htmlClass{InductiveConstructor}{\text{nothing}}}}\, \\ \,\href{Ledger.Conway.Specification.Epoch.html#17702}{\htmlId{17986}{\htmlClass{Bound}{\text{pd'}}}}\, \end{pmatrix}$