Source code on Github
module EUTxOErr.DoubleSatisfaction where

open import Prelude.Init; open SetAsType
open import Prelude.General using (true⇒T)
open import Prelude.DecEq
open import Prelude.Decidable
open import Prelude.Membership
open import Prelude.Allable
open import Prelude.InferenceRules

open import EUTxOErr
  hiding (s)
  renaming (S to UTxOSet)
  renaming (_‼_ to _‼ᵐ_)
open import Prelude.Lists.Indexed using (_‼_)

data S : Type where
    : S

toggleS : S  S
toggleS = λ where
    
    

instance
  _ : ToData S
  _ = record {serialise = ser; serialise-inj = serInj; deserialise = deser}
    where
    ser = λ where
        "◇"
        "◆"

    deser : _
    deser d =
      Nullary.map′
        Sum.[  ,_ ,  ,_ ]
         where ( , d≡)  inj₁ d≡; ( , d≡)  inj₂ d≡)
        ¿ (d  "◇")  (d  "◆") ¿

    serInj : Injective≡ ser
    serInj {}{} refl = refl
    serInj {}{} refl = refl
    serInj {}{} ()
    serInj {}{} ()

-- ** Validator
toggle : Validator
toggle toggle♯ record {inputs = is; outputs = os} _ d
  with deserialise {A = S} d
... | no _ = false
... | yes (s , _) =  consume◇ ∈? is    produce◆ ∈? os 
  where
    consume◇ = record
      { outputRef =  serialise s   1  at toggle♯
      ; validatorHash = toggle♯
      ; redeemerHash = ""  }
    produce◆ =  serialise (toggleS s)   1  at toggle♯
toggle♯ = toggle 

-- Fix one direction for now: ◇ ↝ ◆
consume◇ = InputInfo  record
  { outputRef     =  serialise    1  at toggle♯
  ; validatorHash = toggle♯
  ; redeemerHash  = ""  }
produce◆ = OutputInfo 
   serialise    1  at toggle♯

module _
  {r : DATA} {txi : TxInfo}
  (let d = serialise 
       record {inputs = is; outputs = os} = txi)
  where

  toggle≡ :
     consume◇  is
     produce◆  os
      ──────────────────────────
      call toggle txi r d  true
  toggle≡ ◇∈is ◆∈os
    rewrite deserialise∘serialise 
          | dec-yes (consume◇ ∈? is) ◇∈is .proj₂
          | dec-yes (produce◆ ∈? os) ◆∈os .proj₂
          = refl
--

t₀ = Tx  record
  { inputs = []
  ; outputs = [  serialise   1  at toggle♯ ]
  ; forge = 1  }
t₀₀ = (t₀ ) indexed-at 0

o  = TxOutput        serialise   1  at toggle♯
i  = TxInput        record { outputRef = t₀₀ ; validator = toggle ; redeemer = "" }
ri = ResolvedInput  i , o

t₁ = Tx  record
  { inputs  = [ i ]
  ; outputs = [  serialise   1  at toggle♯ ]
  ; forge   = 0  }
t₁₀ = (t₁ ) indexed-at 0

t₁′ = Tx  record
  { inputs  = [ i ]
  ; outputs =  serialise   1  at toggle♯
              serialise   1  at toggle♯
             []
  ; forge   = 1  }
t₁′₀ = (t₁′ ) indexed-at 0
t₁′₁ = (t₁′ ) indexed-at 1

singleSat doubleSat : L
singleSat = t₀  t₁   []
doubleSat = t₀  t₁′  []

v₀ : VL  [ t₀ ]
v₀ = t₀
   record { noDoubleSpending    = []
           ; validOutputRefs     = []
           ; preservesValues     = refl
           ; allInputsValidate   = []
           ; validateValidHashes = [] }
   []

s₀ =  t₀ ⟧₀ 

_ = s₀  singleton (t₀₀ , o)
   refl

