Skip to content

Instantly share code, notes, and snippets.

@txus
Last active July 16, 2020 14:10
Show Gist options
  • Save txus/518da7cf15cc9acf788f8f3afb547fc9 to your computer and use it in GitHub Desktop.
Save txus/518da7cf15cc9acf788f8f3afb547fc9 to your computer and use it in GitHub Desktop.
Plutus Playground Smart Contract (should adapt from https://gist.github.com/j-mueller/db9bb00b6b45fe7e475e75473c1e778b)
-- This is a starter contract, based on the Game contract,
-- containing the bare minimum required scaffolding.
--
-- What you should change to something more suitable for
-- your use case:
-- * The DataScript type
-- * The Redeemer type
--
-- And add function implementations (and rename them to
-- something suitable) for the endpoints:
-- * publish
-- * redeem
import qualified Language.PlutusTx as PlutusTx
import Language.PlutusTx.Prelude
import Ledger (Address, DataScript (DataScript), PendingTx, PubKey,
RedeemerScript (RedeemerScript), ValidatorScript (ValidatorScript),
applyScript, compileScript, scriptAddress, lifted, pendingTxValidRange)
import qualified Ledger.Interval as Interval
import Ledger.Value (Value)
import qualified Ledger.Validation as V
import Ledger.Slot (Slot, SlotRange)
import qualified Ledger.Ada as Ada
import Playground.Contract
import Wallet (MonadWallet, WalletAPI, WalletDiagnostics, collectFromScript, ownPubKey,
defaultSlotRange, payToScript_, startWatching, logMsg)
import qualified Wallet as W
import Wallet.Emulator (Wallet)
import qualified Wallet.Emulator as EM
data Commitment = Commitment
{ commitmentDeadline :: Slot
, commitmentWitnesses :: [PubKey]
, owner :: PubKey
} deriving (Generic, ToJSON, FromJSON, ToSchema)
PlutusTx.makeLift ''Commitment
mkCommitment :: Slot -> [Wallet] -> Wallet -> Commitment
mkCommitment ddl witnessWallets ownerWallet =
Commitment
{ commitmentDeadline = ddl
, commitmentWitnesses = fmap EM.walletPubKey witnessWallets
, owner = EM.walletPubKey ownerWallet
}
votingRange :: Commitment -> SlotRange
votingRange c =
W.intervalFrom (commitmentDeadline c)
data WitnessVote = Confirm | Deny
deriving (Generic, ToJSON, FromJSON, ToSchema)
PlutusTx.makeLift ''WitnessVote
type WitnessValidator = PubKey -> PendingTx -> Bool
validVote :: Commitment -> WitnessValidator
validVote commitment witness ptx =
-- Check that the commitment deadline is already due
Interval.contains (votingRange commitment) (pendingTxValidRange ptx)
-- check that the witness is actually part of the commitment
&& witness `elem` (commitmentWitnesses commitment)
-- Check that the vote is signed by the witness
&& (ptx `V.txSignedBy` witness)
votingScript :: Commitment -> ValidatorScript
votingScript c = ValidatorScript $
$$(Ledger.compileScript [|| validVote ||])
`Ledger.applyScript`
Ledger.lifted c
-- | The address of a [[Commitment]]
commitmentAddress :: Commitment -> Ledger.Address
commitmentAddress = Ledger.scriptAddress . votingScript
-- | Helper function used to build the DataScript.
mkDataScript :: Slot -> [Wallet] -> Wallet -> DataScript
mkDataScript ddl witnesses owner =
DataScript $ lifted $ mkCommitment ddl witnesses owner
-- | The "publish" contract endpoint.
publish :: MonadWallet m => Slot -> [Wallet] -> Wallet -> Value -> m ()
publish ddl witnessWallets ownerWallet lockedFunds =
payToScript_ defaultSlotRange (commitmentAddress $ mkCommitment ddl witnessWallets ownerWallet) lockedFunds (mkDataScript ddl witnessWallets ownerWallet)
contribute :: MonadWallet m => Slot -> [Wallet] -> Wallet -> WitnessVote -> m ()
contribute ddl witnessWallets ownerWallet vote = do
ownPK <- ownPubKey
let ds = DataScript $ Ledger.lifted ownPK
range = W.interval 1 ddl
payToScript_ range (commitmentAddress $ mkCommitment ddl witnessWallets ownerWallet) (Ada.adaValueOf 0) ds
logMsg "Submitted vote"
$(mkFunctions ['publish, 'contribute])
[0,[{"wallets":[{"simulatorWalletWallet":{"getWallet":1},"simulatorWalletBalance":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},10]]]]}},{"simulatorWalletWallet":{"getWallet":2},"simulatorWalletBalance":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},10]]]]}}],"signatures":[{"functionName":"publish","argumentSchema":[{"contents":[["getSlot",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaObject"},{"contents":[["getWallet",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaArray"},{"contents":[["getWallet",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaObject"},{"tag":"FormSchemaValue"}]},{"functionName":"contribute","argumentSchema":[{"contents":[["getSlot",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaObject"},{"contents":[["getWallet",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaArray"},{"contents":[["getWallet",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaObject"},{"contents":["Confirm","Deny"],"tag":"FormSchemaRadio"}]},{"functionName":"payToWallet_","argumentSchema":[{"tag":"FormSchemaValue"},{"contents":[["getWallet",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaObject"}]}],"currencies":[{"knownTokens":[{"unTokenName":""}],"hash":"","friendlyName":"Ada"}],"actions":[{"simulatorWallet":{"simulatorWalletWallet":{"getWallet":1},"simulatorWalletBalance":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},10]]]]}},"functionSchema":{"functionName":"publish","argumentSchema":[{"contents":[["getSlot",{"contents":2,"tag":"FormInt"}]],"tag":"FormObject"},{"contents":[{"contents":[["getWallet",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaObject"},[{"contents":[["getWallet",{"contents":2,"tag":"FormInt"}]],"tag":"FormObject"}]],"tag":"FormArray"},{"contents":[["getWallet",{"contents":1,"tag":"FormInt"}]],"tag":"FormObject"},{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},2]]]],"tag":"FormValue"}]},"tag":"Action"},{"blocks":2,"tag":"Wait"},{"simulatorWallet":{"simulatorWalletWallet":{"getWallet":2},"simulatorWalletBalance":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},10]]]]}},"functionSchema":{"functionName":"contribute","argumentSchema":[{"contents":[["getSlot",{"contents":2,"tag":"FormInt"}]],"tag":"FormObject"},{"contents":[{"contents":[["getWallet",{"tag":"FormSchemaInt"}]],"tag":"FormSchemaObject"},[{"contents":[["getWallet",{"contents":2,"tag":"FormInt"}]],"tag":"FormObject"}]],"tag":"FormArray"},{"contents":[["getWallet",{"contents":1,"tag":"FormInt"}]],"tag":"FormObject"},{"contents":[["Confirm","Deny"],"Confirm"],"tag":"FormRadio"}]},"tag":"Action"}]}]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment