2

As per entire code below, give always mandates that Wallet 2 be given:

thePkh :: PubKeyHash
thePkh = pubKeyHash $ walletPubKey $ Wallet 2

theVal :: Value
theVal = ADA.toValue (ADA.Lovelace 3_000_000) 

give :: Contract () PaySchema Text () 
give = do
    let param = PayParam thePkh theVal
    let tx = mustPayToTheScript () theVal
    ledgerTx <- submitTxConstraints (typedValidator param) tx

So why must I also invoke the grab endpoint for Wallet 2 (trace12)? What changes if instead it's invoked for Wallet 3 (trace13)?

trace12 #######################################
...
Final balances
Wallet 1: 
    {, ""}: 96999990
Wallet 2: 
    {, ""}: 102996448
Wallet 3: 
    {, ""}: 100000000
Wallet 4: 
    {, ""}: 100000000
Wallet 5: 
    {, ""}: 100000000
Wallet 6: 
    {, ""}: 100000000
Wallet 7: 
    {, ""}: 100000000
Wallet 8: 
    {, ""}: 100000000
Wallet 9: 
    {, ""}: 100000000
Wallet 10: 
    {, ""}: 100000000

Note that if Wallet 3 instead is invoked for grab, then the result is different:

trace13 #######################################
...
Final balances
Wallet 1: 
    {, ""}: 96999990
Wallet 2: 
    {, ""}: 100000000
Wallet 3: 
    {, ""}: 100000000
Wallet 4: 
    {, ""}: 100000000
Wallet 5: 
    {, ""}: 100000000
Wallet 6: 
    {, ""}: 100000000
Wallet 7: 
    {, ""}: 100000000
Wallet 8: 
    {, ""}: 100000000
Wallet 9: 
    {, ""}: 100000000
Wallet 10: 
    {, ""}: 100000000
Script 3f3c25dfdfad56d6f08d6d3e8bec53ab14d1950be944bc0ed26957c6: 
    {, ""}: 3000000

Why is that? And what does it mean to invoke an endpoint for a wallet altogether?

{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE DeriveAnyClass             #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE NoImplicitPrelude          #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeApplications           #-}
{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE TypeOperators              #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE DerivingStrategies         #-}
{-# LANGUAGE NumericUnderscores         #-}
{-# LANGUAGE TupleSections              #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}


module ASK (trace12, trace13 ) where
import           Control.Monad        hiding (fmap)
import           Data.Map            as Map
import           Data.Monoid               as Mnd ( (<>), Monoid(mconcat) )
import           Data.Text            (Text, unpack)
import           Data.Void            (Void)
import           GHC.Generics         (Generic)
import qualified Prelude              as H--askell

import           Plutus.Contract
import qualified Plutus.Trace.Emulator as Emu
import           PlutusTx             (Data (..))
import qualified PlutusTx
import           PlutusTx.Prelude     hiding (Semigroup(..), unless) 
import           Ledger               hiding (singleton)
import           Ledger.Constraints   as Constraints
import qualified Ledger.Typed.Scripts as Scripts
import           Ledger.Value         (Value(Value), geq)
import           Wallet.Emulator.Wallet  (Wallet(Wallet), walletPubKey)
import qualified Plutus.V1.Ledger.Ada as ADA
import qualified Control.Monad.Freer.Extras as Extras


data PayParam = PayParam
    { _pkh :: PubKeyHash
    , _val :: Value
    } deriving H.Show


PlutusTx.makeLift ''PayParam


{-# INLINABLE mkValidator #-}
mkValidator :: PayParam -> () -> () -> ScriptContext -> Bool
mkValidator param () () ctx = 
    traceIfFalse "beneficiary's signature missing" signedByBeneficiary
        where
            info :: TxInfo
            info = scriptContextTxInfo ctx

            signedByBeneficiary :: Bool
            signedByBeneficiary = txSignedBy info $ _pkh param


data Lock
instance Scripts.ValidatorTypes Lock where
    type instance DatumType Lock = ()
    type instance RedeemerType Lock = ()


typedValidator :: PayParam -> Scripts.TypedValidator Lock
typedValidator param = Scripts.mkTypedValidator @Lock
    ($$(PlutusTx.compile [|| mkValidator ||]) `PlutusTx.applyCode` PlutusTx.liftCode param)
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = Scripts.wrapValidator @() @()


{-# INLINABLE validator #-}
validator :: PayParam -> Validator
validator = Scripts.validatorScript . typedValidator


{-# INLINABLE valHash #-}
valHash :: PayParam -> Ledger.ValidatorHash
valHash = Scripts.validatorHash . typedValidator


{-# INLINABLE scrAddress #-}
scrAddress :: PayParam -> Ledger.Address
scrAddress = scriptAddress  . validator

--------------------------

{-# INLINABLE thePkh #-}
thePkh :: PubKeyHash
thePkh = pubKeyHash $ walletPubKey $ Wallet 2


{-# INLINABLE theVal #-}
theVal :: Value
theVal = ADA.toValue (ADA.Lovelace 3_000_000) 


give :: Contract () PaySchema Text () 
give = do
    let param = PayParam thePkh theVal

    let tx = mustPayToTheScript () theVal
    ledgerTx <- submitTxConstraints (typedValidator param) tx

    -- also works fine
    -- let tx = mustPayToOtherScript (valHash param) unitDatum theVal
    -- ledgerTx <- submitTx tx

    void $ awaitTxConfirmed $ txId ledgerTx
    logInfo @H.String "\ngive"


grab :: Contract () PaySchema Text () 
grab = do      
    let param = PayParam thePkh theVal

    utxos <- utxoAt $ scrAddress param
    let lookups = Constraints.unspentOutputs utxos <>
                  Constraints.otherScript (validator param) <>
                  Constraints.typedValidatorLookups (typedValidator param)
   
    let orefs = fst <$> Map.toList utxos

    let tx :: TxConstraints () ()
        tx = PlutusTx.Prelude.mconcat [mustSpendScriptOutput oref unitRedeemer | oref <- orefs]    

    ledgerTx <- submitTxConstraintsWith @Lock lookups tx
    awaitTxConfirmed $ txId ledgerTx     
    logInfo @H.String "\ngrab"      


type PaySchema =
    Endpoint "give" ()
        .\/ 
    Endpoint "grab" ()


endpoints :: Contract () PaySchema Text ()
endpoints = 
    forever
        $ handleError logError
        $ awaitPromise
        $ give' `select` grab' 
            where
                give' = endpoint @"give" $ const give 
                grab' = endpoint @"grab" $ const grab


trace12 :: H.IO ()
trace12 = Emu.runEmulatorTraceIO $ do
    h1 <- Emu.activateContractWallet (Wallet 1) endpoints
    h2 <- Emu.activateContractWallet (Wallet 2) endpoints
    void $ Emu.waitNSlots 5
    Emu.callEndpoint @"give" h1 ()
    void $ Emu.waitUntilSlot 10    
    Emu.callEndpoint @"grab" h2 ()
    void $ Emu.waitUntilSlot 15


trace13 :: H.IO ()
trace13 = Emu.runEmulatorTraceIO $ do
    h1 <- Emu.activateContractWallet (Wallet 1) endpoints
    h3 <- Emu.activateContractWallet (Wallet 3) endpoints
    void $ Emu.waitNSlots 5
    Emu.callEndpoint @"give" h1 ()
    void $ Emu.waitUntilSlot 10    
    Emu.callEndpoint @"grab" h3 ()
    void $ Emu.waitUntilSlot 15

plutus commit: plutus-starter-devcontainer/v1.0.7

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.