{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
# LANGUAGE NoImplicitPrelude    #
# LANGUAGE ScopedTypeVariables #
# LANGUAGE TemplateHaskell      #
# LANGUAGE TypeApplications     #
# LANGUAGE TypeFamilies         #
{-# LANGUAGE TypeOperators       #-}
{-# LANGUAGE OverloadedStrings   #-}

module MathBounty where

PlutusTx
import           PlutusTx                       (Data (..))
import qualified PlutusTx
import qualified PlutusTx.Builtins              as Builtins
import           PlutusTx.Prelude               hiding (Semigroup(..), unless)
--Contract Monad
import           Plutus.Contract               
--Ledger 
import           Ledger                         hiding (singleton)
import qualified Ledger.Address                 as V1Address
  Same library name , different functions for V1 and V2 in some cases
import qualified Ledger . Typed . Scripts          as Scripts              
  New library name for Typed  and some new fuctions
import qualified Plutus.V1.Ledger.Api                 as PlutusV1           -- 
import           Ledger.Ada                     as Ada
Trace Emulator
import           Plutus.Trace
import qualified Plutus.Trace.Emulator          as Emulator
import qualified Wallet.Emulator.Wallet         as Wallet
  ( broken ) 
 import            Playground . Contract             ( printJson , printSchemas , ensureKnownCurrencies , stage ) 
 import            Playground . TH                   ( mkKnownCurrencies , mkSchemaDefinitions ) 
 import            Playground . Types                (  ( .. ) ) 
 --"Normal " Haskell
import           Playground.Contract            (printJson, printSchemas, ensureKnownCurrencies, stage)
import           Playground.TH                  (mkKnownCurrencies, mkSchemaDefinitions)
import           Playground.Types               (KnownCurrency (..))
--"Normal" Haskell -}
import           Control.Monad                  hiding (fmap)
import           Data.Map                       as Map
import           Data.Text                      (Text)
import           Data.Void                      (Void)
import           Prelude                        (IO, Semigroup (..), String, show)
import           Text.Printf                    (printf)
import           Control.Monad.Freer.Extras     as Extras


 import Language .  . TH ( RuleBndr(TypedRuleVar ) ) 

import Language.Haskell.TH (RuleBndr(TypedRuleVar))
-}

# OPTIONS_GHC -fno - warn - unused - imports #

--THE ON-CHAIN CODE

newtype MyWonderfullRedeemer = MWR Integer

  At compile time write an instance of this data type ( MyWonderFullRedeemer ) on the IsData typeclass

# INLINABLE typedRedeemer #
typedRedeemer :: () -> MyWonderfullRedeemer -> PlutusV1.ScriptContext -> Bool   
typedRedeemer _ (MWR redeemer) _ = traceIfFalse "Wrong redeemer!" (redeemer == 42)
 

  New type that encode the information about the Datum and the Redeemer
instance Scripts.ValidatorTypes Typed where
     type instance RedeemerType Typed = MyWonderfullRedeemer
     type instance DatumType Typed = ()

typedValidator :: Scripts.TypedValidator Typed
typedValidator = Scripts.mkTypedValidator @Typed      
    $$(PlutusTx.compile [|| typedRedeemer ||]) 
    $$(PlutusTx.compile [|| wrap ||])                               
  where
    wrap = Scripts.mkUntypedValidator  @() @MyWonderfullRedeemer     --New wrapper function for typed validators             
    

validator :: Validator
validator = Scripts.validatorScript typedValidator                   -- Get the untyped validator script of the wrapped typeValidator PlutusCore

valHash :: Ledger.ValidatorHash
valHash = Scripts.validatorHash typedValidator                      

scrAddress :: Ledger.Address
  New functino to derive the address , included in the Utils library
--scrAddress = scriptAddress validator 


--THE OFFCHAIN CODE

type GiftSchema =
            Endpoint "give" Integer  --
        .\/ Endpoint "grab" Integer

give :: AsContractError e => Integer -> Contract w s e ()
give amount = do
  Typed version for one script , This Tx needs an output , that s its going to be the Script Address , Datum MUST be specified , so unit ( ) .
This line submit the Tx
    void $ awaitTxConfirmed $ getCardanoTxId ledgerTx                                                --This line waits for confirmation
    Plutus.Contract.logInfo @String $ printf "made a gift of %d lovelace" amount                                     --This line log info,usable on the PP(Plutus Playground)
    
--grab :: forall w s e. AsContractError e => Contract w s e ()                                     
grab :: forall w s e. AsContractError e => Integer -> Contract w s e ()                                     
grab n = do
    utxos <- utxosAt scrAddress                                                                      -- This will find all UTXOs that sit at the script address
    let orefs   = fst <$> Map.toList utxos                                                           -- This get all the references of the UTXOs
        lookups = Constraints.unspentOutputs utxos      <>                                           -- Tell where to find all the UTXOS
  and inform about the actual validator ( the spending tx needs to provide the actual validator )
        tx :: TxConstraints Void Void                                                            
  Define the TX giving constrains , one for each UTXO sitting on this addrs ,
                                                                                                     -- must provide a redeemer (ignored in this case)
  Allow the wallet to construct the tx with the necesary information
    void $ awaitTxConfirmed $ getCardanoTxId ledgerTx                                                -- Wait for confirmation
    Plutus.Contract.logInfo @String $ "collected gifts"                                                              -- Log information 

endpoints :: Contract () GiftSchema Text ()
endpoints = awaitPromise (give' `select` grab') >> endpoints                                         -- Asynchronously wait for the endpoints interactions from the wallet
  where                                                                                              -- and recursively wait for the endpoints all over again
    give' = endpoint @"give" give                                                                    -- block until give
    grab' = endpoint @"grab" grab                                                                    -- block until grab

  Playground broken at the moment - September 2022
  mkSchemaDefinitions '' GiftSchema                                                                      -- Generate the Schema for the playground
-- mkKnownCurrencies [] 

--SIMULATION

test :: IO ()
test = runEmulatorTraceIO $ do
    h1 <- activateContractWallet (Wallet.knownWallet 1) endpoints
    h2 <- activateContractWallet (Wallet.knownWallet 2) endpoints
    callEndpoint @"give" h1 $ 51000000
    void $ Emulator.waitNSlots 11
    callEndpoint @"grab" h2 42
    s <- Emulator.waitNSlots 11
    Extras.logInfo $ "End of Simulation at slot " ++ show s
# LANGUAGE DataKinds           #
# LANGUAGE FlexibleContexts    #
# LANGUAGE TypeOperators       #
# LANGUAGE OverloadedStrings   #
Contract Monad
Ledger 
 
"Normal " Haskell
"Normal" Haskell -}
THE ON-CHAIN CODE
New wrapper function for typed validators             
 Get the untyped validator script of the wrapped typeValidator PlutusCore
