Slide 1

Slide 1 text

PLUTUS Plutus and Extended UTxO Manuel M T Chakravarty, Language Architect @ IOHK

Slide 2

Slide 2 text

PLUTUS What is Plutus?

Slide 3

Slide 3 text

PLUTUS What is Plutus? Innovative development and execution platform for distributed contract applications on Cardano SL & CL.

Slide 4

Slide 4 text

PLUTUS The Three Pillars of Plutus

Slide 5

Slide 5 text

PLUTUS Safety & Security

Slide 6

Slide 6 text

PLUTUS Safety & Security Superior Ledger

Slide 7

Slide 7 text

PLUTUS Safety & Security Superior Ledger Full Stack

Slide 8

Slide 8 text

PLUTUS Safety & Security Superior Ledger Full Stack

Slide 9

Slide 9 text

PLUTUS

Slide 10

Slide 10 text

functional programming PLUTUS λ

Slide 11

Slide 11 text

functional programming with modern type systems PLUTUS λτ

Slide 12

Slide 12 text

functional programming modern type systems PLUTUS

Slide 13

Slide 13 text

functional programming modern type systems PLUTUS input output

Slide 14

Slide 14 text

functional programming modern type systems PLUTUS input output pure function side effects

Slide 15

Slide 15 text

functional programming modern type systems PLUTUS input output typed function safe usage :: ⍺ :: β

Slide 16

Slide 16 text

PLUTUS input output typed function safe usage :: ⍺ :: β local reasoning

Slide 17

Slide 17 text

PLUTUS input output typed function safe usage :: ⍺ :: β local reasoning type-directed design

Slide 18

Slide 18 text

PLUTUS input output typed function safe usage :: ⍺ :: β local reasoning type-directed design advanced testing & verification

Slide 19

Slide 19 text

PLUTUS local reasoning type-directed design advanced testing & verification }

Slide 20

Slide 20 text

PLUTUS local reasoning type-directed design advanced testing & verification } understand code behaviour

Slide 21

Slide 21 text

PLUTUS local reasoning type-directed design advanced testing & verification } understand code behaviour find exploits

Slide 22

Slide 22 text

PLUTUS core Plutus Core

Slide 23

Slide 23 text

PLUTUS core Plutus Core not a bytecode typed FP calculus

Slide 24

Slide 24 text

PLUTUS core Plutus Core not a bytecode not a classic virtual machine typed FP calculus abstract machine interpreter

Slide 25

Slide 25 text

PLUTUS core Plutus Core small, powerful & based on peer-reviewed science not a bytecode not a classic virtual machine typed FP calculus abstract machine interpreter

Slide 26

Slide 26 text

PLUTUS core Plutus Core

Slide 27

Slide 27 text

PLUTUS core Plutus Core Where is it used?

Slide 28

Slide 28 text

PLUTUS Safety & Security Superior Ledger Full Stack

Slide 29

Slide 29 text

PLUTUS Account-based Ledger UTxO-based Ledger

Slide 30

Slide 30 text

PLUTUS Account-based Ledger UTxO-based Ledger functional imperative

Slide 31

Slide 31 text

PLUTUS Account-based Ledger UTxO-based Ledger functional imperative mutable shared state dataflow

Slide 32

Slide 32 text

PLUTUS Account-based Ledger UTxO-based Ledger functional imperative mutable shared state dataflow compositional entangled

Slide 33

Slide 33 text

PLUTUS What about the expressiveness of smart contracts?

Slide 34

Slide 34 text

PLUTUS What about the expressiveness of smart contracts? Bitcoin

Slide 35

Slide 35 text

PLUTUS What about the expressiveness of smart contracts? Bitcoin Ethereum

Slide 36

Slide 36 text

PLUTUS What about the expressiveness of smart contracts? Bitcoin Ethereum minimal

Slide 37

Slide 37 text

PLUTUS What about the expressiveness of smart contracts? Bitcoin Ethereum minimal enough rope

Slide 38

Slide 38 text

PLUTUS

Slide 39

Slide 39 text

PLUTUS

Slide 40

Slide 40 text

PLUTUS Input Output

Slide 41

Slide 41 text

PLUTUS Input Output

Slide 42

Slide 42 text

PLUTUS Input Output ν: Validator x: Value core

Slide 43

Slide 43 text

PLUTUS Input Output ν: Validator x: Value ρ: Redeemer core core

Slide 44

Slide 44 text