module ⦅1⦆ where
  vor : ∀[ ref  outputRefs t₁ ] (ref ∈ᵈ s₀)
  vor = here refl  []

  rt₁ = Resolved t₁
       L.All.map (s₀ ‼ᵐ_) vor

  _ = mkUtxo t₀ (here refl)  (t₀₀ , o)
     refl

  rt≡ : rt₁  [ o ]
  rt≡ = cong (_∷ []) $ ‼-singleton {k = t₀₀}{o}

  txi  = mkTxInfo t₁ rt₁
  is = txi .TxInfo.inputs
  os = txi .TxInfo.outputs

  ris = ResolvedInputs
       resolveInputs t₁ rt₁

  postulate ris≡ : ris  [ ri ]
  -- ris≡ rewrite ≟-refl 0 | ≟-refl "" | ≟-refl '◇' = cong [_] (cong (i ,_) refl)

  val≡ : T (call (i .validator) txi (i .redeemer) (o .datum))
  val≡ = true⇒T $
    begin
      call (i .validator) txi (i .redeemer) (o .datum)
    ≡⟨⟩
      toggle toggle♯ txi "" (serialise )
    ≡⟨ toggle≡ {""}{txi}
        ( subst (Any (consume◇ ≡_)  map mkInputInfo) (sym ris≡)
        $ here refl
        )
        (here refl) 
      true
     where open ≡-Reasoning

  _ : VL  singleSat
  _ = t₀
     record
      { noDoubleSpending    = []
      ; validOutputRefs     = []
      ; preservesValues     = refl
      ; allInputsValidate   = []
      ; validateValidHashes = []
      }
     t₁
     record
      { noDoubleSpending    = []  []
      ; validOutputRefs     = vor
      ; preservesValues     = pv
      ; allInputsValidate   = aiv
      ; validateValidHashes = vvh
      }
     []
    where
    pv : t₁ .forge +  ris (value  proj₂)   (t₁ .outputs) value
    pv = cong    t₁ .forge +   (value  proj₂)) ris≡

    aiv : ∀[ (i , o)  ris ]
      T (call (i .validator) txi (i .redeemer) (o .datum))
    aiv = subst (L.All.All _) (sym ris≡)
        $ val≡  []

    vvh : ∀[ (i , o)  ris ]
      (o .address  i .validator )
    vvh = subst (L.All.All _) (sym ris≡)
        $ refl  []

  open HoareReasoning -- unsolved metas if inlined in `where` clause :(
  _ =
    begin
      emp
    ~⟨ t₀ ∶- 𝟘⇒𝟙 refl 
      t₀₀   serialise   1  at toggle♯
    ~⟨ t₁ ∶- 𝟙⇒𝟙 rt₁ val≡ refl 
      t₁₀   serialise   1  at toggle♯
    

module ⦅12⦆ where
  vor : ∀[ ref  outputRefs t₁′ ] (ref ∈ᵈ s₀)
  vor = here refl  []

  rt₁′ = Resolved t₁′
        L.All.map (s₀ ‼ᵐ_) vor

  _ = mkUtxo t₀ (here refl)  (t₀₀ , o)
     refl

  rt≡ : rt₁′  [ o ]
  rt≡ = cong (_∷ []) $ ‼-singleton {k = t₀₀}{o}

  txi  = mkTxInfo t₁′ rt₁′
  is = txi .TxInfo.inputs
  os = txi .TxInfo.outputs

  ris = ResolvedInputs
       resolveInputs t₁′ rt₁′

  postulate ris≡ : ris  [ i , o ]
  -- ris≡ rewrite ≟-refl 0 | ≟-refl "" | ≟-refl '◇' = cong [_] (cong (i ,_) refl)

  val≡ : T (call (i .validator) txi (i .redeemer) (o .datum))
  val≡ = true⇒T $
    begin
      call (i .validator) txi (i .redeemer) (o .datum)
    ≡⟨⟩
      toggle toggle♯ txi "" (serialise )
    ≡⟨ toggle≡ {""}{txi}
        ( subst (Any (consume◇ ≡_)  map mkInputInfo) (sym ris≡)
        $ here refl
        )
        (here refl) 
      true
     where open ≡-Reasoning

  _ : VL  doubleSat
  _ = t₀
     record
      { noDoubleSpending    = []
      ; validOutputRefs     = []
      ; preservesValues     = refl
      ; allInputsValidate   = []
      ; validateValidHashes = []
      }
     t₁′
     record
      { noDoubleSpending    = []  []
      ; validOutputRefs     = vor
      ; preservesValues     = pv
      ; allInputsValidate   = aiv
      ; validateValidHashes = vvh
      }
     []
    where
    pv : t₁′ .forge +  ris (value  proj₂)   (t₁′ .outputs) value
    pv = cong    t₁′ .forge +   (value  proj₂)) ris≡

    aiv : ∀[ (i , o)  ris ]
      T (call (i .validator) txi (i .redeemer) (o .datum))
    aiv = subst (L.All.All _) (sym ris≡)
        $ val≡  []

    vvh : ∀[ (i , o)  ris ]
      (o .address  i .validator )
    vvh = subst (L.All.All _) (sym ris≡)
        $ refl  []

  open HoareReasoning
  _ =
    begin
      emp
    ~⟨ t₀ ∶- 𝟘⇒𝟙 refl 
      t₀₀   serialise   1  at toggle♯
    ~⟨ t₁′ ∶- 𝟙⇒𝟚 rt₁′ val≡ refl 
      t₁′₀   serialise   1  at toggle♯
      
      t₁′₁   serialise   1  at toggle♯
    

-- ** Rule out double satisfaction

data YesDP (s₀ : UTxOSet) : Type₁ where
  yesDP :  {t txi txi′ txi″ v v′ v″} 
     txi    serialise   v   at toggle♯  -- ∗ R ⟩
    [ t ]
     txi′   serialise   v′  at toggle♯
     txi″   serialise   v″  at toggle♯ -- ∗ R
    ⟩@ s₀
    ──────────────────────────────────────────────
    YesDP s₀

yesDP-toggle :  s₀  YesDP s₀
yesDP-toggle s₀ = yesDP {t = $t} λ Ps₀ 
  let open 𝕄 Ps₀
  in 1⇒2 rt val≡ refl Ps₀
  where
    txi₀ = TxOutputRef  t₀₀

    $o  = TxOutput   serialise   1  at toggle♯
    $i  = TxInput   record
      { outputRef = txi₀ ; validator = toggle ; redeemer = "" }
    $ri = ResolvedInput  $i , $o

    $t = Tx  record
      { inputs  = [ $i ]
      ; outputs =  serialise   1  at toggle♯
                  serialise   1  at toggle♯
                 []
      ; forge   = 1  }

    module 𝕄 (Ps₀ : (t₀₀   serialise   1  at toggle♯) s₀) where
      postulate vor : ∀[ ref  outputRefs $t ] (ref ∈ᵈ s₀)
      -- vor = here refl ∷ []

      rt  = Resolved $t
           L.All.map (s₀ ‼ᵐ_) vor
      txi = mkTxInfo $t rt
      is  = txi .TxInfo.inputs
      os  = txi .TxInfo.outputs
      ris = resolveInputs $t rt

      postulate rt≡ : rt  [ $o ]
      -- rt≡ = cong (_∷ []) $ ‼-singleton {k = txi₀}{o}

      postulate ris≡ : ris  [ ri ]

      val≡ : T $ call toggle txi "" (serialise )
      val≡ = true⇒T $
        begin
          call toggle txi "" (serialise )
        ≡⟨ toggle≡ {""}{txi}
            ( subst (Any (consume◇ ≡_)  map mkInputInfo) (sym ris≡)
            $ here refl
            )
            (here refl) 
          true
         where open ≡-Reasoning

-- ** Fixed validator
toggle′ : Validator
toggle′ toggle♯ record {inputs = is; outputs = os} _ d
  with deserialise {A = S} d
... | no _ = false
... | yes (s , _) =  ¿ (is  [ consume◇′ ]) × (os  [ produce◆′ ]) ¿ 
  where
    consume◇′ = record
      { outputRef =  serialise    1  at toggle♯
      ; validatorHash = toggle♯
      ; redeemerHash = ""  }
    produce◆′ =  serialise    1  at toggle♯
toggle′♯ = toggle′ 

consume◇′ = InputInfo  record
  { outputRef     =  serialise    1  at toggle′♯
  ; validatorHash = toggle′♯
  ; redeemerHash  = ""  }
produce◆′ = OutputInfo 
   serialise    1  at toggle′♯

module _
  {s : S} {r : DATA} {txi : TxInfo}
  (let d = serialise s
       record {inputs = is; outputs = os} = txi)
  where

  toggle′≡ :
     is  [ consume◇′ ]
     os  [ produce◆′ ]
      ───────────────────────────
      call toggle′ txi r d  true
  toggle′≡ refl refl
    rewrite deserialise∘serialise s
          | ≟-refl consume◇′
          | ≟-refl produce◆′
          = refl
--

data NoDP : Type₁ where
  noDP :
    (¬ -- ∃ λ R →
        λ t 
        λ txi   λ txi′   λ txi″ 
        λ v   λ v′   λ v″ 
       txi    serialise   v   at toggle′♯  -- ∗ R ⟩
      [ t ]
       txi′   serialise   v′  at toggle′♯
       txi″   serialise   v″  at toggle′♯ -- ∗ R
      )
    ───────────────────────────────────────────────
    NoDP

postulate noDP-toggle′ : NoDP
-- noDP-toggle′ = noDP λ (t , txi , txi′ , txi″ , v , v′ , v″ , p) →
--   let Ps₀ = p {s₀} ({!!} , {!!})
--    in {!!}