scrAddress = scriptAddress validator 
THE OFFCHAIN CODE

This line waits for confirmation
This line log info,usable on the PP(Plutus Playground)
grab :: forall w s e. AsContractError e => Contract w s e ()                                     
 This will find all UTXOs that sit at the script address
 This get all the references of the UTXOs
 Tell where to find all the UTXOS
 must provide a redeemer (ignored in this case)
 Wait for confirmation
 Log information 
 Asynchronously wait for the endpoints interactions from the wallet
 and recursively wait for the endpoints all over again
 block until give
 block until grab
 Generate the Schema for the playground
 mkKnownCurrencies [] 
SIMULATION
# LANGUAGE NoImplicitPrelude    #
# LANGUAGE ScopedTypeVariables #
# LANGUAGE TemplateHaskell      #
# LANGUAGE TypeApplications     #
# LANGUAGE TypeFamilies         #

module MathBounty where

PlutusTx
import           PlutusTx                       (Data (..))
import qualified PlutusTx
import qualified PlutusTx.Builtins              as Builtins
import           PlutusTx.Prelude               hiding (Semigroup(..), unless)
import           Plutus.Contract               
import           Ledger                         hiding (singleton)
import qualified Ledger.Address                 as V1Address
  Same library name , different functions for V1 and V2 in some cases