PLUTUS Input Output ν: Validator x: Value ρ: Redeemer ν(ρ) ≟ True core core

Slide 45

Slide 45 text

PLUTUS Input Output ν: Validator x: Value ρ: Redeemer ν(ρ) ≟ True ν: Validator x: Value ρ: Redeemer core core core core

Slide 46

Slide 46 text

PLUTUS Input Output ν: Validator x: Value ρ: Redeemer ν(ρ) ≟ True ν: Validator x: Value ρ: Redeemer δ: Data core core core core core

Slide 47

Slide 47 text

PLUTUS Input Output ν: Validator x: Value ρ: Redeemer ν(ρ) ≟ True ν: Validator x: Value ρ: Redeemer δ: Data σ: State core core core core core

Slide 48

Slide 48 text

PLUTUS Input Output ν: Validator x: Value ρ: Redeemer ν(ρ) ≟ True ν: Validator x: Value ρ: Redeemer ν(ρ, δ, σ, x) ≟ True δ: Data σ: State core core core core core

Slide 49

Slide 49 text

PLUTUS ν: Validator x: Value ρ: Redeemer ν(ρ, δ, σ, x) ≟ True δ: Data σ: State Extended UTxO core core core

Slide 50

Slide 50 text

PLUTUS ν: Validator x: Value ρ: Redeemer ν(ρ, δ, σ, x) ≟ True δ: Data σ: State Extended UTxO Preserves the superior structure of UTxO ledgers core core core

Slide 51

Slide 51 text

PLUTUS ν: Validator x: Value ρ: Redeemer ν(ρ, δ, σ, x) ≟ True δ: Data σ: State Extended UTxO Preserves the superior structure of UTxO ledgers Greatly increases the expressive power of scripts core core core

Slide 52

Slide 52 text

PLUTUS Extended UTxO Preserves the superior structure of UTxO ledgers Greatly increases the expressive power of scripts

Slide 53

Slide 53 text

PLUTUS Extended UTxO Preserves the superior structure of UTxO ledgers Greatly increases the expressive power of scripts data flows with value

Slide 54

Slide 54 text

PLUTUS Extended UTxO Preserves the superior structure of UTxO ledgers Greatly increases the expressive power of scripts data flows with value scripts have an identity

Slide 55

Slide 55 text

PLUTUS Extended UTxO Preserves the superior structure of UTxO ledgers Greatly increases the expressive power of scripts data flows with value scripts have an identity invariants across transaction chains

Slide 56

Slide 56 text

PLUTUS Safety & Security Superior Ledger Full Stack

Slide 57

Slide 57 text

PLUTUS

Slide 58

Slide 58 text

PLUTUS What does it take to write a smart contract application?

Slide 59

Slide 59 text

PLUTUS Simple crowdfunding

Slide 60

Slide 60 text

PLUTUS Simple crowdfunding 1. Payment into campaign until a payment deadline

Slide 61

Slide 61 text

PLUTUS Simple crowdfunding 1. Payment into campaign until a payment deadline 2. If funding goal reached, campaign owner can collect funds

Slide 62

Slide 62 text

PLUTUS Simple crowdfunding 1. Payment into campaign until a payment deadline 2. If funding goal reached, campaign owner can collect funds 3. If funding goal not reached, refunds can be obtained by contributors

Slide 63

Slide 63 text

PLUTUS Simple crowdfunding 1. Payment into campaign until a payment deadline 2. If funding goal reached, campaign owner can collect funds 3. If funding goal not reached, refunds can be obtained by contributors 4. If campaign owner does not collect by collection deadline, contributors can also obtain refunds

Slide 64

Slide 64 text

PLUTUS 1. Payment into campaign until a payment deadline 2. If funding goal reached, campaign owner can collect funds 3. If funding goal not reached, refunds can be obtained by contributors 4. If campaign owner does not collect by collection deadline, contributors can also obtain refunds

Slide 65

Slide 65 text

PLUTUS 1. Payment into campaign until a payment deadline 2. If funding goal reached, campaign owner can collect funds 3. If funding goal not reached, refunds can be obtained by contributors 4. If campaign owner does not collect by collection deadline, contributors can also obtain refunds pragma solidity ^0.4.6; contract WinnerTakesAll { uint minimumEntryFee; uint public deadlineProjects; uint public deadlineCampaign; uint public winningFunds; address public winningAddress; struct Project { address addr; string name; string url; uint funds; bool initialized; } … Solidity (on-chain)

Slide 66

Slide 66 text

PLUTUS pragma solidity ^0.4.6; contract WinnerTakesAll { uint minimumEntryFee; uint public deadlineProjects; uint public deadlineCampaign; uint public winningFunds; address public winningAddress; struct Project { address addr; string name; string url; uint funds; bool initialized; } … Solidity (on-chain) var Web3 = require('web3'); var web3 = new Web3(); web3.setProvider(new web3.providers.HttpProvider(”http:… var accounts = web3.eth.accounts; accounts.forEach(function(v) { $(”#supportFrom”).append(”

Slide 67

Slide 67 text

PLUTUS pragma solidity ^0.4.6; contract WinnerTakesAll { uint minimumEntryFee; uint public deadlineProjects; uint public deadlineCampaign; uint public winningFunds; address public winningAddress; struct Project { address addr; string name; string url; uint funds; bool initialized; } … Solidity var Web3 = require('web3'); var web3 = new Web3(); web3.setProvider(new web3.providers.HttpProvider(”http:… var accounts = web3.eth.accounts; accounts.forEach(function(v) { $(”#supportFrom”).append(”

Slide 68

Slide 68 text

PLUTUS pragma solidity ^0.4.6; contract WinnerTakesAll { uint minimumEntryFee; uint public deadlineProjects; uint public deadlineCampaign; uint public winningFunds; address public winningAddress; struct Project { address addr; string name; string url; uint funds; bool initialized; } … Solidity var Web3 = require('web3'); var web3 = new Web3(); web3.setProvider(new web3.providers.HttpProvider(”http:… var accounts = web3.eth.accounts; accounts.forEach(function(v) { $(”#supportFrom”).append(”

Slide 69

Slide 69 text

PLUTUS pragma solidity ^0.4.6; contract WinnerTakesAll { uint minimumEntryFee; uint public deadlineProjects; uint public deadlineCampaign; uint public winningFunds; address public winningAddress; struct Project { address addr; string name; string url; uint funds; bool initialized; } … Solidity var Web3 = require('web3'); var web3 = new Web3(); web3.setProvider(new web3.providers.HttpProvider(”http:… var accounts = web3.eth.accounts; accounts.forEach(function(v) { $(”#supportFrom”).append(”

Slide 70

Slide 70 text

PLUTUS Solidity JavaScript off-chain (wallet) on-chain (transaction) two-level (staged) programming model ad hoc

Slide 71

Slide 71 text

PLUTUS Solidity JavaScript off-chain (wallet) on-chain (transaction) two-level (staged) programming model ad hoc inconvenient

Slide 72

Slide 72 text

PLUTUS Solidity JavaScript off-chain (wallet) on-chain (transaction) two-level (staged) programming model ad hoc inconvenient complex

Slide 73

Slide 73 text

PLUTUS Solidity JavaScript off-chain (wallet) on-chain (transaction) two-level (staged) programming model ad hoc inconvenient complex fragile

Slide 74

Slide 74 text

PLUTUS off-chain (wallet) on-chain (transaction) two-level (staged) programming model

Slide 75

Slide 75 text

PLUTUS Haskell off-chain (wallet) on-chain (transaction) two-level (staged) programming model

Slide 76

Slide 76 text

PLUTUS Haskell (Plutus Tx) Haskell off-chain (wallet) on-chain (transaction) two-level (staged) programming model

Slide 77

Slide 77 text

PLUTUS Haskell (Plutus Tx) Haskell off-chain (wallet) on-chain (transaction) two-level (staged) programming model meta programming

Slide 78

Slide 78 text

PLUTUS Haskell (Plutus Tx) Haskell off-chain (wallet) on-chain (transaction) two-level (staged) programming model meta programming integrated

Slide 79

Slide 79 text

PLUTUS Haskell (Plutus Tx) Haskell off-chain (wallet) on-chain (transaction) two-level (staged) programming model meta programming integrated compact

Slide 80

Slide 80 text

PLUTUS Haskell (Plutus Tx) Haskell off-chain (wallet) on-chain (transaction) two-level (staged) programming model meta programming integrated compact robust

Slide 81

Slide 81 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do Haskell

Slide 82

Slide 82 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" Haskell

Slide 83

Slide 83 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey Haskell

Slide 84

Slide 84 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript Haskell

Slide 85

Slide 85 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript (Ledger.scriptAddress (contributionScript campaign)) Haskell

Slide 86

Slide 86 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript (Ledger.scriptAddress (contributionScript campaign)) value Haskell

Slide 87

Slide 87 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript (Ledger.scriptAddress (contributionScript campaign)) value DataScript (Ledger.lifted ownPK) Haskell

Slide 88

Slide 88 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript (Ledger.scriptAddress (contributionScript campaign)) value DataScript (Ledger.lifted ownPK) register (refundTrigger campaign) (refundHandler (Ledger.hashTx tx) campaign) contributionScript :: Campaign -> ValidatorScript Haskell

Slide 89

Slide 89 text

PLUTUS Haskell contributionScript :: Campaign -> ValidatorScript

Slide 90

Slide 90 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = Haskell

Slide 91

Slide 91 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Haskell

Slide 92

Slide 92 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> Plutus Tx Haskell

Slide 93

Slide 93 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx Plutus Tx Haskell

Slide 94

Slide 94 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Plutus Tx Haskell

Slide 95

Slide 95 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && Plutus Tx Haskell

Slide 96

Slide 96 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && Plutus Tx Haskell

Slide 97

Slide 97 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Plutus Tx Haskell

Slide 98

Slide 98 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && Plutus Tx Haskell

Slide 99

Slide 99 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && h <= collectionDeadline && Plutus Tx Haskell

Slide 100

Slide 100 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && h <= collectionDeadline && totalInputs >= target && Plutus Tx Haskell

Slide 101

Slide 101 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && h <= collectionDeadline && totalInputs >= target && $$(txSignedBy) p campaignOwner Plutus Tx Haskell

Slide 102

Slide 102 text

PLUTUS contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && h <= collectionDeadline && totalInputs >= target && $$(txSignedBy) p campaignOwner in $$(P.errorIfNot) isValid ||]) Plutus Tx Haskell

Slide 103

Slide 103 text

PLUTUS Safety & Security Superior Ledger Full Stack

Slide 104

Slide 104 text

PLUTUS Safety & Security Superior Ledger Full Stack

Slide 105

Slide 105 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript (Ledger.scriptAddress (contributionScript campaign)) value DataScript (Ledger.lifted ownPK) register (refundTrigger campaign) (refundHandler (Ledger.hashTx tx) campaign) contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && h <= collectionDeadline && totalInputs >= target && $$(txSignedBy) p campaignOwner in $$(P.errorIfNot) isValid ||]) off-chain on-chain

Slide 106

Slide 106 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript (Ledger.scriptAddress (contributionScript campaign)) value DataScript (Ledger.lifted ownPK) register (refundTrigger campaign) (refundHandler (Ledger.hashTx tx) campaign) contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && h <= collectionDeadline && totalInputs >= target && $$(txSignedBy) p campaignOwner in $$(P.errorIfNot) isValid ||]) core off-chain on-chain

Slide 107

Slide 107 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript (Ledger.scriptAddress (contributionScript campaign)) value DataScript (Ledger.lifted ownPK) register (refundTrigger campaign) (refundHandler (Ledger.hashTx tx) campaign) contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && h <= collectionDeadline && totalInputs >= target && $$(txSignedBy) p campaignOwner in $$(P.errorIfNot) isValid ||]) core core off-chain on-chain

Slide 108

Slide 108 text

PLUTUS contribute :: Campaign -> Value -> MockWallet () contribute campaign value = do when (value <= 0) $ throwOtherError "Must contribute a positive value" ownPK <- ownPubKey tx <- payToScript (Ledger.scriptAddress (contributionScript campaign)) value DataScript (Ledger.lifted ownPK) register (refundTrigger campaign) (refundHandler (Ledger.hashTx tx) campaign) contributionScript :: Campaign -> ValidatorScript contributionScript campaign = ValidatorScript (validator `apply` campaign) where validator = Ledger.fromCompiledCode $$(PlutusTx.compile [|| (\Campaign{..} action contrib tx -> let PendingTx ps outs _ _ (Height h) _ _ = tx isValid = case action of Refund -> h > collectionDeadline && contributorOnly outs && $$(txSignedBy) tx contrib Collect -> h > deadline && h <= collectionDeadline && totalInputs >= target && $$(txSignedBy) p campaignOwner in $$(P.errorIfNot) isValid ||]) core core off-chain on-chain

Slide 109

Slide 109 text

PLUTUS This is Plutus! Safety & Security Superior Ledger Full Stack