Skip to content

Latest commit

 

History

History

M08-bring-it-on

title author
M08 - Bring it on
Walker Leite

Introduction

Getting Started

In this module we'll build the most common off-chain code for a smart contract on Cardano.

To run this presentation type (you will need nix):

../../slide README.md

Community Support

Module Video

Requisites

  1. Plutus
    • You should be familiar with EUTxO Model (module 1);
    • You should be able to serialize plutus code (module 6);
  2. Nix
    • You should be familiar with Nix Language (module 3);
    • You should be familiar with Nix Flakes (module 3);
  3. PureScript
    • You should be familiar with Foreign Function Interface (module 7);
    • You should be familiar with MonadEffect, MonadAff (module 7);
    • You should be familiar with Halogen (module 7);

Optional, but recommended:

Cardano Transaction Lib

Architecture

Frontend:

(Browser) Wallet - CTL - CSL
                    |
Backend:            |
                    |
Ogmius (WebSocket) -|- Ogmius Datum Cache
                    |
                  Kopu 
  • CTL is a Purescript library/interface for building smart contract transactions on Cardano.
  • CSL is a WASM library to serialize and unserialize plutus compatible data. We don't use it directly.
  • Ogmius is a service to query the blockchain using websocket protocol. We don't use it directly.
  • Ogmius Datum Cache is a service to store datum values for V1 (non-vasil) contracts. We don't use it directly.
  • Kopu: is a chain-index to query the blockchain using HTTP protocol. We don't use it directly.

The Contract Monad

The Contract is a newtype wrapper around QueryM, which is a ReaderT on QueryEnv over Aff:

newtype Contract (r :: Row Type) (a :: Type)

-- constructor
Contract (QueryMExtended r Aff a)

newtype QueryMExtended (r :: Row Type) (m :: Type -> Type) (a :: Type)

-- constructor
QueryMExtended (ReaderT (QueryEnv r) m a)

The r :: Row Type defines the type of extraConfig field of the underlying given value for ReaderT:

type QueryEnv (r :: Row Type) = { config :: QueryConfig, extraConfig :: Record r, runtime :: QueryRuntime }

The Contract Monad - Example

Whenever we define a Contract type signature, we need to pass the extraConfig type or a placeholder and the returning value of the monad:

type ExtraConfig = { foo :: String }

submitTx :: Contract ExtraConfig TransactionHash
submitTx = do
  cfg <- ask
  logInfo' $ "Foo: " <> show cfg.foo
  txId <- submit ?bsTx
  logInfo' $ "Tx ID: " <> show txId
  pure txId

To run, we need to pass a valid config (with extraConfig set):

main :: Effect Unit
main = launchAff_ do
  txId <- runContract {..., extraConfig = { foo = "bar" } } submitTx
  log $ show txId
launchAff_ :: forall a. Aff a -> Effect Unit
runContract :: forall (r :: Row Type) (a :: Type). ConfigParams r -> Contract r a -> Aff a

Using a Validator

lock :: forall r. Int -> Contract r TransactionHash
lock amount = do
  validator <- ?toValidator :: Contract r Validator
  let lookups = SL.validator validator
  buildBalanceSignAndSubmitTx lookups ?constraints
newtype Validator = Validator PlutusScript
toValidator :: Either Error Validator
toValidator = wrap <$> ?parseScript

💡 Notice Error matching MonadError Error (Contract r).

Plutus Script Parser

parseScript :: Either Error PlutusScript
parseScript = plutusV2Script
  <$> (lmap (error <<< printTextEnvelopeDecodeError) $ textEnvelopeBytes ?script PlutusScriptV2)
data TextEnvelopeType = PlutusScriptV1 | PlutusScriptV2

textEnvelopeBytes :: String -> TextEnvelopeType -> Either TextEnvelopeDecodeError ByteArray

printTextEnvelopeDecodeError :: TextEnvelopeDecodeError -> String

lmap :: forall f a b c. Bifunctor f => (a -> b) -> f a c -> f b c

plutusV2Script :: ByteArray -> PlutusScript

Plutus Script FFI

// Script.js
exports.script = require("Scripts/always-succeeds-v2.plutus");

⚠️ Your loader must know how to require a plutus file

-- Script.purs
foreign import script :: String

Breakthrough

User Story: As a donator I want to give any amount of ADAs to the first visitor

Scenario

  1. Donator integrates his wallet
  2. Donator locks n ADA into Script Address
  3. Visitor see avaliable n ADA
  4. Visitor integrates his wallet
  5. Visitor grabs all ADA

Bootstrap

cd modules/M08-bring-it-on
nix flake init -t github:LovelaceAcademy/nix-templates#pix-ctl-full
git init
git add --all
nix develop
npm install
git add --all
git commit -m "Initial commit"

CLI wallet on Preview with covering funds

  • Create donator.{skey,vkey,addr} with given cardano-cli
  • Create visitor.{skey,vkey,addr} with given cardano-cli
  • Send test ADA to donator and visitor address Faucet