import qualified Ledger . Typed . Scripts          as Scripts              
  New library name for Typed  and some new fuctions
import           Ledger.Ada                     as Ada
Trace Emulator
import           Plutus.Trace
import qualified Plutus.Trace.Emulator          as Emulator
import qualified Wallet.Emulator.Wallet         as Wallet
  ( broken ) 
 import            Playground . Contract             ( printJson , printSchemas , ensureKnownCurrencies , stage ) 
 import            Playground . TH                   ( mkKnownCurrencies , mkSchemaDefinitions ) 
 import            Playground . Types                (  ( .. ) ) 
import           Playground.Contract            (printJson, printSchemas, ensureKnownCurrencies, stage)
import           Playground.TH                  (mkKnownCurrencies, mkSchemaDefinitions)
import           Playground.Types               (KnownCurrency (..))
import           Control.Monad                  hiding (fmap)
import           Data.Map                       as Map
import           Data.Text                      (Text)
import           Data.Void                      (Void)
import           Prelude                        (IO, Semigroup (..), String, show)
import           Text.Printf                    (printf)
import           Control.Monad.Freer.Extras     as Extras


 import Language .  . TH ( RuleBndr(TypedRuleVar ) ) 

import Language.Haskell.TH (RuleBndr(TypedRuleVar))
-}

# OPTIONS_GHC -fno - warn - unused - imports #


newtype MyWonderfullRedeemer = MWR Integer

  At compile time write an instance of this data type ( MyWonderFullRedeemer ) on the IsData typeclass

# INLINABLE typedRedeemer #
typedRedeemer :: () -> MyWonderfullRedeemer -> PlutusV1.ScriptContext -> Bool   
typedRedeemer _ (MWR redeemer) _ = traceIfFalse "Wrong redeemer!" (redeemer == 42)
 

  New type that encode the information about the Datum and the Redeemer
instance Scripts.ValidatorTypes Typed where
     type instance RedeemerType Typed = MyWonderfullRedeemer
     type instance DatumType Typed = ()

typedValidator :: Scripts.TypedValidator Typed
typedValidator = Scripts.mkTypedValidator @Typed      
    $$(PlutusTx.compile [|| typedRedeemer ||]) 
    $$(PlutusTx.compile [|| wrap ||])                               
  where
    

validator :: Validator

valHash :: Ledger.ValidatorHash
valHash = Scripts.validatorHash typedValidator                      

scrAddress :: Ledger.Address
  New functino to derive the address , included in the Utils library



type GiftSchema =
        .\/ Endpoint "grab" Integer

give :: AsContractError e => Integer -> Contract w s e ()
give amount = do
  Typed version for one script , This Tx needs an output , that s its going to be the Script Address , Datum MUST be specified , so unit ( ) .
This line submit the Tx
    
grab :: forall w s e. AsContractError e => Integer -> Contract w s e ()                                     
grab n = do
  and inform about the actual validator ( the spending tx needs to provide the actual validator )
        tx :: TxConstraints Void Void                                                            
  Define the TX giving constrains , one for each UTXO sitting on this addrs ,
  Allow the wallet to construct the tx with the necesary information

endpoints :: Contract () GiftSchema Text ()

  Playground broken at the moment - September 2022


test :: IO ()
test = runEmulatorTraceIO $ do
    h1 <- activateContractWallet (Wallet.knownWallet 1) endpoints
    h2 <- activateContractWallet (Wallet.knownWallet 2) endpoints
    callEndpoint @"give" h1 $ 51000000
    void $ Emulator.waitNSlots 11
    callEndpoint @"grab" h2 42
    s <- Emulator.waitNSlots 11
    Extras.logInfo $ "End of Simulation at slot " ++ show s