Source code on Github
open import Data.List.Membership.Propositional.Properties using (∈-map⁻; ∈-map⁺; ∈-filter⁻)

open import Prelude.Init hiding (_∋_)
open import Prelude.General
open import Prelude.Lists
open import Prelude.DecEq
open import Prelude.ToN
open import Prelude.Membership

open import UTxO.Hashing
open import UTxO.Value
open import UTxO.Types hiding (I)
open import UTxO.TxUtilities
open import UTxO.Validity
open import StateMachine.Base

open InputInfo

module Bisimulation.Base
  {S I : Set} {{_ : IsData S}} {{_ : IsData I}} {sm : StateMachine S I}
  where

open CEM {sm = sm}

_—→[_]_ : S  I  (S × TxConstraints)  Set
s —→[ i ] (s′ , tx≡) = stepₛₘ s i  just (s′ , tx≡)

infix 30 _—→[_∶-_]_
_—→[_∶-_]_ :  {l}  ValidLedger l  (tx : Tx)  IsValidTx tx l  ValidLedger (tx  l)  Set
vl —→[ tx ∶- vtx ] vl′ = vl′  vl  tx ∶- vtx

_~_ :  {l}  ValidLedger l  S  Set
_~_ {l} _ s = (toData s) ♯ᵈ  ( map (datumHash  out)
                               filter ((_≟ true)  (_≥ᶜ threadₛₘ)  value  out)
                               filter ((𝕍 ≟_)  address  out)
                              -- ∘ map out
                              ) (utxo l)

-- alternative definition (T0D0: replace everywhere)
-- _~′_ : ∀ {l} → ValidLedger l → S → Set
-- _~′_ {l} _ s = Any (λ o → (address o ≡ 𝕍) × (datumHash o ≡ toData s ♯ᵈ) × (nftₛₘ ∈ᶜ value o)) (map out $ utxo l)

view-~ :  {l} {s : S} {vl : ValidLedger l}
   vl ~ s
    λ prevTx   λ v  Σ (s —→ v  outputs prevTx) λ prevOut∈ 
      let
        oRef = (prevTx ♯ₜₓ) indexed-at toℕ (L.Any.index prevOut∈)
        out  = record { address = 𝕍; datumHash = toData s ♯ᵈ; value = v }
        u    = record { prevTx = prevTx; out = out; outRef = oRef }
      in ( u  utxo l
         × prevTx  l
         × oRef  map outRef (utxo l)
         × (getSpentOutputRef l oRef  just out)
         × ((v ≥ᶜ threadₛₘ)  true)
         )
view-~ {l} {s} vl~s
  with ∈-map⁻ (datumHash  out) vl~s
... | u@(record {prevTx = prevTx; out = record {value = v}}) , out∈ , refl
  with ∈-filter⁻ ((_≟ true)  (_≥ᶜ threadₛₘ)  value  out) {xs = filter _ (utxo l)} out∈
... | u∈′ , threadToken≡
  with ∈-filter⁻ ((𝕍 ≟_)  address  out) {xs = utxo l} u∈′
... | u∈ , refl
  with ∈utxo⇒outRef≡ {u = u} {l = l} u∈
... | prev∈ , prevOut∈ , refl
    = prevTx , v , prevOut∈ , u∈ , prev∈ , ∈-map⁺ outRef u∈ , spent≡ , threadToken≡
  where
    oRef = (prevTx ♯ₜₓ) indexed-at toℕ (L.Any.index prevOut∈)
    o    = record { address = 𝕍; datumHash = toData s ♯ᵈ; value = v }
    u′   = record { prevTx = prevTx; out = o; outRef = oRef }

    spent≡ : getSpentOutputRef l oRef  just o
    spent≡ = utxo-getSpent {l = l} {u = u′} u∈

Satisfiable :  {s l} {vl : ValidLedger l}
   TxConstraints
   vl ~ s
   Set
Satisfiable {l = l} {vl} tx≡ vl~s
  with view-~ {vl = vl} vl~s
... | _ , v , _
    = (range≡ tx≡ >>=ₜ (_∋ length l)  true)
    × (spent≥ tx≡ >>=ₜ (v ≥ᶜ_)  true)
    × (∀ tx 
        All {A = MonetaryPolicy}
             f  T (f (toPendingMPS l tx (f ))))
            (maybe (map proj₁) [] (forge≡ tx≡)))

mkTx :  {l} {s s′ : S} {i : I} {vl : ValidLedger l} {vl~s : vl ~ s}
   (tx≡ : TxConstraints)
   Satisfiable {vl = vl} tx≡ vl~s
   Σ[ tx  Tx ] (verifyTx l tx tx≡  true)
mkTx {l} {s} {s′} {i} {vl} {vl~s} tx≡ (r≡ , s≥ , _)
  with view-~ {vl = vl} vl~s
... | prevTx , v , prevOut∈ , _ , _ , _ , getSpent≡ , _
    = tx , verify≡
    where
      frg = maybe toValue $0 (forge≡ tx≡)
      rng = M.fromMaybe (-∞  +∞) (range≡ tx≡)
      plc = maybe (map proj₁) [] (forge≡ tx≡)

      i₀ = (prevTx ♯ₜₓ) indexed-at toℕ (L.Any.index prevOut∈) ←— (i , s)

      tx = record { inputs   = [ i₀ ]
                  ; outputs  = [ s′ —→ (frg +ᶜ v) ]
                  ; policies = plc
                  ; forge    = frg
                  ; range    = rng
                  ; datumWitnesses = [ toData s′ ♯ᵈ , toData s′ ] }

      txi = mkTxInfo l tx

      frgT : (forge≡ tx≡ >>=ₜ λ v   TxInfo.forge txi  toValue v )  true
      frgT with forge≡ tx≡
      ... | nothing = refl
      ... | just v  rewrite ≟-refl (toValue v) = refl

      rngT : (range≡ tx≡ >>=ₜ λ r   TxInfo.range txi  r )  true
      rngT with range≡ tx≡
      ... | nothing = refl
      ... | just v  rewrite ≟-refl v = refl

      v≡ : valueSpent txi  v
      v≡ rewrite sum-single {v = InputInfo.value (mkInputInfo l i₀)}
               | getSpent≡
               = refl

      spT  : (spent≥ tx≡ >>=ₜ (valueSpent txi ≥ᶜ_))  true
      spT rewrite v≡ = s≥

      verify≡ : verifyTx l tx tx≡  true
      verify≡ rewrite frgT | rngT | spT = refl