├── .gitignore ├── assets ├── lock.datum ├── unlock.redeemer ├── contract.addr ├── .gitignore └── contract.plutus ├── .vscode ├── settings.json └── tasks.json ├── scripts ├── contract-balance.sh ├── download-params.sh ├── dev-wallet-balance.sh └── new-dev-wallet.sh ├── app └── Main.hs ├── src └── Hello │ ├── Utils.hs │ ├── Shared.hs │ └── Contract.hs ├── plutus-hello-world.cabal ├── cabal.project └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | dist-newstyle/ -------------------------------------------------------------------------------- /assets/lock.datum: -------------------------------------------------------------------------------- 1 | {"constructor":0,"fields":[{"int":42}]} 2 | -------------------------------------------------------------------------------- /assets/unlock.redeemer: -------------------------------------------------------------------------------- 1 | {"constructor":0,"fields":[{"int":21}]} 2 | -------------------------------------------------------------------------------- /assets/contract.addr: -------------------------------------------------------------------------------- 1 | addr_test1wqc4vg0vgkjzda49gy30rhk2plpgkm9aj7u6m7grmfsyx4qhsw06w -------------------------------------------------------------------------------- /assets/.gitignore: -------------------------------------------------------------------------------- 1 | *.skey 2 | *.vkey 3 | wallet1.addr 4 | *.tx 5 | *.tx-signed 6 | pparams.json -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "haskell.manageHLS": "PATH", 3 | "task.allowAutomaticTasks": "on" 4 | } -------------------------------------------------------------------------------- /scripts/contract-balance.sh: -------------------------------------------------------------------------------- 1 | cardano-cli query utxo --address $(cat assets/contract.addr) --testnet-magic $CARDANO_NODE_MAGIC -------------------------------------------------------------------------------- /scripts/download-params.sh: -------------------------------------------------------------------------------- 1 | here=$(dirname $0) 2 | 3 | cardano-cli query protocol-parameters --testnet-magic $CARDANO_NODE_MAGIC > ${here}/../assets/params.json 4 | -------------------------------------------------------------------------------- /scripts/dev-wallet-balance.sh: -------------------------------------------------------------------------------- 1 | here=$(dirname $0) 2 | 3 | cardano-cli query utxo \ 4 | --address $(cat ${here}/../assets/wallet1.addr) \ 5 | --testnet-magic $CARDANO_NODE_MAGIC 6 | -------------------------------------------------------------------------------- /assets/contract.plutus: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PlutusScriptV1", 3 | "description": "", 4 | "cborHex": "588b58890100003232322322322325335001100813263200833573892103505435000083232333573466e20008004488008488004cccd5cd19b8735573aa00a900011bad357426aae7940188c98c8024cd5ce0050048039999ab9a3370e6aae75400920002375a6ae84d55cf280191931900419ab9c0090080061375400226ea80052612001491035054310001" 5 | } 6 | -------------------------------------------------------------------------------- /scripts/new-dev-wallet.sh: -------------------------------------------------------------------------------- 1 | here=$(dirname $0) 2 | 3 | cardano-cli address key-gen \ 4 | --verification-key-file ${here}/../assets/wallet1.vkey \ 5 | --signing-key-file ${here}/../assets/wallet1.skey 6 | 7 | cardano-cli address build \ 8 | --payment-verification-key-file ${here}/../assets/wallet1.vkey \ 9 | --out-file ${here}/../assets/wallet1.addr \ 10 | --testnet-magic $CARDANO_NODE_MAGIC -------------------------------------------------------------------------------- /app/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Options.Applicative 4 | import qualified Hello.Utils as Utils 5 | 6 | type Opts = FilePath 7 | 8 | opts :: ParserInfo Opts 9 | opts = 10 | let parseOpts = argument str . mconcat $ [metavar "FILE", help "File to which the plutus script will be written"] 11 | in info (parseOpts <**> helper) . mconcat $ [fullDesc, progDesc "Create a smart contract for bulk purchases"] 12 | 13 | main :: IO () 14 | main = execParser opts >>= Utils.writePlutusFile 15 | -------------------------------------------------------------------------------- /src/Hello/Utils.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE LambdaCase #-} 3 | {-# LANGUAGE RankNTypes #-} 4 | {-# LANGUAGE ScopedTypeVariables #-} 5 | {-# LANGUAGE TypeFamilies #-} 6 | 7 | -- {-# LANGUAGE NoImplicitPrelude #-} 8 | 9 | module Hello.Utils (writePlutusFile, encodePlutusData) where 10 | 11 | import qualified Cardano.Api as Api 12 | -- Contracts 13 | import qualified Hello.Contract as Contract 14 | -- 15 | import PlutusTx.Prelude (Either (..), Maybe (Nothing), ($), (++), (>>=)) 16 | import System.FilePath ( FilePath ) 17 | import Prelude (IO, print, putStrLn) 18 | import Data.Aeson ( encode ) 19 | import Cardano.Api (scriptDataToJson, ScriptDataJsonSchema (..)) 20 | import Cardano.Api.Shelley (fromPlutusData) 21 | import PlutusTx (builtinDataToData, ToData (toBuiltinData)) 22 | import qualified Data.ByteString.Lazy as BSL 23 | 24 | writePlutusFile :: FilePath -> IO () 25 | writePlutusFile filePath = 26 | Api.writeFileTextEnvelope filePath Nothing Contract.serialized >>= \case 27 | Left err -> print $ Api.displayError err 28 | Right () -> putStrLn $ "wrote validator to file " ++ filePath 29 | 30 | encodePlutusData :: forall a. ToData a => a -> BSL.ByteString 31 | encodePlutusData a = Data.Aeson.encode $ scriptDataToJson ScriptDataJsonDetailedSchema $ fromPlutusData (builtinDataToData $ toBuiltinData a) 32 | -------------------------------------------------------------------------------- /src/Hello/Shared.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE RankNTypes #-} 3 | {-# LANGUAGE ScopedTypeVariables #-} 4 | {-# LANGUAGE TypeFamilies #-} 5 | {-# LANGUAGE NoImplicitPrelude #-} 6 | 7 | module Hello.Shared (wrap, validatorHash) where 8 | 9 | import qualified Cardano.Api.Shelley as Shelly 10 | import Codec.Serialise (serialise) 11 | import qualified Data.ByteString.Lazy as BSL 12 | import qualified Data.ByteString.Short as BSS 13 | import qualified Plutus.V1.Ledger.Scripts as Scripts 14 | import PlutusTx 15 | import PlutusTx.Prelude 16 | 17 | wrap :: 18 | forall a b c. 19 | ( UnsafeFromData a, 20 | UnsafeFromData b, 21 | UnsafeFromData c 22 | ) => 23 | (a -> b -> c -> Bool) -> 24 | BuiltinData -> 25 | BuiltinData -> 26 | BuiltinData -> 27 | () 28 | wrap f a b c = 29 | check 30 | ( f 31 | (unsafeFromBuiltinData a) 32 | (unsafeFromBuiltinData b) 33 | (unsafeFromBuiltinData c) 34 | ) 35 | 36 | validatorHash :: Scripts.Validator -> Scripts.ValidatorHash 37 | validatorHash = Scripts.ValidatorHash . Scripts.getScriptHash . scriptHash . Scripts.getValidator 38 | 39 | scriptHash :: Scripts.Script -> Scripts.ScriptHash 40 | scriptHash = 41 | Scripts.ScriptHash 42 | . toBuiltin 43 | . Shelly.serialiseToRawBytes 44 | . Shelly.hashScript 45 | . toCardanoApiScript 46 | 47 | toCardanoApiScript :: Scripts.Script -> Shelly.Script Shelly.PlutusScriptV2 48 | toCardanoApiScript = 49 | Shelly.PlutusScript Shelly.PlutusScriptV2 50 | . Shelly.PlutusScriptSerialised 51 | . BSS.toShort 52 | . BSL.toStrict 53 | . serialise -------------------------------------------------------------------------------- /src/Hello/Contract.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE BangPatterns #-} 2 | {-# LANGUAGE CPP #-} 3 | {-# LANGUAGE DataKinds #-} 4 | {-# LANGUAGE LambdaCase #-} 5 | {-# LANGUAGE NamedFieldPuns #-} 6 | {-# LANGUAGE RankNTypes #-} 7 | {-# LANGUAGE RecordWildCards #-} 8 | {-# LANGUAGE ScopedTypeVariables #-} 9 | {-# LANGUAGE TemplateHaskell #-} 10 | {-# LANGUAGE TypeApplications #-} 11 | {-# LANGUAGE TypeFamilies #-} 12 | {-# LANGUAGE NoImplicitPrelude #-} 13 | 14 | 15 | module Hello.Contract (validator, wrapped, serialized, hash, HelloDatum (..), HelloRedeemer (..)) where 16 | import Cardano.Api.Shelley (PlutusScript (PlutusScriptSerialised)) 17 | import Codec.Serialise (serialise) 18 | import qualified Data.ByteString.Lazy as BSL 19 | import qualified Data.ByteString.Short as BSS 20 | import Hello.Shared (validatorHash, wrap) 21 | import qualified Plutus.V2.Ledger.Api as PlutusV2 22 | import PlutusTx 23 | import PlutusTx.Prelude 24 | import Cardano.Api 25 | 26 | newtype HelloDatum = HelloDatum Integer 27 | PlutusTx.unstableMakeIsData ''HelloDatum 28 | 29 | newtype HelloRedeemer = HelloRedeemer Integer 30 | PlutusTx.unstableMakeIsData ''HelloRedeemer 31 | 32 | run :: HelloDatum -> HelloRedeemer -> PlutusV2.ScriptContext -> Bool 33 | run (HelloDatum datum) (HelloRedeemer redeemer) _ = redeemer < datum 34 | 35 | -- Entry 36 | 37 | wrapped :: BuiltinData -> BuiltinData -> BuiltinData -> () 38 | wrapped = wrap run 39 | 40 | validator :: PlutusV2.Validator 41 | validator = PlutusV2.mkValidatorScript $$(PlutusTx.compile [||wrapped||]) 42 | 43 | serialized :: PlutusScript PlutusScriptV2 44 | serialized = PlutusScriptSerialised . BSS.toShort . BSL.toStrict . serialise $ validator 45 | 46 | hash :: PlutusV2.ValidatorHash 47 | hash = validatorHash validator 48 | -------------------------------------------------------------------------------- /plutus-hello-world.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 2.4 2 | name: plutus-hello-world 3 | version: 0.1.0.0 4 | 5 | -- A short (one-line) description of the package. 6 | synopsis: Plutus Hello World 7 | 8 | -- A longer description of the package. 9 | description: A simple plutus starter template 10 | 11 | -- A URL where users can report bugs. 12 | -- bug-reports: 13 | 14 | -- The license under which the package is released. 15 | -- license: 16 | author: rvcas 17 | maintainer: x@rvcas.dev 18 | 19 | -- A copyright notice. 20 | -- copyright: 21 | -- category: 22 | extra-source-files: CHANGELOG.md 23 | 24 | flag defer-plugin-errors 25 | description: 26 | Defer errors from the plugin, useful for things like Haddock that can't handle it. 27 | default: False 28 | manual: True 29 | 30 | common lang 31 | default-language: Haskell2010 32 | build-depends: base ^>=4.14.3.0 33 | ghc-options: 34 | -Wall -fobject-code -fno-ignore-interface-pragmas 35 | -fno-omit-interface-pragmas -fno-strictness -fno-spec-constr 36 | -fno-specialise 37 | if flag(defer-plugin-errors) 38 | ghc-options: -fplugin-opt PlutusTx.Plugin:defer-errors 39 | 40 | library 41 | import: lang 42 | exposed-modules: 43 | Hello.Contract 44 | Hello.Shared 45 | Hello.Utils 46 | 47 | hs-source-dirs: src 48 | build-depends: 49 | , bytestring 50 | , cardano-api 51 | , filepath 52 | , plutus-core 53 | , plutus-ledger-api 54 | , plutus-tx 55 | , plutus-tx-plugin 56 | , serialise 57 | , aeson 58 | 59 | executable plutus-starter-kit 60 | import: lang 61 | main-is: Main.hs 62 | 63 | -- Modules included in this executable, other than Main. 64 | -- other-modules: 65 | 66 | -- LANGUAGE extensions used by modules in this package. 67 | -- other-extensions: 68 | hs-source-dirs: app 69 | default-language: Haskell2010 70 | ghc-options: -Wall -Werror -threaded -rtsopts -with-rtsopts=-T 71 | build-depends: 72 | , optparse-applicative 73 | , plutus-hello-world -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Cabal Update", 6 | "command": "cabal", 7 | "args": ["update"], 8 | "options": { 9 | "cwd": "${workspaceFolder}" 10 | }, 11 | "presentation": { 12 | "panel": "shared", 13 | "group": "cabal" 14 | } 15 | }, 16 | { 17 | "label": "Cabal Build", 18 | "command": "cabal", 19 | "args": ["build"], 20 | "options": { 21 | "cwd": "${workspaceFolder}" 22 | }, 23 | "runOptions": { 24 | "runOn": "folderOpen" 25 | }, 26 | "presentation": { 27 | "panel": "shared", 28 | "group": "cabal" 29 | }, 30 | "dependsOn": ["Cabal Update"] 31 | }, 32 | { 33 | "label": "Compile Contract", 34 | "command": "cabal", 35 | "args": ["run", "plutus-starter-kit", "--", "assets/contract.plutus"], 36 | "presentation": { 37 | "panel": "shared", 38 | "group": "cabal" 39 | }, 40 | "dependsOn": ["Cabal Build"] 41 | }, 42 | { 43 | "label": "Check Contract Balance", 44 | "command": ".vscode/contract-balance.sh", 45 | "presentation": { 46 | "panel": "shared", 47 | "group": "cabal" 48 | } 49 | }, 50 | { 51 | "label": "Check Dev Wallet Balance", 52 | "command": ".vscode/wallet1-balance.sh", 53 | "presentation": { 54 | "panel": "shared", 55 | "group": "cabal" 56 | } 57 | }, 58 | { 59 | "label": "New Dev Wallet", 60 | "command": ".vscode/new-dev-wallet.sh", 61 | "presentation": { 62 | "panel": "shared", 63 | "group": "cabal" 64 | } 65 | }, 66 | { 67 | "label": "Download Protocol Paramters", 68 | "command": ".vscode/download-params.sh", 69 | "presentation": { 70 | "panel": "shared", 71 | "group": "cabal", 72 | "revealProblems": "never" 73 | } 74 | } 75 | ] 76 | } -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | index-state: 2022-02-09T00:00:00Z 2 | 3 | with-compiler: ghc-8.10.7 4 | 5 | packages: 6 | ./ 7 | 8 | flags: -scrypt 9 | 10 | package cardano-crypto-praos 11 | flags: -external-libsodium-vrf 12 | 13 | package cardano-api 14 | ghc-options: -Werror 15 | 16 | package cardano-cli 17 | ghc-options: -Werror 18 | 19 | package cardano-git-rev 20 | ghc-options: -Werror 21 | 22 | package cardano-node 23 | ghc-options: -Werror 24 | 25 | package cardano-node-chairman 26 | ghc-options: -Werror 27 | 28 | package cardano-testnet 29 | ghc-options: -Werror 30 | 31 | package tx-generator 32 | ghc-options: -Werror 33 | 34 | package trace-dispatcher 35 | ghc-options: -Werror 36 | 37 | package trace-resources 38 | ghc-options: -Werror 39 | 40 | package cardano-tracer 41 | ghc-options: -Werror 42 | 43 | package cryptonite 44 | -- Using RDRAND instead of /dev/urandom as an entropy source for key 45 | -- generation is dubious. Set the flag so we use /dev/urandom by default. 46 | flags: -support_rdrand 47 | 48 | -- --------------------------------------------------------- 49 | -- Disable all tests by default 50 | 51 | tests: False 52 | 53 | test-show-details: direct 54 | 55 | -- Then enable specific tests in this repo 56 | 57 | package cardano-api 58 | tests: True 59 | 60 | package cardano-cli 61 | tests: True 62 | 63 | package cardano-node 64 | tests: True 65 | 66 | package cardano-node-chairman 67 | tests: True 68 | 69 | package cardano-submit-api 70 | tests: True 71 | 72 | package cardano-testnet 73 | tests: True 74 | 75 | package trace-resources 76 | tests: True 77 | 78 | package trace-dispatcher 79 | tests: True 80 | 81 | package trace-forward 82 | tests: True 83 | 84 | package cardano-tracer 85 | tests: True 86 | 87 | package trace-resources 88 | tests: True 89 | 90 | package locli 91 | tests: True 92 | 93 | -- The following is needed because Nix is doing something crazy. 94 | package byron-spec-ledger 95 | tests: False 96 | 97 | package vector-map 98 | ghc-options: -Werror 99 | 100 | package iohk-monitoring 101 | tests: False 102 | 103 | package ouroboros-consensus-test 104 | tests: False 105 | 106 | package ouroboros-consensus-cardano-test 107 | tests: False 108 | 109 | package ouroboros-network 110 | tests: False 111 | 112 | package ouroboros-network-framework 113 | tests: False 114 | 115 | package plutus-tx 116 | tests: False 117 | 118 | package prettyprinter-configurable 119 | tests: False 120 | 121 | package small-steps 122 | tests: False 123 | 124 | package small-steps-test 125 | tests: False 126 | 127 | package tx-generator 128 | tests: True 129 | 130 | package goblins 131 | tests: False 132 | 133 | package io-classes 134 | tests: False 135 | 136 | package cardano-ledger-alonzo-test 137 | tests: False 138 | 139 | package plutus-script-utils 140 | haddock-options: "--optghc=-fplugin-opt PlutusTx.Plugin:defer-errors" 141 | 142 | -- --------------------------------------------------------- 143 | 144 | -- The two following one-liners will cut off / restore the remainder of this file (for nix-shell users): 145 | -- when using the "cabal" wrapper script provided by nix-shell. 146 | -- --------------------------- 8< -------------------------- 147 | -- Please do not put any `source-repository-package` clause above this line. 148 | 149 | -- Using a fork until our patches can be merged upstream 150 | source-repository-package 151 | type: git 152 | location: https://github.com/input-output-hk/optparse-applicative 153 | tag: 7497a29cb998721a9068d5725d49461f2bba0e7a 154 | --sha256: 1gvsrg925vynwgqwplgjmp53vj953qyh3wbdf34pw21c8r47w35r 155 | 156 | source-repository-package 157 | type: git 158 | location: https://github.com/vshabanov/ekg-json 159 | tag: 00ebe7211c981686e65730b7144fbf5350462608 160 | --sha256: 1zvjm3pb38w0ijig5wk5mdkzcszpmlp5d4zxvks2jk1rkypi8gsm 161 | 162 | source-repository-package 163 | type: git 164 | location: https://github.com/input-output-hk/cardano-base 165 | tag: 0f3a867493059e650cda69e20a5cbf1ace289a57 166 | --sha256: 0p0az3sbkhb7njji8xxdrfb0yx2gc8fmrh872ffm8sfip1w29gg1 167 | subdir: 168 | base-deriving-via 169 | binary 170 | binary/test 171 | cardano-crypto-class 172 | cardano-crypto-praos 173 | cardano-crypto-tests 174 | measures 175 | orphans-deriving-via 176 | slotting 177 | strict-containers 178 | 179 | source-repository-package 180 | type: git 181 | location: https://github.com/input-output-hk/cardano-crypto 182 | tag: f73079303f663e028288f9f4a9e08bcca39a923e 183 | --sha256: 1n87i15x54s0cjkh3nsxs4r1x016cdw1fypwmr68936n3xxsjn6q 184 | 185 | source-repository-package 186 | type: git 187 | location: https://github.com/input-output-hk/cardano-ledger 188 | tag: 3be8a19083fc13d9261b1640e27dd389b51bb08e 189 | --sha256: 0dvm9l43mp1i34bcywmznd0660hhcfxwgawypk9q1hjkml1i41z3 190 | subdir: 191 | eras/alonzo/impl 192 | eras/alonzo/test-suite 193 | eras/babbage/impl 194 | eras/babbage/test-suite 195 | eras/byron/chain/executable-spec 196 | eras/byron/crypto 197 | eras/byron/crypto/test 198 | eras/byron/ledger/executable-spec 199 | eras/byron/ledger/impl 200 | eras/byron/ledger/impl/test 201 | eras/shelley/impl 202 | eras/shelley/test-suite 203 | eras/shelley-ma/impl 204 | eras/shelley-ma/test-suite 205 | libs/cardano-ledger-core 206 | libs/cardano-ledger-pretty 207 | libs/cardano-protocol-tpraos 208 | libs/cardano-data 209 | libs/vector-map 210 | libs/set-algebra 211 | libs/small-steps 212 | libs/small-steps-test 213 | libs/non-integral 214 | 215 | source-repository-package 216 | type: git 217 | location: https://github.com/input-output-hk/typed-protocols 218 | tag: 181601bc3d9e9d21a671ce01e0b481348b3ca104 219 | --sha256: 1lr97b2z7l0rpsmmz92rsv27qzd5vavz10cf7n25svya4kkiysp5 220 | subdir: 221 | typed-protocols 222 | typed-protocols-cborg 223 | typed-protocols-examples 224 | 225 | source-repository-package 226 | type: git 227 | location: https://github.com/input-output-hk/cardano-node 228 | tag: c75451f0ffd7a60b5ad6c4263891e6c8acac105a 229 | --sha256: 1z0zv1i58ikmbqg878f9z573jkwp4lzhmmswshm6c96rq6lprzh8 230 | subdir: 231 | cardano-api 232 | 233 | source-repository-package 234 | type: git 235 | location: https://github.com/input-output-hk/cardano-prelude 236 | tag: bb4ed71ba8e587f672d06edf9d2e376f4b055555 237 | --sha256: 00h10l5mmiza9819p9v5q5749nb9pzgi20vpzpy1d34zmh6gf1cj 238 | subdir: 239 | cardano-prelude 240 | cardano-prelude-test 241 | 242 | source-repository-package 243 | type: git 244 | location: https://github.com/input-output-hk/goblins 245 | tag: cde90a2b27f79187ca8310b6549331e59595e7ba 246 | --sha256: 17c88rbva3iw82yg9srlxjv2ia5wjb9cyqw44hik565f5v9svnyg 247 | 248 | source-repository-package 249 | type: git 250 | location: https://github.com/input-output-hk/iohk-monitoring-framework 251 | tag: 066f7002aac5a0efc20e49643fea45454f226caa 252 | --sha256: 0s6x4in11k5ba7nl7la896g28sznf9185xlqg9c604jqz58vj9nj 253 | subdir: 254 | contra-tracer 255 | iohk-monitoring 256 | plugins/backend-aggregation 257 | plugins/backend-ekg 258 | plugins/backend-monitoring 259 | plugins/backend-trace-forwarder 260 | plugins/scribe-systemd 261 | tracer-transformers 262 | 263 | source-repository-package 264 | type: git 265 | location: https://github.com/input-output-hk/Win32-network 266 | tag: 3825d3abf75f83f406c1f7161883c438dac7277d 267 | --sha256: 19wahfv726fa3mqajpqdqhnl9ica3xmf68i254q45iyjcpj1psqx 268 | 269 | source-repository-package 270 | type: git 271 | location: https://github.com/input-output-hk/ouroboros-network 272 | tag: a65c29b6a85e90d430c7f58d362b7eb097fd4949 273 | --sha256: 1fmab5hmi1y8lss97xh6hhikmyhsx9x31yhvg6zpr2kcq7kc6qkf 274 | subdir: 275 | monoidal-synchronisation 276 | network-mux 277 | ouroboros-consensus 278 | ouroboros-consensus-byron 279 | ouroboros-consensus-cardano 280 | ouroboros-consensus-protocol 281 | ouroboros-consensus-shelley 282 | ouroboros-network 283 | ouroboros-network-framework 284 | ouroboros-network-testing 285 | 286 | source-repository-package 287 | type: git 288 | location: https://github.com/input-output-hk/io-sim 289 | tag: f4183f274d88d0ad15817c7052df3a6a8b40e6dc 290 | --sha256: 0vb2pd9hl89v2y5hrhrsm69yx0jf98vppjmfncj2fraxr3p3lldw 291 | subdir: 292 | io-classes 293 | io-sim 294 | strict-stm 295 | 296 | source-repository-package 297 | type: git 298 | location: https://github.com/input-output-hk/plutus 299 | tag: f680ac6979e069fcc013e4389ee607ff5fa6672f 300 | --sha256: 180jq8hd0jlg48ya7b5yw3bnd2d5czy0b1agy9ng3mgnzpyq747i 301 | subdir: 302 | plutus-core 303 | plutus-ledger-api 304 | plutus-tx 305 | plutus-tx-plugin 306 | prettyprinter-configurable 307 | stubs/plutus-ghc-stub 308 | word-array 309 | 310 | source-repository-package 311 | type: git 312 | location: https://github.com/well-typed/plutonomy.git 313 | tag: 6c01302ba8cf3be4f71617e106cd5ef7ed10fc63 314 | 315 | package plutonomy 316 | flags: +plutus-f680ac697 317 | 318 | source-repository-package 319 | type: git 320 | location: https://github.com/input-output-hk/flat 321 | tag: ee59880f47ab835dbd73bea0847dab7869fc20d8 322 | --sha256: 1lrzknw765pz2j97nvv9ip3l1mcpf2zr4n56hwlz0rk7wq7ls4cm 323 | 324 | constraints: 325 | hedgehog >= 1.0 326 | , bimap >= 0.4.0 327 | , libsystemd-journal >= 1.4.4 328 | , systemd >= 2.3.0 329 | -- systemd-2.3.0 requires at least network 3.1.1.0 but it doesn't declare 330 | -- that dependency 331 | , network >= 3.1.1.0 332 | , HSOpenSSL >= 0.11.7.2 333 | , algebraic-graphs < 0.7 334 | , protolude < 0.3.1 335 | 336 | package snap-server 337 | flags: +openssl 338 | 339 | package comonad 340 | flags: -test-doctests 341 | 342 | package cardano-ledger-alonzo-test 343 | tests: False 344 | 345 | allow-newer: 346 | *:aeson, 347 | monoidal-containers:aeson, 348 | monoidal-containers:semialign, 349 | ouroboros-consensus:semialign, 350 | size-based:template-haskell -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plutus Hello World 2 | 3 | This is a bare bones Plutus smart-contract template. The goal is to provide the minimum expression of a Plutus project to be used as starting point to build more complex contracts. 4 | 5 | ## Dev Environment 6 | 7 | To build the script you'll need the Haskell toolchain (GCH, Cabal, etc) and several dependencies from IOHK repositories. There's also a requirement on the [secp256k1](https://github.com/bitcoin-core/secp256k1.git) library. Once you've compiled the source code into a Plutus script, you'll need a fully-synced Cardano Node and the `cardano-cli` binary in order to submit example transactions to the Blockchain. 8 | 9 | If you don't want to install the required components yourself, you can use [Demeter.run](https://demeter.run) platform to create a cloud environment with access to common Cardano infrastrcuture. The following command will open this repo in a private, web-based VSCode IDE with all of the required Haskell toolchain, access to a shared Cardano Node and a pre-installed binary of the `cardano-cli`. 10 | 11 | [![Code in Cardano Workspace](https://demeter.run/code/badge.svg)](https://demeter.run/code?repository=https://github.com/txpipe/plutus-starter-kit.git&template=plutus) 12 | 13 | ## Quick Start 14 | 15 | > **Note** 16 | > This guide assumes that you're using a Cardano Workspace as detailed above. 17 | 18 | ### Compile the Validator 19 | 20 | The source code for the Plutus contract lives in the `src/Hello` folder. The `Contracts.hs` contains a minimalistic validator logic and the required boilerplate code to serialize the Plutus-Tx code as UPLC that can be submitted on-chain. 21 | 22 | The entry point for the Cabal project lives in `Main.hs` and can be used to trigger the serialization. Run the following command from the workspace terminal: 23 | 24 | ```sh 25 | cabal run plutus-starter-kit -- assets/contract.plutus 26 | ``` 27 | 28 | > **Note** 29 | > The _Cardano Workspace_ provides a cached version of the Cardano api dependencies. This greatly accelerates the build process. 30 | 31 | When the command finishes, you should get a `assets/contract.plutus` file that contains a JSON envelope of the UPLC code. This file can be used to submit transactions on-chain. 32 | 33 | ```json 34 | { 35 | "type": "PlutusScriptV2", 36 | "description": "", 37 | "cborHex": "5907c35907c001000..." 38 | } 39 | ``` 40 | 41 | To construct on-chain transactions, we'll need the address of the script we've just compiled. For this, run the following command: 42 | 43 | ```sh 44 | cardano-cli address build \ 45 | --payment-script-file ./assets/contract.plutus \ 46 | --testnet-magic ${CARDANO_NODE_MAGIC} \ 47 | --out-file ./assets/contract.addr 48 | ``` 49 | 50 | > **Note** 51 | > The `CARDANO_NODE_MAGIC` env variable is set automatically by the Cardano Workspace. 52 | 53 | If you want to query the balance of your script address, we added a helper script that queries the UTxO for the address generated in the previous step. Open your Cardano Workspace terminal and run the following command: 54 | 55 | ```sh 56 | ./scripts/contract-balance.sh 57 | ``` 58 | 59 | > **Note** 60 | > Querying the node for UTxO is not part of the scope for this Starter Kit. If you want to learn more about common operations through the CLI, try out the [Cardano-CLI Starter Kit](https://github.com/txpipe/cardano-cli-starter-kit) 61 | 62 | ### Prepare a Dev Wallet 63 | 64 | To interact with our contract on-chain, we'll need a wallet with some tAda (test ADA). Open your Cardano Workspace terminal and excute the following command: 65 | 66 | ```sh 67 | ./scripts/new-dev-wallet.sh 68 | ``` 69 | 70 | > **Note** 71 | > Creating wallet keys is not part of the scope for this Starter Kit. If you want to learn more about common operations through the CLI, try out the [Cardano-CLI Starter Kit](https://github.com/txpipe/cardano-cli-starter-kit) 72 | 73 | When done, you should see new files inside the `assets` directory that contain the key pairs and address for your newly created wallet. 74 | 75 | If you want to query the balance of your wallet address, you can use a helper script that queries the UTxO for the address generated in the previous step. Open your Cardano Workspace terminal and run the following command: 76 | 77 | ```sh 78 | ./scripts/dev-wallet-balance.sh 79 | ``` 80 | 81 | > **Note** 82 | > Querying the node for UTxO is not part of the scope for this Starter Kit. If you want to learn more about common operations through the CLI, try out the [Cardano-CLI Starter Kit](https://github.com/txpipe/cardano-cli-starter-kit) 83 | 84 | Your wallet we'll need some funds to interact with the contract. You can use the corresponding [faucet](https://docs.cardano.org/cardano-testnet/tools/faucet) to obtain some. 85 | 86 | ### Lock Funds 87 | 88 | Now that we have a validator script ready, we'll lock funds on the script address. Locking funds is just a fancy way of saying that we'll send some assests (ADA in this case) to the script by submitting a transaction to the corresponding address. It is called "locking" because the funds can only be retrieved if the validator script allows it. 89 | 90 | Our very basic validator has one simple task: to ensure that the integer value in the datum is greater or equal than the integer value in the redeemer (quite dumb and useless). 91 | 92 | Our datum is defined as a Haskell newtype that wraps a single integer. The `src/Hello/Contract.hs` contains the correponding code: 93 | 94 | ```haskell 95 | newtype HelloDatum = HelloDatum Integer 96 | ``` 97 | 98 | When locking the funds, the submitting party is the one in control of the datum and needs to specify the hash of the value. For that, we need a JSON representation of the datum to be passed to the cardano-cli in order to obtain the hash. The file `assets/lock.datum` contains an example of the JSON representation for a datum that holds the value `42`: 99 | 100 | ```json 101 | {"constructor":0,"fields":[{"int":42}]} 102 | ``` 103 | 104 | From inside your Cardano Workspace, open a terminal and execute the following command to generate a hash for data contained in the `assets/lock.datum` file. The result of the cardano-cli command will be stored in the `scriptdatumhash` variable. 105 | 106 | ```sh 107 | scriptdatumhash=$(cardano-cli transaction hash-script-data --script-data-file assets/lock.datum) 108 | ``` 109 | 110 | The locking transaction needs a reference to a UTxO in your dev wallet to be used as source for the funds we'll be locking in the script. Since this step is specific to the state of your wallet, you'll need to manually assign the value in a shell variable for the next step to succeed. 111 | 112 | Use the `dev-wallet-balance.sh` to check your available UTxO and select the one to be used in our test transaction. Assign the `{TxHash}#{TxIn}` to the `locktxin` shell variable. We'll be locking a small amount of tADA (1230000 lovelace), make sure that your UTxO has enough. The following is just an example, replace accordingly: 113 | 114 | ```sh 115 | $ ./scripts/dev-wallet-balance.sh 116 | 117 | TxHash TxIx Amount 118 | --------------------------------------------------------------------------------- 119 | 0939be18d8583bbdd7309b4cfefd419c8900df0f84142149066ec2755c94a322 0 9980637126 lovelace 120 | 9805cc2d7c08f8b99acd2d60d9cf1e3eb14b281e7f3f430f26a26f0927ff5fde 0 1060942 lovelace 121 | 9ec2a9a546d8a9c7221be452e26278d2128cb39429d57a58b420598c0e9c2591 0 1060678 lovelace 122 | 123 | $ locktxin=0939be18d8583bbdd7309b4cfefd419c8900df0f84142149066ec2755c94a322#0 124 | ``` 125 | 126 | We also need to retrieve some Protocol Parameters before building the transaction, in order to do so, execute the following script helper: 127 | 128 | ```sh 129 | $ ./scripts/download-params.sh 130 | ``` 131 | 132 | Now we are finally ready to build the locking transaction. From inside your Cardano Workspace, open a terminal and execute the following command to build the unsigned Tx payload. 133 | 134 | ```sh 135 | cardano-cli transaction build \ 136 | --babbage-era \ 137 | --testnet-magic ${CARDANO_NODE_MAGIC} \ 138 | --change-address $(cat assets/wallet1.addr) \ 139 | --tx-in ${locktxin} \ 140 | --tx-out $(cat assets/contract.addr)+1230000 \ 141 | --tx-out-datum-hash ${scriptdatumhash} \ 142 | --protocol-params-file assets/params.json \ 143 | --out-file assets/lock.tx 144 | ``` 145 | 146 | > **Note** 147 | > The `CARDANO_NODE_MAGIC` env variable is set automatically by the Cardano Workspace. 148 | 149 | The next step consists of signing the transaction with our dev wallet key. From inside your Cardano Workspace, open a terminal and execute the following command: 150 | 151 | ```sh 152 | cardano-cli transaction sign \ 153 | --tx-body-file assets/lock.tx \ 154 | --signing-key-file assets/wallet1.skey \ 155 | --testnet-magic ${CARDANO_NODE_MAGIC} \ 156 | --out-file assets/lock.tx-signed 157 | ``` 158 | 159 | The only remaining task is to submit the signed transaction on-chain. From inside your Cardano Workspace, open a terminal and execute the following command: 160 | 161 | ```sh 162 | cardano-cli transaction submit \ 163 | --testnet-magic ${CARDANO_NODE_MAGIC} \ 164 | --tx-file assets/lock.tx-signed 165 | ``` 166 | 167 | After a few seconds (might be longer depending on chain activity), the balance for the script address should show our locked funds. Check the UTxO of the script address using our helper script: 168 | 169 | ```sh 170 | ./scripts/contract-balance.sh 171 | ``` 172 | 173 | The output of the script should show something similar to the following: 174 | 175 | ```sh 176 | TxHash TxIx Amount 177 | -------------------------------------------------------------------------------------- 178 | b00...313 1 1230000 lovelace + TxOutDatumHash ScriptDataInBabbageEra "923...4ec" 179 | ``` 180 | 181 | # Unlock Funds 182 | 183 | To unlock the assets, we need to prepare a transaction that consumes the UTxO from the contract address and including a redeemer that complies with the contraints defined by our validator. 184 | 185 | Query the contract balance once more, take the TxHash and TxIx and store it inside the variable `lockedtxin`. 186 | 187 | ```sh 188 | $ ./scripts/contract-balance.sh 189 | TxHash TxIx Amount 190 | -------------------------------------------------------------------------------------- 191 | 8af...ee4 0 1230000 lovelace + TxOutDatumHash ScriptDataInBabbageEra "923...4ec" 192 | 193 | $ lockedtxin=8afb82a260fc3c0fd4e5828da171b4ae52144669c2ec915df846cff6a628dee4#0 194 | ``` 195 | 196 | We also need to specify some collateral UTxO that the protocol can use in case our validator fails. For this, query the balance of your wallet again, select an available UTxO and store it in the variable `collateraltxin`. 197 | 198 | ```sh 199 | $ ./scripts/dev-wallet-balance.sh 200 | 201 | TxHash TxIx Amount 202 | --------------------------------------------------------------------------------- 203 | 0939be18d8583bbdd7309b4cfefd419c8900df0f84142149066ec2755c94a322 0 9980637126 lovelace 204 | 9805cc2d7c08f8b99acd2d60d9cf1e3eb14b281e7f3f430f26a26f0927ff5fde 0 1060942 lovelace 205 | 9ec2a9a546d8a9c7221be452e26278d2128cb39429d57a58b420598c0e9c2591 0 1060678 lovelace 206 | 207 | $ collateraltxin=0939be18d8583bbdd7309b4cfefd419c8900df0f84142149066ec2755c94a322#0 208 | ``` 209 | 210 | ```sh 211 | cardano-cli transaction build \ 212 | --babbage-era \ 213 | --testnet-magic ${CARDANO_NODE_MAGIC} \ 214 | --tx-in ${lockedtxin} \ 215 | --tx-in-script-file assets/contract.plutus \ 216 | --tx-in-datum-file assets/lock.datum \ 217 | --tx-in-redeemer-file assets/unlock.redeemer \ 218 | --change-address $(cat assets/wallet1.addr) \ 219 | --tx-in-collateral ${collateraltxin} \ 220 | --protocol-params-file assets/params.json \ 221 | --out-file assets/unlock.tx 222 | ``` 223 | 224 | As usual, the next step consists of signing the transaction with our dev wallet key. From inside your Cardano Workspace, open a terminal and execute the following command: 225 | 226 | ```sh 227 | cardano-cli transaction sign \ 228 | --tx-body-file assets/unlock.tx \ 229 | --signing-key-file assets/wallet1.skey \ 230 | --testnet-magic ${CARDANO_NODE_MAGIC} \ 231 | --out-file assets/unlock.tx-signed 232 | ``` 233 | 234 | Now we need to submit the signed transaction on-chain. From inside your Cardano Workspace, open a terminal and execute the following command: 235 | 236 | ```sh 237 | cardano-cli transaction submit --testnet-magic ${CARDANO_NODE_MAGIC} --tx-file assets/unlock.tx-signed 238 | ``` 239 | 240 | After a few seconds, assuming that the submission was successful, you should see the unlocked assets back in your dev wallet. Use the following command to check your wallet balance. You should see the new UTxO. 241 | 242 | ```sh 243 | ./scripts/dev-wallet-balance.sh 244 | ``` --------------------------------------------------------------------------------