{-# OPTIONS --safe #-}

open import Ledger.Prelude renaming (filterˢ to filter)
open import Ledger.Types.GovStructure

module Ledger.Certs (gs : _) (open GovStructure gs) where

open import Tactic.Derive.DecEq

open import Ledger.GovernanceActions gs
open RwdAddr
open PParams


data DepositPurpose : Type where
  CredentialDeposit  : Credential    DepositPurpose
  PoolDeposit        : KeyHash       DepositPurpose
  DRepDeposit        : Credential    DepositPurpose
  GovActionDeposit   : GovActionID   DepositPurpose

Deposits = DepositPurpose  Coin


instance
  unquoteDecl DecEq-DepositPurpose = derive-DecEq
    ((quote DepositPurpose , DecEq-DepositPurpose)  [])


record PoolParams : Type where
  field
    rewardAddr : Credential


data DCert : Type where
  delegate    : Credential  Maybe VDeleg  Maybe KeyHash  Coin  DCert
  dereg       : Credential  Maybe Coin  DCert
  regpool     : KeyHash  PoolParams  DCert
  retirepool  : KeyHash  Epoch  DCert
  regdrep     : Credential  Coin  Anchor  DCert
  deregdrep   : Credential  Coin  DCert
  ccreghot    : Credential  Maybe Credential  DCert


  -- The `reg` cert is deprecated in Conway, but it's still present in this era
  -- for backwards compatibility. This has been added to the spec to make
  -- conformance testing work properly. We don't talk about this certificate
  -- in the pdf because it has been deprecated and we want to discourage people
  -- from using it.
  reg         : Credential  Coin  DCert


cwitness : DCert  Maybe Credential
cwitness (delegate c _ _ _)  = just c
cwitness (dereg c _)         = just c
cwitness (regpool kh _)      = just $ KeyHashObj kh
cwitness (retirepool kh _)   = just $ KeyHashObj kh
cwitness (regdrep c _ _)     = just c
cwitness (deregdrep c _)     = just c
cwitness (ccreghot c _)      = just c


-- The implementation requires the `reg` cert to be witnessed only if the
-- deposit is set. There didn't use to be a field for the deposit, but that was
-- added in the Conway era to make it easier to determine, just by looking at
-- the transaction, how much deposit was paid for that certificate.
cwitness (reg _ zero)        = nothing
cwitness (reg c (suc _))     = just c


record CertEnv : Type where
  field
    epoch     : Epoch
    pp        : PParams
    votes     : List GovVote
    wdrls     : RwdAddr  Coin
    coldCreds :  Credential

record DState : Type where


  constructor ⟦_,_,_⟧ᵈ


  field
    voteDelegs   : Credential  VDeleg
    stakeDelegs  : Credential  KeyHash
    rewards      : Credential  Coin



record PState : Type where
  field
    pools     : KeyHash  PoolParams
    retiring  : KeyHash  Epoch



record GState : Type where


  constructor ⟦_,_⟧ᵛ


  field
    dreps      : Credential  Epoch
    ccHotKeys  : Credential  Maybe Credential

record CertState : Type where


  constructor ⟦_,_,_⟧ᶜˢ


  field
    dState : DState
    pState : PState
    gState : GState

record DelegEnv : Type where
  field
    pparams       : PParams
    pools         : KeyHash  PoolParams
    delegatees    :  Credential

GovCertEnv  = CertEnv
PoolEnv     = PParams


rewardsBalance : DState  Coin
rewardsBalance ds = ∑[ x  DState.rewards ds ] x

instance
  HasCoin-CertState : HasCoin CertState
  HasCoin-CertState .getCoin = rewardsBalance  CertState.dState


instance
  unquoteDecl To-CertEnv To-DState To-PState To-GState To-CertState To-DelegEnv = derive-To
    (   (quote CertEnv , To-CertEnv)
       (quote DState , To-DState)
       (quote PState , To-PState)
       (quote GState , To-GState)
       (quote CertState , To-CertState)
     [ (quote DelegEnv , To-DelegEnv) ])

private variable
  rwds rewards           : Credential  Coin
  dReps                  : Credential  Epoch
  sDelegs stakeDelegs    : Credential  KeyHash
  ccKeys ccHotKeys       : Credential  Maybe Credential
  vDelegs voteDelegs     : Credential  VDeleg
  pools                  : KeyHash  PoolParams
  retiring               : KeyHash  Epoch
  wdrls                  : RwdAddr  Coin

  an          : Anchor
  Γ           : CertEnv
  d           : Coin
  md          : Maybe Coin
  c           : Credential
  mc          : Maybe Credential
  delegatees  :  Credential
  dCert       : DCert
  e           : Epoch
  vs          : List GovVote
  kh          : KeyHash
  mkh         : Maybe KeyHash
  poolParams  : PoolParams
  pp          : PParams
  mv          : Maybe VDeleg

  stᵈ stᵈ' : DState
  stᵍ stᵍ' : GState
  stᵖ stᵖ' : PState
  cc :  Credential


data


  _⊢_⇀⦇_,DELEG⦈_     : DelegEnv     DState      DCert        DState      Type


data


  _⊢_⇀⦇_,POOL⦈_      : PoolEnv      PState      DCert        PState      Type


data


  _⊢_⇀⦇_,GOVCERT⦈_   : GovCertEnv   GState      DCert        GState      Type


data


  _⊢_⇀⦇_,CERT⦈_      : CertEnv      CertState   DCert        CertState   Type


data


  _⊢_⇀⦇_,CERTBASE⦈_  : CertEnv      CertState               CertState   Type


module _ where  -- achieves uniform (but perhaps misleading) alignment of type signatures in fig


  _⊢_⇀⦇_,CERTS⦈_     : CertEnv      CertState   List DCert   CertState   Type


  _⊢_⇀⦇_,CERTS⦈_ = ReflexiveTransitiveClosureᵇ' {_⊢_⇀⟦_⟧ᵇ_ = _⊢_⇀⦇_,CERTBASE⦈_} {_⊢_⇀⦇_,CERT⦈_}


data _⊢_⇀⦇_,DELEG⦈_ where


  DELEG-delegate :
    let Γ =  pp , pools , delegatees 
    in
     (c  dom rwds  d  pp .keyDeposit)
     (c  dom rwds  d  0)
     mv  mapˢ (just  credVoter DRep) delegatees 
        fromList ( nothing  just abstainRep  just noConfidenceRep  [] )
     mkh  mapˢ just (dom pools)   nothing 
      ────────────────────────────────
      Γ    vDelegs , sDelegs , rwds  ⇀⦇ delegate c mv mkh d ,DELEG⦈
            insertIfJust c mv vDelegs , insertIfJust c mkh sDelegs , rwds ∪ˡ  c , 0  

  DELEG-dereg :
     (c , 0)  rwds
      ────────────────────────────────
       pp , pools , delegatees    vDelegs , sDelegs , rwds  ⇀⦇ dereg c md ,DELEG⦈
         vDelegs   c   , sDelegs   c   , rwds   c   

  DELEG-reg :
     c  dom rwds
     d  pp .keyDeposit  d  0
      ────────────────────────────────
       pp , pools , delegatees  
         vDelegs , sDelegs , rwds  ⇀⦇ reg c d ,DELEG⦈
         vDelegs , sDelegs , rwds ∪ˡ  c , 0  


data _⊢_⇀⦇_,POOL⦈_ where


  POOL-regpool :
     kh  dom pools
      ────────────────────────────────
      pp    pools , retiring  ⇀⦇ regpool kh poolParams ,POOL⦈
              kh , poolParams  ∪ˡ pools , retiring 

  POOL-retirepool :
    ────────────────────────────────
    pp   pools , retiring  ⇀⦇ retirepool kh e ,POOL⦈  pools ,  kh , e  ∪ˡ retiring 


data _⊢_⇀⦇_,GOVCERT⦈_ where


  GOVCERT-regdrep :
    let Γ =  e , pp , vs , wdrls , cc 
    in
     (d  pp .drepDeposit × c  dom dReps)  (d  0 × c  dom dReps)
      ────────────────────────────────
      Γ   dReps , ccKeys  ⇀⦇ regdrep c d an ,GOVCERT⦈
            c , e + pp .drepActivity  ∪ˡ dReps , ccKeys 

  GOVCERT-deregdrep :
     c  dom dReps
      ────────────────────────────────
       e , pp , vs , wdrls , cc    dReps , ccKeys  ⇀⦇ deregdrep c d ,GOVCERT⦈  dReps   c   , ccKeys 

  GOVCERT-ccreghot :
     (c , nothing)  ccKeys
     c  cc
      ────────────────────────────────
       e , pp , vs , wdrls , cc    dReps , ccKeys  ⇀⦇ ccreghot c mc ,GOVCERT⦈  dReps ,  c , mc  ∪ˡ ccKeys 


data _⊢_⇀⦇_,CERT⦈_ where


  CERT-deleg :
      pp , PState.pools stᵖ , dom (GState.dreps stᵍ)   stᵈ ⇀⦇ dCert ,DELEG⦈ stᵈ'
      ────────────────────────────────
       e , pp , vs , wdrls , cc    stᵈ , stᵖ , stᵍ  ⇀⦇ dCert ,CERT⦈  stᵈ' , stᵖ , stᵍ 

  CERT-pool :
     pp  stᵖ ⇀⦇ dCert ,POOL⦈ stᵖ'
      ────────────────────────────────
       e , pp , vs , wdrls , cc    stᵈ , stᵖ , stᵍ  ⇀⦇ dCert ,CERT⦈  stᵈ , stᵖ' , stᵍ 

  CERT-vdel :
     Γ  stᵍ ⇀⦇ dCert ,GOVCERT⦈ stᵍ'
      ────────────────────────────────
      Γ   stᵈ , stᵖ , stᵍ  ⇀⦇ dCert ,CERT⦈  stᵈ , stᵖ , stᵍ' 


data _⊢_⇀⦇_,CERTBASE⦈_ where


  CERT-base :
    let refresh          = mapPartial getDRepVote (fromList vs)
        refreshedDReps   = mapValueRestricted (const (e + pp .drepActivity)) dReps refresh
        wdrlCreds        = mapˢ stake (dom wdrls)
        validVoteDelegs  = voteDelegs ∣^ (  mapˢ (credVoter DRep) (dom dReps)
                                         fromList (noConfidenceRep  abstainRep  []) )
    in
     filter isKeyHash wdrlCreds  dom voteDelegs
     mapˢ (map₁ stake) (wdrls ˢ)  rewards ˢ
      ────────────────────────────────
       e , pp , vs , wdrls , cc  
          voteDelegs , stakeDelegs , rewards 
        , stᵖ
        ,  dReps , ccHotKeys 
         ⇀⦇ _ ,CERTBASE⦈
          validVoteDelegs , stakeDelegs , constMap wdrlCreds 0 ∪ˡ rewards 
        , stᵖ
        ,  refreshedDReps , ccHotKeys