I am a mobile developer and I am very interested in Cardano, so I am now learning how to develop smart contracts in Plutus. I am currently enrolled in the udemy course but the Q&A section there doesn’t seem active, so I am hoping we can have a more active discussion here.
I am having issues using the Ada datatype. Here is a very basic example that doesn’t work. I noticed that it works fine if I replace the Ada with Value as the parameter for the lock method. Not sure what is happening here.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -O0 #-}
module Tutorial.ValidatorScripts where
import qualified Language.PlutusTx as PlutusTx
import qualified Ledger.Interval as Interval
import Ledger.Slot (SlotRange)
import qualified Ledger.Slot as Slot
import qualified Language.PlutusTx.Prelude as P
import Ledger as L
import qualified Ledger.Ada.TH as Ada
import Ledger.Ada (Ada)
import Ledger.Validation as V
import Playground.Contract
import Wallet as W
data TxText = TxText (P.SizedByteString 32)
PlutusTx.makeLift ''TxText
payload :: TxText -> DataScript
payload text = DataScript $ L.lifted text
validator :: ValidatorScript
validator = ValidatorScript $$(L.compileScript [||
\(ds :: ()) (rs :: ()) (_ :: PendingTx) -> ()
||])
address :: Address
address = L.scriptAddress validator
lock :: MonadWallet m => Ada -> m ()
lock value = do
_ <- if value <= 0
then throwOtherError "Must contribute a positive value"
else pure ()
let ds = payload $ TxText "Test"
range = W.defaultSlotRange
ammount = $$(Ada.toValue) value
payToScript_ range address ammount ds
logMsg "Submitted contribution"
$(mkFunctions ['lock])
Working:
lock :: MonadWallet m => Value -> m ()
lock value = do
let ds = payload $ TxText "Test"
range = W.defaultSlotRange
ammount = value
payToScript_ range address ammount ds
logMsg "Submitted contribution"
I also enrolled to the training and honestly… that’s a very bad training… poor content, poor audio, poor video… I am just wondering if they really want to engage people on this… for me it was a very bad training.
Hi @adapt, I tried your example and I get a NegativeValueError with the lock endpoint that uses Ada.
I think that’s a bug - the Playground has a different understanding of what Ada is, so when you set up a simulation that forges for example 10 “Playground-Ada”, and use the lock endpoint to lock 5 “Backend-Ada” then the transaction will fail because the wallet actually has 0 “Backend-Ada” at that time.I’ve created a github issue to track this: https://github.com/input-output-hk/plutus/issues/1005
@Jann_Mueller Perfect, thanks! I was not aware of that difference between Playground-Ada and Backend-Ada. That actually helps me understand the issues I’ve been having.
Since a wallet needs to call startWatching to keep track of the outputs for an address, collectFromScript (as far as I understand) will only collect funds from transactions that happened after startWatching.
Is there a way to collect funds from transactions that happened before the startWatching call?
As an example lets think of a smart contract that collects funds from multiple users and pays the total to a random user. This random user should be able to collect all the funds, even if they happened before he entered the game.
This isn’t possible in the current wallet API, to avoid forcing the wallet (which might be running in a resource constrained environment) to either go back through past transactions on the chain, or to keep track of the entire UTXO set.
But this question has come up a few times, and the final word on it hasn’t been spoken yet. It’s not impossible that you will be able to look at earlier transactions through the wallet API at some point.
PS @adapt You can just post any future questions about Plutus in the Plutus forum: https://forum.cardano.org/c/developers/plutus instead of this thread - then they will be easier to find and the discussion can be more focused.
How could you alter the crowdfunding contract example so that the funds could be paid to a different wallet than the campaignOwner?
I tried just creating the contract (run scheduleCollection) as wallet 1 and set wallet 3 to be the campaignOwner however this doesn’t work.
I’ve tried other ways and made some changes below to show my thinking, last two lines of scheduleCollection is incorrect but just trying to show an incorrect solution. Added a second wallet argument to scheduleCollection and added the campaignPayee to the Campaign.
At the end of scheduleCollection what I want to do is take the inputs of the contract and output them to campaignPayee who is not the person setting up the contract
-- added campaignPayee to pay to instead of campaignOwner
data Campaign = Campaign
{ campaignDeadline :: Slot
, campaignTarget :: Value
, campaignCollectionDeadline :: Slot
, campaignOwner :: PubKey
, campaignPayee :: PubKey
} deriving (Generic, ToJSON, FromJSON, ToSchema)
mkCampaign :: Slot -> Value -> Slot -> Wallet -> Wallet -> Campaign
mkCampaign ddl target collectionDdl ownerWallet payeeWallet =
Campaign
{ campaignDeadline = ddl
, campaignTarget = target
, campaignCollectionDeadline = collectionDdl
, campaignOwner = EM.walletPubKey ownerWallet
, campaignPayee = EM.walletPubKey payeeWallet
}
scheduleCollection :: MonadWallet m => Slot -> Value -> Slot -> Wallet -> Wallet -> m ()
scheduleCollection deadline target collectionDeadline ownerWallet payeeWallet = do
let cmp = mkCampaign deadline target collectionDeadline ownerWallet payeeWallet
register (collectFundsTrigger cmp) (EventHandler (\_ -> do
logMsg "Collecting funds"
let redeemerScript = Ledger.RedeemerScript (Ledger.lifted Collect)
range = collectionRange cmp
-- trying to do something like this, i.e. take all of the outputs and pay them to payeeWallet
utxos <- W.outputsAt (campaignAddress cmp)
W.payToPublicKey_ W.always utxos (EM.walletPubKey payeeWallet) ))
To preface - it appears the official example in the playground as well as the accompanying tutorial has changed. Still, since I spent some time obsessing over this it would still be nice if someone could explain the thought process behind this.
In the Plutus book, Chapter 10 (about the vesting scheme).
I can’t wrap my head around why redeemerScript1 is needed at all - no where in the book does it say that on-chain redeemers are applied to anything. Why define a redeemer that is being applied to a data script?