10

Below is my attempt to implement the homework assignment.

Is the way I call the endpoint twice in payTrace with minor differences appropriate?

Since payTest2 would not execute properly without modifying the original payContract, is the way I handle the contract error appropriate?

payContract :: Contract () PaySchema Text ()
payContract = do
    pp <- endpoint @"pay"
    let tx = mustPayToPubKey (ppRecipient pp) $ lovelaceValueOf $ ppLovelace pp
    Contract.handleError (\err -> Contract.logError $ "Caught error: " ++ unpack err) $ (void $ submitTx tx)
    payContract

-- A trace that invokes the pay endpoint of payContract on Wallet 1 twice, each time with Wallet 2 as
-- recipient, but with amounts given by the two arguments. There should be a delay of one slot
-- after each endpoint call.
payTrace :: Integer -> Integer -> EmulatorTrace ()
payTrace x y = do
    h1 <- activateContractWallet (Wallet 1) payContract
    callEndpoint @"pay" h1 $ PayParams
        { ppRecipient = pubKeyHash $ walletPubKey $ Wallet 2
        , ppLovelace  = x
        }
    void $ Emulator.waitNSlots 1
    xs <- observableState h1
    Extras.logInfo $ show xs

    callEndpoint @"pay" h1 $ PayParams
        { ppRecipient = pubKeyHash $ walletPubKey $ Wallet 2
        , ppLovelace  = y
        }
    void $ Emulator.waitNSlots 1
    ys <- observableState h1
    Extras.logInfo $ show ys

I retracted the surrounding code that has not been modified. The start code can be found here.

2 Answers 2

3

The exception handler does not cover the first payment contract run. I've created a separate function for this that handles this error:

payContract' :: Contract () PaySchema Void ()
payContract' = Contract.handleError
    (\err -> Contract.logError $ "Caught error: " ++ unpack err)
    payContract

Then of course you have to call the payContract' in your emulator tracer as follows:

h1 <- activateContractWallet (Wallet 1) payContract'

You can also combine everything together like this:

payContract :: Contract () PaySchema Text ()
payContract = Contract.handleError
    (\err -> Contract.logError $ "Caught error: " ++ unpack err) $ do
    pp <- endpoint @"pay"
    let tx = mustPayToPubKey (ppRecipient pp) $ lovelaceValueOf $ ppLovelace pp
    void $ submitTx tx
    payContract
1
1

I did a similar solution as @Mankeh - I added a second function to catch the error on the first transaction. Theirs is cleaner than mine.

And after checking the solution, I see that I got the order of submitTx and Contract.handleError mixed up in the payContract function. If I had put them in the solution's order, then the first error would be caught and the second 'wrapper' function wouldn't have been needed.

-- my solution
payContract :: Contract () PaySchema Text ()
payContract = do
    pp <- endpoint @"pay"
    let tx = mustPayToPubKey (ppRecipient pp) $ lovelaceValueOf $ ppLovelace pp
    void $ submitTx tx
    Contract.handleError (\err -> Contract.logError $ "Caught error inner1: " ++ unpack err) 
        payContract
    

payContractErrHandler :: Contract () PaySchema Text ()
payContractErrHandler = do
    Contract.handleError (\err -> Contract.logError $ "Caught error: " ++ unpack err)
        payContract
    payContractErrHandler

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.