├── src └── MyModule.hs ├── hie.yaml ├── .gitignore ├── nix ├── sources.json ├── default.nix ├── pkgs │ ├── default.nix │ └── haskell │ │ ├── default.nix │ │ ├── haskell.nix │ │ └── sha256map.nix ├── lib │ └── ci.nix └── sources.nix ├── examples ├── test │ ├── Spec.hs │ └── Spec │ │ ├── game.pir │ │ └── Game.hs └── src │ └── Plutus │ └── Contracts │ └── Game.hs ├── shell.nix ├── .devcontainer └── devcontainer.json ├── default.nix ├── CONTRIBUTING.md ├── .github └── workflows │ └── test.yml ├── scripts └── test ├── plutus-starter.cabal ├── release.nix ├── pab └── Main.hs ├── README.md ├── cabal.project └── LICENSE /src/MyModule.hs: -------------------------------------------------------------------------------- 1 | module MyModule where 2 | 3 | hello :: String 4 | hello = "hello" 5 | 6 | main :: IO () 7 | main = putStrLn hello -------------------------------------------------------------------------------- /hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | cabal: 3 | - path: "./src" 4 | component: "plutus-starter:lib:plutus-starter" 5 | - path: "./examples/src" 6 | component: "plutus-starter:lib:plutus-starter" 7 | - path: "./examples/test" 8 | component: "plutus-starter:test:plutus-example-projects-test" 9 | - path: "./pab" 10 | component: "plutus-starter:exe:plutus-starter-pab" 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | dist-* 3 | cabal-dev 4 | *.o 5 | *.hi 6 | *.hie 7 | *.chi 8 | *.chs.h 9 | *.dyn_o 10 | *.dyn_hi 11 | .hpc 12 | .hsenv 13 | .cabal-sandbox/ 14 | cabal.sandbox.config 15 | *.prof 16 | *.aux 17 | *.hp 18 | *.eventlog 19 | .stack-work/ 20 | cabal.project.local 21 | cabal.project.local~ 22 | .HTF/ 23 | .ghc.environment.* 24 | result* 25 | .envrc 26 | .vim 27 | scripts/wallet 28 | status.json -------------------------------------------------------------------------------- /nix/sources.json: -------------------------------------------------------------------------------- 1 | { 2 | "plutus-apps": { 3 | "branch": "v0.1.0", 4 | "description": "The Plutus Application Platform", 5 | "homepage": "", 6 | "owner": "input-output-hk", 7 | "repo": "plutus-apps", 8 | "rev": "v0.1.0", 9 | "sha256": "1pcxv8l4rgwi0sa3ygq1ag1hyxj61rh03ij5mws78hax09p16vl4", 10 | "type": "tarball", 11 | "url": "https://github.com/input-output-hk/plutus-apps/archive/v0.1.0.tar.gz", 12 | "url_template": "https://github.com///archive/.tar.gz" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/test/Spec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module Main(main) where 3 | 4 | import qualified Spec.Game 5 | import Test.Tasty 6 | import Test.Tasty.Hedgehog (HedgehogTestLimit (..)) 7 | 8 | main :: IO () 9 | main = defaultMain tests 10 | 11 | -- | Number of successful tests for each hedgehog property. 12 | -- The default is 100 but we use a smaller number here in order to speed up 13 | -- the test suite. 14 | -- 15 | limit :: HedgehogTestLimit 16 | limit = HedgehogTestLimit (Just 5) 17 | 18 | tests :: TestTree 19 | tests = localOption limit $ testGroup "use cases" [ 20 | Spec.Game.tests 21 | ] 22 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pure ? false, source-repo-override ? { } }: 2 | let 3 | packages = import ./. { inherit source-repo-override; }; 4 | inherit (packages) pkgs plutus-starter project; 5 | 6 | in 7 | project.shellFor { 8 | withHoogle = false; 9 | 10 | nativeBuildInputs = with plutus-starter; [ 11 | hlint 12 | cabal-install 13 | haskell-language-server 14 | stylish-haskell 15 | pkgs.niv 16 | cardano-repo-tool 17 | pkgs.ghcid 18 | # HACK: This shouldn't need to be here. 19 | pkgs.lzma.dev 20 | ] ++ (pkgs.lib.optionals pure [ 21 | pkgs.git 22 | pkgs.cacert 23 | pkgs.curl 24 | pkgs.jq 25 | ]); 26 | } 27 | -------------------------------------------------------------------------------- /nix/default.nix: -------------------------------------------------------------------------------- 1 | { source-repo-override }: 2 | let 3 | # Pratically, the only needed dependency is the plutus repository. 4 | sources = import ./sources.nix { inherit pkgs; }; 5 | 6 | # We're going to get everything from the main plutus repository. This ensures 7 | # we're using the same version of multiple dependencies such as nipxkgs, 8 | # haskell-nix, cabal-install, compiler-nix-name, etc. 9 | plutus = import sources.plutus-apps {}; 10 | pkgs = plutus.pkgs; 11 | 12 | haskell-nix = pkgs.haskell-nix; 13 | 14 | plutus-starter = import ./pkgs { 15 | inherit pkgs haskell-nix sources plutus source-repo-override; 16 | }; 17 | 18 | in 19 | { 20 | inherit pkgs plutus-starter; 21 | } 22 | -------------------------------------------------------------------------------- /examples/test/Spec/game.pir: -------------------------------------------------------------------------------- 1 | (program 2 | (let 3 | (nonrec) 4 | (typebind (tyvardecl ScriptContext (type)) (all a (type) (fun a a))) 5 | (datatypebind 6 | (datatype 7 | (tyvardecl Bool (type)) 8 | 9 | Bool_match 10 | (vardecl True Bool) (vardecl False Bool) 11 | ) 12 | ) 13 | (lam 14 | hs 15 | (con bytestring) 16 | (lam 17 | cs 18 | (con bytestring) 19 | (lam 20 | ds 21 | ScriptContext 22 | [ 23 | [ 24 | [ 25 | { (builtin ifThenElse) Bool } 26 | [ [ (builtin equalsByteString) hs ] [ (builtin sha2_256) cs ] ] 27 | ] 28 | True 29 | ] 30 | False 31 | ] 32 | ) 33 | ) 34 | ) 35 | ) 36 | ) -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Plutus Starter Project", 3 | "image": "docker.io/inputoutput/plutus-starter-devcontainer:v0.1.0", 4 | 5 | "remoteUser": "plutus", 6 | 7 | "mounts": [ 8 | // This shares cabal's remote repository state with the host. We don't mount the whole of '.cabal', because 9 | // 1. '.cabal/config' contains absolute paths that will only make sense on the host, and 10 | // 2. '.cabal/store' is not necessarily portable to different version of cabal etc. 11 | "source=${localEnv:HOME}/.cabal/packages,target=/home/plutus/.cabal/packages,type=bind,consistency=cached", 12 | ], 13 | 14 | "settings": { 15 | // Note: don't change from bash so it runs .bashrc 16 | "terminal.integrated.shell.linux": "/bin/bash" 17 | }, 18 | 19 | // IDs of extensions inside container 20 | "extensions": [ 21 | "haskell.haskell" 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /nix/pkgs/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs 2 | , sources 3 | , plutus 4 | , haskell-nix 5 | , source-repo-override 6 | }: 7 | let 8 | gitignore-nix = pkgs.callPackage plutus."gitignore.nix" { }; 9 | 10 | compiler-nix-name = plutus.plutus-apps.haskell.compiler-nix-name; 11 | 12 | haskell = pkgs.callPackage ./haskell { 13 | inherit gitignore-nix sources haskell-nix source-repo-override; 14 | inherit compiler-nix-name; # Use the same GHC version as plutus 15 | inherit (pkgs) libsodium-vrf; 16 | }; 17 | 18 | hlint = plutus.plutus-apps.hlint; 19 | 20 | cabal-install = plutus.plutus-apps.cabal-install; 21 | 22 | stylish-haskell = plutus.plutus-apps.stylish-haskell; 23 | 24 | haskell-language-server = plutus.plutus-apps.haskell-language-server; 25 | 26 | cardano-repo-tool = plutus.plutus-apps.cardano-repo-tool; 27 | in 28 | { 29 | inherit haskell hlint cabal-install stylish-haskell haskell-language-server cardano-repo-tool; 30 | } 31 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { source-repo-override ? { } }: 2 | ######################################################################## 3 | # default.nix -- The top-level nix build file for plutus-starter. 4 | # 5 | # This file defines various attributes that are used for building and 6 | # developing plutus-starter. 7 | # 8 | ######################################################################## 9 | 10 | let 11 | # Here a some of the various attributes for the variable 'packages': 12 | # 13 | # { pkgs 14 | # plutus-starter: { 15 | # haskell: { 16 | # project # The Haskell project created by haskell-nix.project 17 | # packages # All the packages defined by our project, including dependencies 18 | # projectPackages # Just the packages in the project 19 | # } 20 | # hlint 21 | # cabal-install 22 | # stylish-haskell 23 | # haskell-language-server 24 | # } 25 | # } 26 | packages = import ./nix { inherit source-repo-override; }; 27 | 28 | inherit (packages) pkgs plutus-starter; 29 | project = plutus-starter.haskell.project; 30 | in 31 | { 32 | inherit pkgs plutus-starter; 33 | 34 | inherit project; 35 | } 36 | -------------------------------------------------------------------------------- /nix/pkgs/haskell/default.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , haskell-nix 3 | , gitignore-nix 4 | , sources 5 | , compiler-nix-name 6 | , libsodium-vrf 7 | , source-repo-override 8 | }: 9 | let 10 | # The Hackage index-state from cabal.project 11 | index-state = 12 | let 13 | parseIndexState = rawCabalProject: 14 | let 15 | indexState = lib.lists.concatLists ( 16 | lib.lists.filter (l: l != null) 17 | (map (l: builtins.match "^index-state: *(.*)" l) 18 | (lib.splitString "\n" rawCabalProject))); 19 | in 20 | lib.lists.head (indexState ++ [ null ]); 21 | in 22 | parseIndexState (builtins.readFile ../../../cabal.project); 23 | 24 | # The haskell project created by haskell-nix.cabalProject' 25 | project = import ./haskell.nix { 26 | inherit lib haskell-nix compiler-nix-name gitignore-nix libsodium-vrf source-repo-override; 27 | }; 28 | 29 | # All the packages defined by our project, including dependencies 30 | packages = project.hsPkgs; 31 | 32 | # Just the packages in the project 33 | projectPackages = haskell-nix.haskellLib.selectProjectPackages packages; 34 | in 35 | rec { 36 | inherit project projectPackages packages; 37 | } 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## How to update dependencies 4 | 5 | 1. Go to https://github.com/input-output-hk/plutus-apps/tags and take note of the latest `v.X.Y.Z` tag. 6 | 2. Update the tag and/or hash in the following files: 7 | - `.devcontainer/devcontainer.json` 8 | - `nix/sources.json` 9 | - `nix/pkgs/haskell/sha256map.nix` 10 | - `cabal.project` 11 | 3. Copy over most of https://github.com/input-output-hk/plutus-apps/blob/main/cabal.project into `cabal.project` 12 | 4. Copy over the `sha256map` values from https://github.com/input-output-hk/plutus-apps/blob/main/nix/pkgs/haskell/sha256map.nix into `nix/pkgs/haskell/sha256map.nix` (but leave the first line that you just changed in step 2). To get the right hash value for `plutus-apps`, change one digit, then run `nix-shell`. You will get an error that shows the correct hash. 13 | 5. It’s likely that the code for the guessing game needs to be changed; luckily, you can copy the source from https://github.com/input-output-hk/plutus-apps/blob/main/plutus-playground-server/usecases/Game.hs roughly, and it should work. 14 | 6. Test the different parts: 15 | - VSCode 16 | * You need to make sure to rebuild the image 17 | * Then, once in VSCode, do `cabal build` and `cabal test`, and then make sure HLS works 18 | - nix 19 | * `nix-shell` 20 | * `cabal build`/`cabal test` 21 | -------------------------------------------------------------------------------- /nix/pkgs/haskell/haskell.nix: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Builds Haskell packages with Haskell.nix 3 | ############################################################################ 4 | { haskell-nix 5 | , gitignore-nix 6 | , compiler-nix-name 7 | , lib 8 | , libsodium-vrf 9 | , source-repo-override 10 | }: 11 | 12 | let 13 | project = haskell-nix.project { 14 | # 'cleanGit' cleans a source directory based on the files known by git 15 | src = haskell-nix.haskellLib.cleanGit { 16 | name = "plutus-starter"; 17 | src = ../../../.; 18 | }; 19 | 20 | inherit compiler-nix-name; 21 | 22 | # If using materialization, be sure to disable it when source-repo-override is set or it won't take effect. 23 | 24 | sha256map = import ./sha256map.nix; 25 | 26 | modules = [ 27 | { 28 | packages = { 29 | # Broken due to haddock errors. Refer to https://github.com/input-output-hk/plutus/blob/master/nix/pkgs/haskell/haskell.nix 30 | plutus-ledger.doHaddock = false; 31 | plutus-use-cases.doHaddock = false; 32 | 33 | # See https://github.com/input-output-hk/iohk-nix/pull/488 34 | cardano-crypto-praos.components.library.pkgconfig = lib.mkForce [ [ libsodium-vrf ] ]; 35 | cardano-crypto-class.components.library.pkgconfig = lib.mkForce [ [ libsodium-vrf ] ]; 36 | }; 37 | } 38 | ]; 39 | 40 | inherit source-repo-override; 41 | }; 42 | in 43 | project 44 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "Tests" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | jobs: 8 | nix-build: 9 | strategy: 10 | matrix: 11 | os: [ubuntu-latest] 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - uses: actions/checkout@v2.3.4 15 | - uses: nixbuild/nix-quick-install-action@v9 16 | with: 17 | nix_conf: | 18 | allowed-uris = https://github.com/NixOS/nixpkgs https://github.com/input-output-hk https://github.com/NixOS/nixpkgs-channels 19 | trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= iohk.cachix.org-1:DpRUyj7h7V830dp/i6Nti+NEO2/nhblbov/8MW7Rqoo= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 20 | substituters = https://hydra.iohk.io https://iohk.cachix.org https://cache.nixos.org/ 21 | - run: nix-build release.nix --restrict-eval -I . -A required --no-out-link 22 | 23 | guessing-game: 24 | strategy: 25 | matrix: 26 | os: [ubuntu-latest] 27 | runs-on: ${{ matrix.os }} 28 | steps: 29 | - uses: actions/checkout@v2.3.4 30 | - uses: nixbuild/nix-quick-install-action@v9 31 | with: 32 | nix_conf: | 33 | allowed-uris = https://github.com/NixOS/nixpkgs https://github.com/input-output-hk https://github.com/NixOS/nixpkgs-channels 34 | trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= iohk.cachix.org-1:DpRUyj7h7V830dp/i6Nti+NEO2/nhblbov/8MW7Rqoo= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 35 | substituters = https://hydra.iohk.io https://iohk.cachix.org https://cache.nixos.org/ 36 | - run: ./scripts/test 37 | -------------------------------------------------------------------------------- /examples/test/Spec/Game.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE TemplateHaskell #-} 3 | {-# LANGUAGE TypeApplications #-} 4 | {-# LANGUAGE NumericUnderscores #-} 5 | {-# LANGUAGE OverloadedStrings #-} 6 | 7 | module Spec.Game 8 | ( tests 9 | ) where 10 | 11 | import Control.Monad (void) 12 | import qualified Ledger.Ada as Ada 13 | import Plutus.Contract (Contract, ContractError) 14 | import Plutus.Contract.Test 15 | import Plutus.Contracts.Game 16 | import Plutus.Trace.Emulator (ContractInstanceTag) 17 | import qualified Plutus.Trace.Emulator as Trace 18 | import qualified PlutusTx 19 | import Test.Tasty 20 | import qualified Test.Tasty.HUnit as HUnit 21 | import Prelude 22 | 23 | t1, t2 :: ContractInstanceTag 24 | t1 = Trace.walletInstanceTag w1 25 | t2 = Trace.walletInstanceTag w2 26 | 27 | theContract :: Contract () GameSchema ContractError () 28 | theContract = game 29 | 30 | -- W1 locks funds, W2 (and other wallets) should have access to guess endpoint 31 | -- No funds locked, so W2 (and other wallets) should not have access to guess endpoint 32 | tests :: TestTree 33 | tests = testGroup "game" 34 | [ checkPredicate "Expose 'lock' endpoint, and 'guess' endpoint" 35 | (endpointAvailable @"lock" theContract t1 36 | .&&. (endpointAvailable @"guess" theContract t1)) 37 | $ void $ Trace.activateContractWallet w1 (lock @ContractError) 38 | 39 | , checkPredicate "'lock' endpoint submits a transaction" 40 | (anyTx theContract t1) 41 | $ do 42 | hdl <- Trace.activateContractWallet w1 theContract 43 | Trace.callEndpoint @"lock" hdl (LockParams "secret" (Ada.adaValueOf 10)) 44 | 45 | , checkPredicate "'guess' endpoint is available after locking funds" 46 | (endpointAvailable @"guess" theContract t2) 47 | $ do 48 | void $ Trace.activateContractWallet w2 theContract 49 | lockTrace w1 "secret" 50 | 51 | , checkPredicate "guess right (unlock funds)" 52 | (walletFundsChange w2 (Ada.adaValueOf 10) 53 | .&&. walletFundsChange w1 (Ada.adaValueOf (-10))) 54 | $ do 55 | lockTrace w1 "secret" 56 | guessTrace w2 "secret" 57 | 58 | , checkPredicate "guess wrong" 59 | (walletFundsChange w2 (Ada.lovelaceValueOf 0) 60 | .&&. walletFundsChange w1 (Ada.adaValueOf (-10))) 61 | $ do 62 | lockTrace w1 "secret" 63 | guessTrace w2 "SECRET" 64 | 65 | , goldenPir "examples/test/Spec/game.pir" $$(PlutusTx.compile [|| validateGuess ||]) 66 | 67 | , HUnit.testCase "script size is reasonable" (reasonable gameValidator 20000) 68 | ] 69 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env nix-shell 2 | # -*-Shell-script-*- 3 | #! nix-shell -i bash ../shell.nix --pure --arg pure true 4 | 5 | set -eEuo pipefail 6 | 7 | cabal update 8 | 9 | cabal build plutus-starter-pab 10 | 11 | # We run plutus-starter-pab under a coproc to enable backgrounding when in an interactive shell 12 | coproc cabal exec -- plutus-starter-pab 13 | kill_pab() { 14 | echo >&${COPROC[1]} 15 | 16 | wait 17 | } 18 | trap kill_pab EXIT 19 | 20 | # Start a background loop to print out the output from plutus-starter-pab 21 | exec 3<&${COPROC[0]} 22 | (while IFS= read -u 3 -r line; do echo $line; done) & 23 | 24 | wait_with_backoff() { 25 | cmd="$1" 26 | msg="$2" 27 | final_cmd="${3:-$cmd}" 28 | up=0 29 | for ((i=0;i<=6;i++)) 30 | do 31 | if eval "$cmd" 32 | then 33 | up=1 34 | break 35 | fi 36 | let delay=2**i 37 | echo "$msg, sleeping for ${delay} seconds then trying again" >&2 38 | sleep "${delay}" 39 | done 40 | if [[ "$up" == "0" ]] 41 | then 42 | eval "$final_cmd" 43 | fi 44 | } 45 | 46 | wait_with_backoff "curl --fail http://localhost:9080/api/contract/definitions &>/dev/null" "Connecting to PAB failed" "curl --fail http://localhost:9080/api/contract/definitions" 47 | 48 | play() { 49 | secret="$1" 50 | guess="$2" 51 | 52 | WALLET_ID=$(cat scripts/wallet) 53 | CONTRACT_ID=$(curl --fail --silent \ 54 | --header "Content-Type: application/json" \ 55 | --data '{"caID": "GameContract", "caWallet":{"getWalletId": "'$WALLET_ID'"}}' \ 56 | http://localhost:9080/api/contract/activate | jq -r '.unContractInstanceId') 57 | 58 | log_count=0 59 | wait_for_contract() { 60 | wait_with_backoff 'curl --fail --silent http://localhost:9080/api/contract/instance/'$CONTRACT_ID'/status > status.json && [[ "$(jq -r '\''.cicCurrentState.logs | length'\'' < status.json)" -gt "'$log_count'" && ("$(jq -r .cicCurrentState.lastLogs[0]._logMessageContent < status.json)" == "Waiting for guess or lock endpoint..." || "$(jq -r .cicStatus < status.json)" == "Done") ]]' "Contract not ready" 61 | log_count="$(jq -r '.cicCurrentState.logs | length' = 4.9 && < 5, 48 | aeson -any, 49 | bytestring -any, 50 | containers -any, 51 | freer-extras -any, 52 | playground-common -any, 53 | plutus-contract -any, 54 | plutus-ledger -any, 55 | plutus-ledger-api -any, 56 | plutus-ledger-constraints -any, 57 | plutus-tx -any, 58 | plutus-tx-plugin -any, 59 | plutus-script-utils -any, 60 | text -any, 61 | lens -any, 62 | hs-source-dirs: src examples/src 63 | 64 | test-suite plutus-example-projects-test 65 | import: lang 66 | type: exitcode-stdio-1.0 67 | main-is: Spec.hs 68 | hs-source-dirs: examples/test 69 | other-modules: 70 | Spec.Game 71 | build-depends: 72 | plutus-tx -any, 73 | plutus-tx-plugin, 74 | plutus-contract -any, 75 | plutus-pab -any, 76 | plutus-ledger -any, 77 | plutus-starter -any 78 | build-depends: 79 | base >=4.9 && <5, 80 | tasty -any, 81 | tasty-hunit -any, 82 | text -any, 83 | tasty-hedgehog >=0.2.0.0 84 | 85 | 86 | executable plutus-starter-pab 87 | import: lang 88 | main-is: Main.hs 89 | hs-source-dirs: pab 90 | ghc-options: 91 | -threaded 92 | build-depends: 93 | base >= 4.9 && < 5, 94 | data-default -any, 95 | plutus-contract -any, 96 | plutus-pab -any, 97 | plutus-starter -any, 98 | aeson -any, 99 | freer-simple -any, 100 | prettyprinter -any, 101 | freer-extras -any, 102 | plutus-ledger -any, 103 | openapi3 -any, 104 | -------------------------------------------------------------------------------- /nix/pkgs/haskell/sha256map.nix: -------------------------------------------------------------------------------- 1 | { 2 | "https://github.com/input-output-hk/plutus-apps.git"."v0.1.0" = "1pcxv8l4rgwi0sa3ygq1ag1hyxj61rh03ij5mws78hax09p16vl4"; 3 | "https://github.com/input-output-hk/ekg-forward"."297cd9db5074339a2fb2e5ae7d0780debb670c63" = "1zcwry3y5rmd9lgxy89wsb3k4kpffqji35dc7ghzbz603y1gy24g"; 4 | "https://github.com/input-output-hk/cardano-addresses"."71006f9eb956b0004022e80aadd4ad50d837b621" = "11dl3fmq7ry5wdmz8kw07ji8yvrxnrsf7pgilw5q9mi4aqyvnaqk"; 5 | "https://github.com/input-output-hk/cardano-base"."41545ba3ac6b3095966316a99883d678b5ab8da8" = "0icq9y3nnl42fz536da84414av36g37894qnyw4rk3qkalksqwir"; 6 | "https://github.com/input-output-hk/cardano-config"."e9de7a2cf70796f6ff26eac9f9540184ded0e4e6" = "1wm1c99r5zvz22pdl8nhkp13falvqmj8dgkm8fxskwa9ydqz01ld"; 7 | "https://github.com/input-output-hk/cardano-crypto"."f73079303f663e028288f9f4a9e08bcca39a923e" = "1n87i15x54s0cjkh3nsxs4r1x016cdw1fypwmr68936n3xxsjn6q"; 8 | "https://github.com/input-output-hk/cardano-ledger"."1a9ec4ae9e0b09d54e49b2a40c4ead37edadcce5" = "0avzyiqq0m8njd41ck9kpn992yq676b1az9xs77977h7cf85y4wm"; 9 | "https://github.com/input-output-hk/cardano-node"."2b1d18c6c7b7142d9eebfec34da48840ed4409b6" = "102pj525ysvj27h9nb8gidxm1cmwp8vpdyfnpwm1ywz3zkpk2mjp"; 10 | "https://github.com/input-output-hk/cardano-prelude"."bb4ed71ba8e587f672d06edf9d2e376f4b055555" = "00h10l5mmiza9819p9v5q5749nb9pzgi20vpzpy1d34zmh6gf1cj"; 11 | "https://github.com/input-output-hk/cardano-wallet"."f6d4db733c4e47ee11683c343b440552f59beff7" = "0gb3zyv3q5v5sd8r29s02yc0brwq5a01is9c0n528391n2r8g1yy"; 12 | "https://github.com/input-output-hk/goblins"."cde90a2b27f79187ca8310b6549331e59595e7ba" = "17c88rbva3iw82yg9srlxjv2ia5wjb9cyqw44hik565f5v9svnyg"; 13 | "https://github.com/input-output-hk/iohk-monitoring-framework"."46f994e216a1f8b36fe4669b47b2a7011b0e153c" = "1il8fx3misp3650ryj368b3x95ksz01zz3x0z9k00807j93d0ka0"; 14 | "https://github.com/input-output-hk/ouroboros-network"."4fac197b6f0d2ff60dc3486c593b68dc00969fbf" = "1b43vbdsr9m3ry1kgag2p2ixpv54gw7a4vvmndxl6knqg8qbsb8b"; 15 | "https://github.com/input-output-hk/plutus"."6d9ac7c2f89363d574dbc10be5c2db4b661c9a43" = "1678c7fgd7sn8wfd8bpv60wqnfla3vijyb9n6x6d2d2mfiri6p9c"; 16 | "https://github.com/input-output-hk/purescript-bridge"."47a1f11825a0f9445e0f98792f79172efef66c00" = "0da1vn2l6iyfxcjk58qal1l4755v92zi6yppmjmqvxf1gacyf9px"; 17 | "https://github.com/input-output-hk/servant-purescript"."44e7cacf109f84984cd99cd3faf185d161826963" = "10pb0yfp80jhb9ryn65a4rha2lxzsn2vlhcc6xphrrkf4x5lhzqc"; 18 | "https://github.com/input-output-hk/Win32-network"."3825d3abf75f83f406c1f7161883c438dac7277d" = "19wahfv726fa3mqajpqdqhnl9ica3xmf68i254q45iyjcpj1psqx"; 19 | "https://github.com/Quid2/flat"."ee59880f47ab835dbd73bea0847dab7869fc20d8" = "1lrzknw765pz2j97nvv9ip3l1mcpf2zr4n56hwlz0rk7wq7ls4cm"; 20 | "https://github.com/raduom/hysterical-screams"."4c523469e9efd3f0d10d17da3304923b7b0e0674" = "0w118v4vffrsjxfmwfv8qcn2qxmxpd1gxwcjnda91qz09jnpg0vp"; 21 | "https://github.com/input-output-hk/quickcheck-dynamic"."c272906361471d684440f76c297e29ab760f6a1e" = "sha256-TioJQASNrQX6B3n2Cv43X2olyT67//CFQqcpvNW7N60="; 22 | } 23 | -------------------------------------------------------------------------------- /release.nix: -------------------------------------------------------------------------------- 1 | { plutus-apps ? null 2 | }: 3 | 4 | # The content of this file was partially copied from the equivalent file in the plutus repository. 5 | # It is used by IOHK's Hydra for CI (building the project, running the tests, etc.) 6 | # 7 | # Therefore, do not worry too much about the structure. 8 | let 9 | # If hydra passed us a plutus-apps checkout, we want to override the 10 | # plutus-apps used by haskell.nix 11 | source-repo-override = if plutus-apps == null then {} else { 12 | # Overwrite the source-repository-package entry with this URL 13 | "https://github.com/input-output-hk/plutus-apps.git" = orig: { 14 | url = plutus-apps.uri; 15 | ref = plutus-apps.rev; 16 | # Nix needs the sha256 of the checked-out source, but hydra 17 | # gives us the path itself, not its hash. This uses the 18 | # exportReferencesGraph feature of Nix to introspect properties 19 | # of a given store path (in this case, its sha256), creates 20 | # a Nix expression containing that hash, and imports that Nix 21 | # expression into the current evaluation to get the hash 22 | sha256 = import (pkgs.stdenv.mkDerivation { 23 | name = "plutus-apps-sha.nix"; 24 | exportReferencesGraph.plutus-apps = plutus-apps; 25 | __structuredAttrs = true; 26 | PATH = pkgs.lib.makeBinPath [ pkgs.coreutils pkgs.jq ]; 27 | builder = builtins.toFile "builder" '' 28 | . .attrs.sh 29 | jq '."plutus-apps"[0].narHash' < .attrs.json > "$(jq -r .outputs.out < .attrs.json)" 30 | ''; 31 | }); 32 | # We assume the new version has the same subpackages we did 33 | # originally. 34 | inherit (orig) subdirs; 35 | }; 36 | }; 37 | packages = import ./. { 38 | inherit source-repo-override; 39 | }; 40 | 41 | pkgs = packages.pkgs; 42 | haskellNix = pkgs.haskell-nix; 43 | 44 | # Just the packages in the project 45 | projectPackages = haskellNix.haskellLib.selectProjectPackages packages.project.hsPkgs; 46 | 47 | inherit (import ./nix/lib/ci.nix { inherit pkgs; }) dimension filterAttrsOnlyRecursive filterDerivations stripAttrsForHydra derivationAggregate; 48 | 49 | # Collects haskell derivations and builds an attrset: 50 | # 51 | # { library = { ... } 52 | # , tests = { ... } 53 | # , benchmarks = { ... } 54 | # , exes = { ... } 55 | # , checks = { ... } 56 | # } 57 | # Where each attribute contains an attribute set 58 | # with all haskell components of that type 59 | mkHaskellDimension = pkgs: haskellProjects: 60 | let 61 | # retrieve all checks from a Haskell package 62 | collectChecks = _: ps: pkgs.haskell-nix.haskellLib.collectChecks' ps; 63 | # retrieve all components of a Haskell package 64 | collectComponents = type: ps: pkgs.haskell-nix.haskellLib.collectComponents' type ps; 65 | # Given a component type and the retrieve function, retrieve components from haskell packages 66 | select = type: selector: (selector type) haskellProjects; 67 | # { component-type : retriever-fn } 68 | attrs = { 69 | "library" = collectComponents; 70 | "tests" = collectComponents; 71 | "benchmarks" = collectComponents; 72 | "exes" = collectComponents; 73 | "checks" = collectChecks; 74 | }; 75 | in 76 | dimension "Haskell component" attrs select; 77 | 78 | ciJobsets = stripAttrsForHydra (filterDerivations { 79 | shell = (import ./shell.nix { inherit source-repo-override; }); 80 | 81 | pureShell = (import ./shell.nix { pure = true; inherit source-repo-override; }); 82 | 83 | build = pkgs.recurseIntoAttrs (mkHaskellDimension pkgs projectPackages); 84 | }); 85 | in 86 | ciJobsets // { required = derivationAggregate "required-plutus-starter" ciJobsets; } 87 | 88 | -------------------------------------------------------------------------------- /pab/Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE DeriveAnyClass #-} 3 | {-# LANGUAGE DeriveGeneric #-} 4 | {-# LANGUAGE DerivingStrategies #-} 5 | {-# LANGUAGE FlexibleContexts #-} 6 | {-# LANGUAGE LambdaCase #-} 7 | {-# LANGUAGE RankNTypes #-} 8 | {-# LANGUAGE TypeApplications #-} 9 | {-# LANGUAGE TypeFamilies #-} 10 | {-# LANGUAGE TypeOperators #-} 11 | 12 | module Main(main, writeCostingScripts) where 13 | 14 | import Control.Monad (void) 15 | import Control.Monad.Freer (interpret) 16 | import Control.Monad.IO.Class (MonadIO (..)) 17 | import Data.Aeson (FromJSON (..), ToJSON (..), genericToJSON, genericParseJSON 18 | , defaultOptions, Options(..)) 19 | import Data.Default (def) 20 | import qualified Data.OpenApi as OpenApi 21 | import GHC.Generics (Generic) 22 | import Plutus.Contract (ContractError) 23 | import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), BuiltinHandler(contractHandler)) 24 | import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin 25 | import Plutus.PAB.Simulator (SimulatorEffectHandlers) 26 | import qualified Plutus.PAB.Simulator as Simulator 27 | import qualified Plutus.PAB.Webserver.Server as PAB.Server 28 | import Plutus.Contracts.Game as Game 29 | import Plutus.Trace.Emulator.Extract (writeScriptsTo, ScriptsConfig (..), Command (..)) 30 | import Prettyprinter (Pretty (..), viaShow) 31 | import Ledger.Index (ValidatorMode(..)) 32 | import qualified Wallet.Emulator.Wallet as Wallet 33 | 34 | main :: IO () 35 | main = void $ Simulator.runSimulationWith handlers $ do 36 | Simulator.logString @(Builtin StarterContracts) "Starting plutus-starter PAB webserver on port 9080. Press enter to exit." 37 | 38 | (wallet, _paymentPubKeyHash) <- Simulator.addWallet 39 | Simulator.waitNSlots 1 40 | liftIO $ writeFile "scripts/wallet" (show $ Wallet.getWalletId wallet) 41 | 42 | shutdown <- PAB.Server.startServerDebug 43 | 44 | -- Example of spinning up a game instance on startup 45 | -- void $ Simulator.activateContract (Wallet 1) GameContract 46 | -- You can add simulator actions here: 47 | -- Simulator.observableState 48 | -- etc. 49 | -- That way, the simulation gets to a predefined state and you don't have to 50 | -- use the HTTP API for setup. 51 | 52 | -- Pressing enter results in the balances being printed 53 | void $ liftIO getLine 54 | 55 | Simulator.logString @(Builtin StarterContracts) "Balances at the end of the simulation" 56 | b <- Simulator.currentBalances 57 | Simulator.logBalances @(Builtin StarterContracts) b 58 | 59 | shutdown 60 | 61 | -- | An example of computing the script size for a particular trace. 62 | -- Read more: 63 | writeCostingScripts :: IO () 64 | writeCostingScripts = do 65 | let config = ScriptsConfig { scPath = "/tmp/plutus-costing-outputs/", scCommand = cmd } 66 | cmd = Scripts { unappliedValidators = FullyAppliedValidators } 67 | -- Note: Here you can use any trace you wish. 68 | trace = correctGuessTrace 69 | (totalSize, exBudget) <- writeScriptsTo config "game" trace def 70 | putStrLn $ "Total size = " <> show totalSize 71 | putStrLn $ "ExBudget = " <> show exBudget 72 | 73 | 74 | data StarterContracts = 75 | GameContract 76 | deriving (Eq, Ord, Show, Generic) 77 | deriving anyclass OpenApi.ToSchema 78 | 79 | -- NOTE: Because 'StarterContracts' only has one constructor, corresponding to 80 | -- the demo 'Game' contract, we kindly ask aeson to still encode it as if it had 81 | -- many; this way we get to see the label of the contract in the API output! 82 | -- If you simple have more contracts, you can just use the anyclass deriving 83 | -- statement on 'StarterContracts' instead: 84 | -- 85 | -- `... deriving anyclass (ToJSON, FromJSON)` 86 | instance ToJSON StarterContracts where 87 | toJSON = genericToJSON defaultOptions { 88 | tagSingleConstructors = True } 89 | instance FromJSON StarterContracts where 90 | parseJSON = genericParseJSON defaultOptions { 91 | tagSingleConstructors = True } 92 | 93 | instance Pretty StarterContracts where 94 | pretty = viaShow 95 | 96 | instance Builtin.HasDefinitions StarterContracts where 97 | getDefinitions = [GameContract] 98 | getSchema = \case 99 | GameContract -> Builtin.endpointsToSchemas @Game.GameSchema 100 | getContract = \case 101 | GameContract -> SomeBuiltin (Game.game @ContractError) 102 | 103 | handlers :: SimulatorEffectHandlers (Builtin StarterContracts) 104 | handlers = 105 | Simulator.mkSimulatorHandlers def 106 | $ interpret (contractHandler Builtin.handleBuiltin) 107 | 108 | -------------------------------------------------------------------------------- /nix/lib/ci.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | let 4 | # Generic nixpkgs, use *only* for lib functions that are stable across versions 5 | lib = pkgs.lib; 6 | in 7 | rec { 8 | # Borrowed from https://github.com/cachix/ghcide-nix/pull/4/files#diff-70bfff902f4dec33e545cac10ee5844d 9 | # Tweaked to use builtins.mapAttrs instead of needing the one from nixpkgs lib 10 | /* 11 | dimension: name -> attrs -> function -> attrs 12 | where 13 | function: keyText -> value -> attrsOf package 14 | 15 | WARNING: Attribute names must not contain periods ("."). 16 | See https://github.com/NixOS/nix/issues/3088 17 | 18 | NOTE: The dimension name will be picked up by agent and web ui soon. 19 | 20 | Specifies a dimension of the build matrix. For example 21 | 22 | dimension "Example" { 23 | withP = { p = true; } 24 | withoutP = { p = false; } 25 | } (key: # either "withP" or "withoutP" 26 | { p }: # either p = true or p = false 27 | myProject p 28 | ) 29 | 30 | evaluates roughly to 31 | 32 | { 33 | withP = myProject true; 34 | withoutP = myProject false; 35 | } 36 | 37 | Use nested calls for multiple dimensions. 38 | 39 | Example: 40 | 41 | dimension "System" { 42 | "x86_64-linux" = {}; 43 | # ... 44 | }: (system: {}: 45 | 46 | dimension "Nixpkgs release" ( 47 | { 48 | "nixpkgs-19_03".nixpkgs = someSource 49 | } // optionalAttrs (system != "...") { 50 | "nixpkgs-unstable".nixpkgs = someOtherSource 51 | } 52 | ) (_key: { nixpkgs }: 53 | 54 | myProject system nixpkgs 55 | 56 | ) 57 | ) 58 | 59 | evaluates roughly to 60 | 61 | { 62 | x86_64-linux.nixpkgs-19_03 = myProject "x86_64-linux" someSource; 63 | x86_64-linux.nixpkgs-unstable = myProject "x86_64-linux" someOtherSource; 64 | ... 65 | } 66 | 67 | If you need to make references across attributes, you can do so by binding 68 | the result. Wherever you write 69 | 70 | dimension "My dimension" {} (key: value: f1 key value) 71 | 72 | You can also write 73 | 74 | let 75 | myDimension = dimension "My dimension" {} (key: value: f2 key value myDimension) 76 | in 77 | myDimension 78 | 79 | This example builds a single test runner to reuse across releases: 80 | 81 | let 82 | overlay = 83 | testRunnerPkgs: self: super: { 84 | # ... 85 | }; 86 | myProject = 87 | { nixpkgs, 88 | pkgs ? import nixpkgs { overlays = [ overlay ]; }, 89 | testRunnerPkgs ? pkgs 90 | }: pkgs; 91 | in 92 | 93 | let 94 | latest = "nixpkgs-19_03"; 95 | releases = 96 | dimension "Nixpkgs release" 97 | { 98 | nixpkgs-18_09.nixpkgs = someSource 99 | nixpkgs-19_03.nixpkgs = someOtherSource 100 | } 101 | (_key: { nixpkgs }: 102 | 103 | myProject { 104 | inherit nixpkgs; 105 | testRunnerPkgs = releases."${latest}"; 106 | } 107 | 108 | ); 109 | in releases; 110 | 111 | */ 112 | dimension = name: attrs: f: 113 | builtins.mapAttrs 114 | (k: v: 115 | let o = f k v; 116 | in o // { recurseForDerivations = o.recurseForDerivations or true; } 117 | ) 118 | attrs 119 | // { meta.dimension.name = name; }; 120 | 121 | /* 122 | Takes an attribute set and returns all the paths to derivations within it, i.e. 123 | derivationPaths { a = { b = ; }; c = ; } == [ "a.b" "c" ] 124 | This can be used with 'attrByPath' or the 'constitutents' of an aggregate Hydra job. 125 | */ 126 | derivationPaths = 127 | let 128 | names = x: lib.filter (n: n != "recurseForDerivations" && n != "meta") (builtins.attrNames x); 129 | go = nameSections: attrs: 130 | builtins.concatMap 131 | (n: 132 | let 133 | v = builtins.getAttr n attrs; 134 | newNameSections = nameSections ++ [ n ]; 135 | in 136 | if pkgs.lib.isDerivation v 137 | then [ (builtins.concatStringsSep "." newNameSections) ] 138 | else if builtins.isAttrs v 139 | then go newNameSections v 140 | else [ ] 141 | ) 142 | (names attrs); 143 | in 144 | go [ ]; 145 | 146 | # Creates an aggregate job with the given name from every derivation in the attribute set. 147 | derivationAggregate = name: attrs: pkgs.releaseTools.aggregate { 148 | inherit name; 149 | constituents = derivationPaths attrs; 150 | }; 151 | 152 | # A filter for removing packages that aren't supported on the current platform 153 | # according to 'meta.platforms'. 154 | platformFilterGeneric = pkgs: system: 155 | # This needs to use the correct nixpkgs version so all the systems line up 156 | let 157 | lib = pkgs.lib; 158 | platform = lib.systems.elaborate { inherit system; }; 159 | # Can't just default to [] for platforms, since no meta.platforms 160 | # means "all platforms" not "no platforms" 161 | in 162 | drv: 163 | if drv ? meta && drv.meta ? platforms then 164 | lib.any (lib.meta.platformMatch platform) drv.meta.platforms 165 | else true; 166 | 167 | # Hydra doesn't like these attributes hanging around in "jobsets": it thinks they're jobs! 168 | stripAttrsForHydra = filterAttrsOnlyRecursive (n: _: n != "recurseForDerivations" && n != "dimension"); 169 | 170 | # Keep derivations and attrsets with 'recurseForDerivations'. This ensures that we match the 171 | # derivations that Hercules will see, and prevents Hydra from trying to pick up all sorts of bad stuff 172 | # (like attrsets that contain themselves!). 173 | filterDerivations = filterAttrsOnlyRecursive (n: attrs: lib.isDerivation attrs || attrs.recurseForDerivations or false); 174 | 175 | # A version of 'filterAttrsRecursive' that doesn't recurse into derivations. This prevents us from going into an infinite 176 | # loop with the 'out' attribute on derivations. 177 | # TODO: Surely this shouldn't be necessary. I think normal 'filterAttrsRecursive' will effectively cause infinite loops 178 | # if you keep derivations and your predicate forces the value of the attribute, as this then triggers a loop on the 179 | # 'out' attribute. Weird. 180 | filterAttrsOnlyRecursive = pred: set: 181 | lib.listToAttrs ( 182 | lib.concatMap 183 | (name: 184 | let v = set.${name}; in 185 | if pred name v then [ 186 | (lib.nameValuePair name ( 187 | if builtins.isAttrs v && !lib.isDerivation v then filterAttrsOnlyRecursive pred v 188 | else v 189 | )) 190 | ] else [ ] 191 | ) 192 | (builtins.attrNames set) 193 | ); 194 | 195 | # Takes an array of systems and returns a `name: system` AttrSet 196 | # filterSystems :: [ string ] -> AttrSet 197 | filterSystems = systems: lib.filterAttrs (_: v: builtins.elem v systems) { 198 | linux = "x86_64-linux"; 199 | darwin = "x86_64-darwin"; 200 | }; 201 | } 202 | -------------------------------------------------------------------------------- /nix/sources.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by Niv. 2 | 3 | let 4 | 5 | # 6 | # The fetchers. fetch_ fetches specs of type . 7 | # 8 | 9 | fetch_file = pkgs: name: spec: 10 | let 11 | name' = sanitizeName name + "-src"; 12 | in 13 | if spec.builtin or true then 14 | builtins_fetchurl { inherit (spec) url sha256; name = name'; } 15 | else 16 | pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; 17 | 18 | fetch_tarball = pkgs: name: spec: 19 | let 20 | name' = sanitizeName name + "-src"; 21 | in 22 | if spec.builtin or true then 23 | builtins_fetchTarball { name = name'; inherit (spec) url sha256; } 24 | else 25 | pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; 26 | 27 | fetch_git = name: spec: 28 | let 29 | ref = 30 | if spec ? ref then spec.ref else 31 | if spec ? branch then "refs/heads/${spec.branch}" else 32 | if spec ? tag then "refs/tags/${spec.tag}" else 33 | abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; 34 | in 35 | builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; 36 | 37 | fetch_local = spec: spec.path; 38 | 39 | fetch_builtin-tarball = name: throw 40 | ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. 41 | $ niv modify ${name} -a type=tarball -a builtin=true''; 42 | 43 | fetch_builtin-url = name: throw 44 | ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. 45 | $ niv modify ${name} -a type=file -a builtin=true''; 46 | 47 | # 48 | # Various helpers 49 | # 50 | 51 | # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 52 | sanitizeName = name: 53 | ( 54 | concatMapStrings (s: if builtins.isList s then "-" else s) 55 | ( 56 | builtins.split "[^[:alnum:]+._?=-]+" 57 | ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) 58 | ) 59 | ); 60 | 61 | # The set of packages used when specs are fetched using non-builtins. 62 | mkPkgs = sources: system: 63 | let 64 | sourcesNixpkgs = 65 | import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; 66 | hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; 67 | hasThisAsNixpkgsPath = == ./.; 68 | in 69 | if builtins.hasAttr "nixpkgs" sources 70 | then sourcesNixpkgs 71 | else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then 72 | import {} 73 | else 74 | abort 75 | '' 76 | Please specify either (through -I or NIX_PATH=nixpkgs=...) or 77 | add a package called "nixpkgs" to your sources.json. 78 | ''; 79 | 80 | # The actual fetching function. 81 | fetch = pkgs: name: spec: 82 | 83 | if ! builtins.hasAttr "type" spec then 84 | abort "ERROR: niv spec ${name} does not have a 'type' attribute" 85 | else if spec.type == "file" then fetch_file pkgs name spec 86 | else if spec.type == "tarball" then fetch_tarball pkgs name spec 87 | else if spec.type == "git" then fetch_git name spec 88 | else if spec.type == "local" then fetch_local spec 89 | else if spec.type == "builtin-tarball" then fetch_builtin-tarball name 90 | else if spec.type == "builtin-url" then fetch_builtin-url name 91 | else 92 | abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; 93 | 94 | # If the environment variable NIV_OVERRIDE_${name} is set, then use 95 | # the path directly as opposed to the fetched source. 96 | replace = name: drv: 97 | let 98 | saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; 99 | ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; 100 | in 101 | if ersatz == "" then drv else 102 | # this turns the string into an actual Nix path (for both absolute and 103 | # relative paths) 104 | if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; 105 | 106 | # Ports of functions for older nix versions 107 | 108 | # a Nix version of mapAttrs if the built-in doesn't exist 109 | mapAttrs = builtins.mapAttrs or ( 110 | f: set: with builtins; 111 | listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) 112 | ); 113 | 114 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 115 | range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); 116 | 117 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 118 | stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); 119 | 120 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 121 | stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); 122 | concatMapStrings = f: list: concatStrings (map f list); 123 | concatStrings = builtins.concatStringsSep ""; 124 | 125 | # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 126 | optionalAttrs = cond: as: if cond then as else {}; 127 | 128 | # fetchTarball version that is compatible between all the versions of Nix 129 | builtins_fetchTarball = { url, name ? null, sha256 }@attrs: 130 | let 131 | inherit (builtins) lessThan nixVersion fetchTarball; 132 | in 133 | if lessThan nixVersion "1.12" then 134 | fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) 135 | else 136 | fetchTarball attrs; 137 | 138 | # fetchurl version that is compatible between all the versions of Nix 139 | builtins_fetchurl = { url, name ? null, sha256 }@attrs: 140 | let 141 | inherit (builtins) lessThan nixVersion fetchurl; 142 | in 143 | if lessThan nixVersion "1.12" then 144 | fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) 145 | else 146 | fetchurl attrs; 147 | 148 | # Create the final "sources" from the config 149 | mkSources = config: 150 | mapAttrs ( 151 | name: spec: 152 | if builtins.hasAttr "outPath" spec 153 | then abort 154 | "The values in sources.json should not have an 'outPath' attribute" 155 | else 156 | spec // { outPath = replace name (fetch config.pkgs name spec); } 157 | ) config.sources; 158 | 159 | # The "config" used by the fetchers 160 | mkConfig = 161 | { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null 162 | , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) 163 | , system ? builtins.currentSystem 164 | , pkgs ? mkPkgs sources system 165 | }: rec { 166 | # The sources, i.e. the attribute set of spec name to spec 167 | inherit sources; 168 | 169 | # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers 170 | inherit pkgs; 171 | }; 172 | 173 | in 174 | mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } 175 | -------------------------------------------------------------------------------- /examples/src/Plutus/Contracts/Game.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE AllowAmbiguousTypes #-} 2 | {-# LANGUAGE DataKinds #-} 3 | {-# LANGUAGE DeriveAnyClass #-} 4 | {-# LANGUAGE DeriveGeneric #-} 5 | {-# LANGUAGE DerivingStrategies #-} 6 | {-# LANGUAGE FlexibleContexts #-} 7 | {-# LANGUAGE FlexibleInstances #-} 8 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 9 | {-# LANGUAGE MultiParamTypeClasses #-} 10 | {-# LANGUAGE NoImplicitPrelude #-} 11 | {-# LANGUAGE PartialTypeSignatures #-} 12 | {-# LANGUAGE RecordWildCards #-} 13 | {-# LANGUAGE ScopedTypeVariables #-} 14 | {-# LANGUAGE TemplateHaskell #-} 15 | {-# LANGUAGE TypeApplications #-} 16 | {-# LANGUAGE TypeFamilies #-} 17 | {-# LANGUAGE TypeOperators #-} 18 | {-# LANGUAGE ViewPatterns #-} 19 | 20 | 21 | -- | A guessing game 22 | module Plutus.Contracts.Game 23 | ( lock 24 | , guess 25 | , game 26 | , GameSchema 27 | , GuessParams(..) 28 | , LockParams(..) 29 | -- * Scripts 30 | , gameValidator 31 | , hashString 32 | , clearString 33 | -- * Address 34 | , gameAddress 35 | , validateGuess 36 | -- * Traces 37 | , guessTrace 38 | , lockTrace 39 | , correctGuessTrace 40 | ) where 41 | 42 | import Control.Monad (void) 43 | import qualified Data.ByteString.Char8 as C 44 | import Data.Map (Map) 45 | import qualified Data.Map as Map 46 | import Data.Maybe (catMaybes) 47 | import Plutus.V1.Ledger.Api (Address, ScriptContext, Validator, Value, Datum(Datum)) 48 | import qualified Ledger 49 | import qualified Ledger.Ada as Ada 50 | import qualified Ledger.Constraints as Constraints 51 | import Ledger.Tx (ChainIndexTxOut (..)) 52 | import Playground.Contract 53 | import Plutus.Contract 54 | import Plutus.Contract.Trace as X 55 | import qualified PlutusTx 56 | import PlutusTx.Prelude hiding (pure, (<$>)) 57 | import qualified Prelude as Haskell 58 | import Plutus.Trace.Emulator (EmulatorTrace) 59 | import qualified Plutus.Trace.Emulator as Trace 60 | import qualified Plutus.Script.Utils.V1.Typed.Scripts as Scripts 61 | 62 | newtype HashedString = HashedString BuiltinByteString deriving newtype (PlutusTx.ToData, PlutusTx.FromData, PlutusTx.UnsafeFromData) 63 | 64 | PlutusTx.makeLift ''HashedString 65 | 66 | newtype ClearString = ClearString BuiltinByteString deriving newtype (PlutusTx.ToData, PlutusTx.FromData, PlutusTx.UnsafeFromData) 67 | 68 | PlutusTx.makeLift ''ClearString 69 | 70 | type GameSchema = 71 | Endpoint "lock" LockParams 72 | .\/ Endpoint "guess" GuessParams 73 | 74 | data Game 75 | instance Scripts.ValidatorTypes Game where 76 | type instance RedeemerType Game = ClearString 77 | type instance DatumType Game = HashedString 78 | 79 | gameInstance :: Scripts.TypedValidator Game 80 | gameInstance = Scripts.mkTypedValidator @Game 81 | $$(PlutusTx.compile [|| validateGuess ||]) 82 | $$(PlutusTx.compile [|| wrap ||]) where 83 | wrap = Scripts.mkUntypedValidator @HashedString @ClearString 84 | 85 | -- create a data script for the guessing game by hashing the string 86 | -- and lifting the hash to its on-chain representation 87 | hashString :: Haskell.String -> HashedString 88 | hashString = HashedString . sha2_256 . toBuiltin . C.pack 89 | 90 | -- create a redeemer script for the guessing game by lifting the 91 | -- string to its on-chain representation 92 | clearString :: Haskell.String -> ClearString 93 | clearString = ClearString . toBuiltin . C.pack 94 | 95 | -- | The validation function (Datum -> Redeemer -> ScriptContext -> Bool) 96 | validateGuess :: HashedString -> ClearString -> ScriptContext -> Bool 97 | validateGuess hs cs _ = isGoodGuess hs cs 98 | 99 | isGoodGuess :: HashedString -> ClearString -> Bool 100 | isGoodGuess (HashedString actual) (ClearString guess') = actual == sha2_256 guess' 101 | 102 | -- | The validator script of the game. 103 | gameValidator :: Validator 104 | gameValidator = Scripts.validatorScript gameInstance 105 | 106 | -- | The address of the game (the hash of its validator script) 107 | gameAddress :: Address 108 | gameAddress = Ledger.scriptAddress gameValidator 109 | 110 | -- | Parameters for the "lock" endpoint 111 | data LockParams = LockParams 112 | { secretWord :: Haskell.String 113 | , amount :: Value 114 | } 115 | deriving stock (Haskell.Eq, Haskell.Show, Generic) 116 | deriving anyclass (FromJSON, ToJSON, ToSchema, ToArgument) 117 | 118 | -- | Parameters for the "guess" endpoint 119 | newtype GuessParams = GuessParams 120 | { guessWord :: Haskell.String 121 | } 122 | deriving stock (Haskell.Eq, Haskell.Show, Generic) 123 | deriving anyclass (FromJSON, ToJSON, ToSchema, ToArgument) 124 | 125 | -- | The "lock" contract endpoint. See note [Contract endpoints] 126 | lock :: AsContractError e => Promise () GameSchema e () 127 | lock = endpoint @"lock" @LockParams $ \(LockParams secret amt) -> do 128 | logInfo @Haskell.String $ "Pay " <> Haskell.show amt <> " to the script" 129 | let tx = Constraints.mustPayToTheScript (hashString secret) amt 130 | void (submitTxConstraints gameInstance tx) 131 | 132 | -- | The "guess" contract endpoint. See note [Contract endpoints] 133 | guess :: AsContractError e => Promise () GameSchema e () 134 | guess = endpoint @"guess" @GuessParams $ \(GuessParams theGuess) -> do 135 | -- Wait for script to have a UTxO of a least 1 lovelace 136 | logInfo @Haskell.String "Waiting for script to have a UTxO of at least 1 lovelace" 137 | utxos <- fundsAtAddressGeq gameAddress (Ada.lovelaceValueOf 1) 138 | 139 | let redeemer = clearString theGuess 140 | tx = collectFromScript utxos redeemer 141 | 142 | -- Log a message saying if the secret word was correctly guessed 143 | let hashedSecretWord = findSecretWordValue utxos 144 | isCorrectSecretWord = fmap (`isGoodGuess` redeemer) hashedSecretWord == Just True 145 | if isCorrectSecretWord 146 | then logWarn @Haskell.String "Correct secret word! Submitting the transaction" 147 | else logWarn @Haskell.String "Incorrect secret word, but still submiting the transaction" 148 | 149 | -- This is only for test purposes to have a possible failing transaction. 150 | -- In a real use-case, we would not submit the transaction if the guess is 151 | -- wrong. 152 | logInfo @Haskell.String "Submitting transaction to guess the secret word" 153 | void (submitTxConstraintsSpending gameInstance utxos tx) 154 | 155 | -- | Find the secret word in the Datum of the UTxOs 156 | findSecretWordValue :: Map TxOutRef ChainIndexTxOut -> Maybe HashedString 157 | findSecretWordValue = 158 | listToMaybe . catMaybes . Map.elems . Map.map secretWordValue 159 | 160 | -- | Extract the secret word in the Datum of a given transaction output is possible 161 | secretWordValue :: ChainIndexTxOut -> Maybe HashedString 162 | secretWordValue o = do 163 | Datum d <- either (const Nothing) Just (_ciTxOutDatum o) 164 | PlutusTx.fromBuiltinData d 165 | 166 | game :: AsContractError e => Contract () GameSchema e () 167 | game = do 168 | logInfo @Haskell.String "Waiting for guess or lock endpoint..." 169 | selectList [lock, guess] >> game 170 | 171 | lockTrace :: Wallet -> Haskell.String -> EmulatorTrace () 172 | lockTrace wallet secretWord = do 173 | hdl <- Trace.activateContractWallet wallet (lock @ContractError) 174 | void $ Trace.waitNSlots 1 175 | Trace.callEndpoint @"lock" hdl (LockParams secretWord (Ada.adaValueOf 10)) 176 | void $ Trace.waitNSlots 1 177 | 178 | guessTrace :: Wallet -> Haskell.String -> EmulatorTrace () 179 | guessTrace wallet guessWord = do 180 | hdl <- Trace.activateContractWallet wallet (guess @ContractError) 181 | void $ Trace.waitNSlots 1 182 | Trace.callEndpoint @"guess" hdl (GuessParams guessWord) 183 | void $ Trace.waitNSlots 1 184 | 185 | correctGuessTrace :: EmulatorTrace () 186 | correctGuessTrace = do 187 | let w1 = X.knownWallet 1 188 | w2 = X.knownWallet 2 189 | secret = "secret" 190 | 191 | h1 <- Trace.activateContractWallet w1 (lock @ContractError) 192 | void $ Trace.waitNSlots 1 193 | Trace.callEndpoint @"lock" h1 (LockParams secret (Ada.adaValueOf 10)) 194 | 195 | h2 <- Trace.activateContractWallet w2 (guess @ContractError) 196 | void $ Trace.waitNSlots 1 197 | Trace.callEndpoint @"guess" h2 (GuessParams secret) 198 | void $ Trace.waitNSlots 1 199 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!WARNING] 2 | > This repository is no longer maintained. To kickstart your Plutus-Tx project, please use [plutus-tx-template](https://github.com/IntersectMBO/plutus-tx-template). 3 | 4 | # Plutus Platform starter project 5 | ![CI](https://github.com/input-output-hk/plutus-starter/actions/workflows/test.yml/badge.svg?branch=main) 6 | 7 | 8 | This project gives a simple starter project for using the Plutus Platform. 9 | 10 | ## Setting up 11 | 12 | ### VSCode devcontainer 13 | 14 | Use the provided VSCode devcontainer to get an environment with the correct tools set up. 15 | 16 | - Install Docker 17 | - Install VSCode 18 | - Install the [Remote Development extension pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) 19 | - You do *not* need to install the Haskell extension 20 | - Ensure you have a `~/.cabal/packages` folder. You can create this via `mkdir -p ~/.cabal/packages`; it's used to cache cabal packages. 21 | - Clone this repository and open it in VSCode 22 | - It will ask if you want to open it in the container, say yes. 23 | - The first time it will take a few minutes to download the devcontainer image from dockerhub, 24 | - `cabal build` from the terminal should work (unless you didn't have a `~/.cabal` folder, in which case you'll need to run `cabal update` first.) 25 | - Opening a Haskell file should give you IDE features (it takes a little while to set up the first time) 26 | 27 | Note: This uses the [plutus-starter-devcontainer image on dockerhub](https://hub.docker.com/r/inputoutput/plutus-starter-devcontainer), if 28 | you wish to build the image yourself, you can do so as follows: 29 | - Clone https://github.com/input-output-hk/plutus-apps, 30 | - Set up your machine to build things with Nix, following the [Plutus README](https://github.com/input-output-hk/plutus/blob/master/README.adoc) (make sure to set up the binary cache!), 31 | - Build and load the docker container: `docker load < $(nix-build default.nix -A devcontainer)`, 32 | - Adjust the `.devcontainer/devcontainer.json` file to point to your local image. 33 | 34 | ### Cabal+Nix build 35 | 36 | Alternatively, use the Cabal+Nix build if you want to develop with incremental builds, but also have it automatically download all dependencies. 37 | 38 | Set up your machine to build things with `Nix`, following the [Plutus README](https://github.com/input-output-hk/plutus/blob/master/README.adoc) (make sure to set up the binary cache!). 39 | 40 | To enter a development environment, simply open a terminal on the project's root and use `nix-shell` to get a bash shell: 41 | 42 | ``` 43 | $ nix-shell 44 | ``` 45 | 46 | Otherwise, you can use [direnv](https://github.com/direnv/direnv) which allows you to use your preferred shell. Once installed, just run: 47 | 48 | ``` 49 | $ echo "use nix" > .envrc # Or manually add "use nix" in .envrc if you already have one 50 | $ direnv allow 51 | ``` 52 | 53 | and you'll have a working development environment for now and the future whenever you enter this directory. 54 | 55 | The build should not take too long if you correctly set up the binary cache. If it starts building GHC, stop and setup the binary cache. 56 | 57 | Afterwards, the command `cabal build` from the terminal should work (if `cabal` couldn't resolve the dependencies, run `cabal update` and then `cabal build`). 58 | 59 | Also included in the environment is a working [Haskell Language Server](https://github.com/haskell/haskell-language-server) you can integrate with your editor. 60 | See [here](https://github.com/haskell/haskell-language-server#configuring-your-editor) for instructions. 61 | 62 | ## The Plutus Application Backend (PAB) example 63 | 64 | We have provided an example PAB application in `./pab`. With the PAB we can serve and interact 65 | with contracts over a web API. You can read more about the PAB here: [PAB Architecture](https://github.com/input-output-hk/plutus-apps/blob/main/plutus-pab/ARCHITECTURE.adoc). 66 | 67 | Here, the PAB is configured with one contract, the `Game` contract from `./examples/src/Plutus/Contracts/Game.hs`. 68 | 69 | Here's an example of running and interacting with this contract via the API. For this it will help if you 70 | have `jq` installed. 71 | 72 | 1. Build the PAB executable: 73 | 74 | ``` 75 | cabal build plutus-starter-pab 76 | ``` 77 | 78 | 2. Run the PAB binary: 79 | 80 | ``` 81 | cabal exec -- plutus-starter-pab 82 | ```` 83 | 84 | This will then start up the server on port 9080. The devcontainer process will then automatically expose this port so that you can connect to it from any terminal (it doesn't have to be a terminal running in the devcontainer). 85 | 86 | First, let's verify that the game is present in the server: 87 | 88 | 3. Check what contracts are present: 89 | 90 | ``` 91 | curl -s http://localhost:9080/api/contract/definitions | jq 92 | ``` 93 | 94 | You should receive a list of contracts and the endpoints that can be called on them, and the arguments 95 | required for those endpoints. 96 | 97 | We're interested in the `GameContract` one. 98 | 99 | #### Playing the guessing game over the API 100 | 101 | The game has two players (wallets). One will initialise the contract and lock a value inside. Another 102 | wallet will then make guesses. Supposing they guess correctly, they'll receive the funds that were 103 | locked; otherwise, they won't! 104 | 105 | 106 | 1. Create wallets 107 | ``` 108 | export WALLET_ID_1=`curl -s -d '' http://localhost:9080/wallet/create | jq '.wiWallet.getWalletId'` 109 | export WALLET_ID_2=`curl -s -d '' http://localhost:9080/wallet/create | jq '.wiWallet.getWalletId'` 110 | ``` 111 | 112 | 2. Start the instances: 113 | 114 | ``` 115 | # Wallet 1 116 | curl -s -H "Content-Type: application/json" \ 117 | --request POST \ 118 | --data '{"caID": "GameContract", "caWallet":{"getWalletId": '$WALLET_ID_1'}}' \ 119 | http://localhost:9080/api/contract/activate | jq 120 | 121 | # Wallet 2 122 | curl -s -H "Content-Type: application/json" \ 123 | --request POST \ 124 | --data '{"caID": "GameContract", "caWallet":{"getWalletId": '$WALLET_ID_2'}}' \ 125 | http://localhost:9080/api/contract/activate | jq 126 | ``` 127 | 128 | From these two queries you will get back two contract instance IDs. These will be needed 129 | in the subsequent steps for running actions against. We can optionally take a look at the state 130 | of the contract with the `status` API: 131 | 132 | 3. Get the status 133 | 134 | ``` 135 | export INSTANCE_ID=... 136 | curl -s http://localhost:9080/api/contract/instance/$INSTANCE_ID/status | jq 137 | ``` 138 | 139 | This has a lot of information; and in particular we can see what endpoints are still available 140 | to call. 141 | 142 | 4. Start the game by locking some value inside 143 | 144 | Now, let's call the `lock` endpoint to start the game. In order to do so, we need to construct 145 | a JSON representation of the `LockParams` that the endpoint takes (look at `Game.hs`). The easiest 146 | way is to simply build the term in haskell and ask `aeson` to encode it. From the terminal: 147 | 148 | ``` 149 | cabal repl 150 | > import Plutus.Contracts.Game 151 | > import Ledger.Ada 152 | > args = LockParams { secretWord = "eagle", amount = lovelaceValueOf 90 } 153 | > import Data.Aeson 154 | > import Data.ByteString.Lazy.Char8 as BSL 155 | > BSL.putStrLn $ encode args 156 | {"amount":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},90]]]]},"secretWord":"eagle"} 157 | ``` 158 | 159 | Great! This is all we need to call the `lock` endpoint, so let's do that now with 160 | the instance from Wallet 1: 161 | 162 | 5. Lock some value (Wallet 1) 163 | 164 | ``` 165 | export INSTANCE_ID=... 166 | curl -H "Content-Type: application/json" \ 167 | --request POST \ 168 | --data '{"amount":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},90]]]]},"secretWord":"eagle"}' \ 169 | http://localhost:9080/api/contract/instance/$INSTANCE_ID/endpoint/lock 170 | ``` 171 | 172 | We can do likewise to work out what the JSON for `GuessParams` is, and then make a guess from 173 | Wallet 2: 174 | 175 | 6. Make a guess (Wallet 2) 176 | 177 | ``` 178 | export INSTANCE_ID=... 179 | curl -H "Content-Type: application/json" \ 180 | --request POST \ 181 | --data '{"guessWord": "duck"}' \ 182 | http://localhost:9080/api/contract/instance/$INSTANCE_ID/endpoint/guess 183 | ``` 184 | 185 | Note that this guess is wrong, so in the log of the server we will see that the transaction 186 | didn't validate. 187 | 188 | As an exercise, you can now spin up another instance for Wallet 2 and make a correct guess, and 189 | confirm that the transaction validates and the Ada is transferred into the right wallet. 190 | 191 | Note that you can verify the balances by looking at the log of `plutus-starter-pab` 192 | when exiting it by pressing return. 193 | 194 | Finally, also node that the PAB also exposes a websocket, which you can read about in 195 | the general [PAB Architecture documentation](https://github.com/input-output-hk/plutus-apps/blob/main/plutus-pab/ARCHITECTURE.adoc). 196 | 197 | 198 | ## Support/Issues/Community 199 | 200 | Issues can be filed in the [GitHub Issue tracker](https://github.com/input-output-hk/plutus-starter/issues). 201 | 202 | For more interactive discussion, you can join the [IOG Technical Community 203 | Discord](https://discord.gg/sSF5gmDBYg). 204 | 205 | Thanks! 206 | -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | index-state: 2022-02-22T20:47:03Z 2 | 3 | packages: ./. 4 | 5 | -- You never, ever, want this. 6 | write-ghc-environment-files: never 7 | 8 | -- Always build tests and benchmarks. 9 | tests: true 10 | benchmarks: true 11 | 12 | -- Plutus apps revision from 2022-04-06 13 | source-repository-package 14 | type: git 15 | location: https://github.com/input-output-hk/plutus-apps.git 16 | tag: v0.1.0 17 | subdir: 18 | doc 19 | freer-extras 20 | playground-common 21 | plutus-chain-index 22 | plutus-chain-index-core 23 | plutus-contract 24 | plutus-example 25 | plutus-contract-certification 26 | plutus-ledger 27 | plutus-ledger-constraints 28 | plutus-pab 29 | plutus-pab-executables 30 | plutus-playground-server 31 | plutus-script-utils 32 | plutus-streaming 33 | plutus-tx-constraints 34 | plutus-use-cases 35 | web-ghc 36 | 37 | 38 | -- The following sections are copied from the 'plutus-apps' repository cabal.project at the revision 39 | -- given above. 40 | -- This is necessary because the 'plutus-apps' libraries depend on a number of other libraries which are 41 | -- not on Hackage, and so need to be pulled in as `source-repository-package`s themselves. Make sure to 42 | -- re-update this section from the template when you do an upgrade. 43 | 44 | -- We never, ever, want this. 45 | write-ghc-environment-files: never 46 | 47 | -- Always build tests and benchmarks. 48 | tests: true 49 | benchmarks: true 50 | 51 | -- The only sensible test display option. 52 | test-show-details: streaming 53 | 54 | allow-newer: 55 | size-based:template-haskell 56 | 57 | constraints: 58 | -- Because later versions of hedgehog introduce a change which break 'cardano-ledger': 59 | -- Test/Cardano/Chain/Delegation/Model.hs:91:41: error: 60 | -- • Could not deduce (TraversableB SignalSDELEG) 61 | -- TODO: Try to remove on next `cardano-node` version upgrade. 62 | hedgehog >= 1.0.2 && < 1.1 63 | 64 | -- These packages appear in our dependency tree and are very slow to build. 65 | -- Empirically, turning off optimization shaves off ~50% build time. 66 | -- It also mildly improves recompilation avoidance. 67 | -- For deve work we don't care about performance so much, so this is okay. 68 | package cardano-ledger-alonzo 69 | optimization: False 70 | package ouroboros-consensus-shelley 71 | optimization: False 72 | package ouroboros-consensus-cardano 73 | optimization: False 74 | package cardano-api 75 | optimization: False 76 | package cardano-wallet 77 | optimization: False 78 | package cardano-wallet-core 79 | optimization: False 80 | package cardano-wallet-cli 81 | optimization: False 82 | package cardano-wallet-launcher 83 | optimization: False 84 | package cardano-wallet-core-integration 85 | optimization: False 86 | 87 | -- Direct dependency. 88 | -- Are you thinking of updating this tag to some other commit? 89 | -- Please ensure that the commit you are about to use is the latest one from 90 | -- the *develop* branch of this repo: 91 | -- * 92 | -- (not master!) 93 | -- 94 | -- In particular we rely on the code from this PR: 95 | -- * 96 | -- being merged. 97 | source-repository-package 98 | type: git 99 | location: https://github.com/input-output-hk/iohk-monitoring-framework 100 | tag: 46f994e216a1f8b36fe4669b47b2a7011b0e153c 101 | subdir: 102 | contra-tracer 103 | iohk-monitoring 104 | tracer-transformers 105 | plugins/backend-ekg 106 | plugins/backend-aggregation 107 | plugins/backend-monitoring 108 | plugins/backend-trace-forwarder 109 | 110 | -- Direct dependency. 111 | source-repository-package 112 | type: git 113 | location: https://github.com/input-output-hk/plutus 114 | tag: 6d9ac7c2f89363d574dbc10be5c2db4b661c9a43 115 | subdir: 116 | plutus-core 117 | plutus-ledger-api 118 | plutus-tx 119 | plutus-tx-plugin 120 | prettyprinter-configurable 121 | stubs/plutus-ghc-stub 122 | word-array 123 | 124 | -- Should follow plutus. 125 | source-repository-package 126 | type: git 127 | location: https://github.com/Quid2/flat 128 | tag: ee59880f47ab835dbd73bea0847dab7869fc20d8 129 | 130 | -- Direct dependency. 131 | source-repository-package 132 | type: git 133 | location: https://github.com/input-output-hk/servant-purescript 134 | tag: 44e7cacf109f84984cd99cd3faf185d161826963 135 | 136 | -- Direct dependency. 137 | source-repository-package 138 | type: git 139 | location: https://github.com/input-output-hk/purescript-bridge 140 | tag: 47a1f11825a0f9445e0f98792f79172efef66c00 141 | 142 | -- Direct dependency. 143 | -- Compared to others, cardano-wallet doesn't bump dependencies very often. 144 | -- Making it a good place to start when bumping dependencies. 145 | -- As, for example, bumping the node first highly risks breaking API with the wallet. 146 | -- Unless early bug fixes are required, this is fine as the wallet tracks stable releases of the node. 147 | -- And it is indeed nice for plutus-apps to track stable releases of the node too. 148 | source-repository-package 149 | type: git 150 | location: https://github.com/input-output-hk/cardano-wallet 151 | tag: f6d4db733c4e47ee11683c343b440552f59beff7 152 | subdir: 153 | lib/cli 154 | lib/core 155 | lib/core-integration 156 | lib/dbvar 157 | lib/launcher 158 | lib/numeric 159 | lib/shelley 160 | lib/strict-non-empty-containers 161 | lib/test-utils 162 | lib/text-class 163 | 164 | 165 | -- Should follow cardano-wallet. 166 | -- Currently tracking v1.34.1. 167 | source-repository-package 168 | type: git 169 | location: https://github.com/input-output-hk/cardano-node 170 | tag: 2b1d18c6c7b7142d9eebfec34da48840ed4409b6 171 | subdir: 172 | cardano-api 173 | cardano-cli 174 | cardano-git-rev 175 | cardano-node 176 | cardano-testnet 177 | trace-dispatcher 178 | trace-forward 179 | trace-resources 180 | 181 | source-repository-package 182 | type: git 183 | location: https://github.com/input-output-hk/ekg-forward 184 | tag: 297cd9db5074339a2fb2e5ae7d0780debb670c63 185 | 186 | source-repository-package 187 | type: git 188 | location: https://github.com/input-output-hk/cardano-config 189 | tag: e9de7a2cf70796f6ff26eac9f9540184ded0e4e6 190 | --sha256: 1wm1c99r5zvz22pdl8nhkp13falvqmj8dgkm8fxskwa9ydqz01ld 191 | 192 | -- Using a fork until our patches can be merged upstream 193 | source-repository-package 194 | type: git 195 | location: https://github.com/input-output-hk/optparse-applicative 196 | tag: 7497a29cb998721a9068d5725d49461f2bba0e7a 197 | --sha256: 1gvsrg925vynwgqwplgjmp53vj953qyh3wbdf34pw21c8r47w35r 198 | 199 | source-repository-package 200 | type: git 201 | location: https://github.com/input-output-hk/hedgehog-extras 202 | tag: edf6945007177a638fbeb8802397f3a6f4e47c14 203 | --sha256: 0wc7qzkc7j4ns2rz562h6qrx2f8xyq7yjcb7zidnj7f6j0pcd0i9 204 | 205 | -- Should follow cardano-wallet. 206 | source-repository-package 207 | type: git 208 | location: https://github.com/input-output-hk/cardano-ledger 209 | tag: 1a9ec4ae9e0b09d54e49b2a40c4ead37edadcce5 210 | subdir: 211 | eras/alonzo/impl 212 | eras/byron/chain/executable-spec 213 | eras/byron/crypto 214 | eras/byron/crypto/test 215 | eras/byron/ledger/executable-spec 216 | eras/byron/ledger/impl 217 | eras/byron/ledger/impl/test 218 | eras/shelley/impl 219 | eras/shelley/test-suite 220 | eras/shelley-ma/impl 221 | libs/cardano-data 222 | libs/cardano-ledger-core 223 | libs/cardano-ledger-pretty 224 | libs/cardano-protocol-tpraos 225 | libs/compact-map 226 | libs/non-integral 227 | libs/set-algebra 228 | libs/small-steps 229 | libs/small-steps-test 230 | 231 | -- Should follow cardano-wallet. 232 | source-repository-package 233 | type: git 234 | location: https://github.com/input-output-hk/ouroboros-network 235 | tag: 4fac197b6f0d2ff60dc3486c593b68dc00969fbf 236 | subdir: 237 | io-classes 238 | io-sim 239 | monoidal-synchronisation 240 | network-mux 241 | ntp-client 242 | ouroboros-consensus 243 | ouroboros-consensus-byron 244 | ouroboros-consensus-cardano 245 | ouroboros-consensus-protocol 246 | ouroboros-consensus-shelley 247 | ouroboros-network 248 | ouroboros-network-framework 249 | ouroboros-network-testing 250 | strict-stm 251 | typed-protocols 252 | typed-protocols-cborg 253 | typed-protocols-examples 254 | 255 | -- Should follow cardano-wallet. 256 | source-repository-package 257 | type: git 258 | location: https://github.com/input-output-hk/cardano-base 259 | tag: 41545ba3ac6b3095966316a99883d678b5ab8da8 260 | subdir: 261 | base-deriving-via 262 | binary 263 | binary/test 264 | cardano-crypto-class 265 | cardano-crypto-praos 266 | measures 267 | orphans-deriving-via 268 | slotting 269 | strict-containers 270 | 271 | -- Should follow cardano-wallet. 272 | source-repository-package 273 | type: git 274 | location: https://github.com/input-output-hk/cardano-prelude 275 | tag: bb4ed71ba8e587f672d06edf9d2e376f4b055555 276 | subdir: 277 | cardano-prelude 278 | cardano-prelude-test 279 | 280 | -- Should follow cardano-wallet. 281 | source-repository-package 282 | type: git 283 | location: https://github.com/input-output-hk/cardano-crypto 284 | tag: f73079303f663e028288f9f4a9e08bcca39a923e 285 | 286 | -- Should follow cardano-wallet. 287 | source-repository-package 288 | type: git 289 | location: https://github.com/input-output-hk/cardano-addresses 290 | tag: 71006f9eb956b0004022e80aadd4ad50d837b621 291 | subdir: 292 | command-line 293 | core 294 | 295 | -- Should follow cardano-wallet. 296 | source-repository-package 297 | type: git 298 | location: https://github.com/input-output-hk/goblins 299 | tag: cde90a2b27f79187ca8310b6549331e59595e7ba 300 | 301 | -- Should follow cardano-wallet. 302 | source-repository-package 303 | type: git 304 | location: https://github.com/input-output-hk/Win32-network 305 | tag: 3825d3abf75f83f406c1f7161883c438dac7277d 306 | 307 | -- Temporary indexing 308 | source-repository-package 309 | type: git 310 | location: https://github.com/raduom/hysterical-screams 311 | tag: 4c523469e9efd3f0d10d17da3304923b7b0e0674 312 | 313 | source-repository-package 314 | type: git 315 | location: https://github.com/input-output-hk/quickcheck-dynamic 316 | tag: c272906361471d684440f76c297e29ab760f6a1e 317 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------