|
| 1 | +--- |
| 2 | +sidebar_position: 1 |
| 3 | +--- |
| 4 | + |
| 5 | +# Plutus Ledger Language Version (Plutus V1/V2/V3) |
| 6 | + |
| 7 | +As explained in [Different Notions of Version](../essential-concepts/versions.md), Plutus V1, V2 and V3 are not distinct programming languages; the primary difference lies in the arguments the script receives from the ledger, and the value it returns. |
| 8 | +Therefore, Plutus V1, V2 and V3 can be understood as type signatures, in the sense that they each represent a subset of Untyped Plutus Core (UPLC) programs with specific types. |
| 9 | +Any UPLC program that matches the expected argument and return types can be considered and used as a Plutus V1, V2 or V3 script. |
| 10 | + |
| 11 | +Next we'll start with a brief overview of the script context, followed by an in-depth explanation of these type signatures. |
| 12 | + |
| 13 | +## ScriptContext |
| 14 | + |
| 15 | +Every Plutus script receives an argument called script context. |
| 16 | +It contains information about the transaction the script is validating, such as inputs, outputs, transaction fee, signatures and so on. |
| 17 | +Additionally, since a transaction may have multiple things to validate (e.g., it may be spending multiple script UTXOs, or performing both spending and minting), each of which is validated by a separate script, the script context also has a script purpose field, telling the script what exactly it is supposed to validate. |
| 18 | + |
| 19 | +Plutus V1, V2 and V3 scripts receive different script contexts even when all else is equal. |
| 20 | +This is because different ledger language versions are introduced in different ledger eras; transactions in different ledger eras have different fields - a new era usually adds new fields and may also change existing fields. |
| 21 | +As a result, The script contexts for Plutus V1, V2 and V3 also have different fields, leading to different Haskell types ([V1](https://plutus.cardano.intersectmbo.org/haddock/master/plutus-ledger-api/PlutusLedgerApi-V1-Contexts.html#t:ScriptContext), [V2](https://plutus.cardano.intersectmbo.org/haddock/master/plutus-ledger-api/PlutusLedgerApi-V2-Contexts.html#t:ScriptContext), [V3](https://plutus.cardano.intersectmbo.org/haddock/master/plutus-ledger-api/PlutusLedgerApi-V3-Contexts.html#t:ScriptContext)). |
| 22 | +We cannot modify the script context fields of an existing ledger language version once it is published, since it would break existing scripts. |
| 23 | + |
| 24 | +In general, a ledger language version cannot be used in a transaction, if the ledger language version was introduced in ledger era A, the transaction uses features in ledger era B, and A is earlier than B. |
| 25 | +For instance, Plutus V1 (introduced in the Alonzo era) scripts cannot be used in a transaction which utilizes inline datum (a Babbage era feature); Plutus V2 (introduced in the Babbage era) scripts cannot be used in a transaction that registers a DRep (introduced in the Conway era)[^1]. |
| 26 | + |
| 27 | + |
| 28 | +## Plutus V1 and Plutus V2 |
| 29 | + |
| 30 | +Plutus V1 and Plutus V2 scripts have four [script purposes](https://plutus.cardano.intersectmbo.org/haddock/master/plutus-ledger-api/PlutusLedgerApi-V1-Contexts.html#t:ScriptPurpose): spending, minting, certifying, and rewarding[^2]. |
| 31 | +The arguments a Plutus V1 or V2 script receives depend on the script purpose. |
| 32 | +There is no requirement on the return value of a Plutus V1 and V2 script: script evaluation succeeds as long as the evaluation terminates without error, and the execution budget is not exceeded. |
| 33 | + |
| 34 | +### Spending Scripts |
| 35 | + |
| 36 | +A Plutus V1/V2 spending script receives three arguments corresponding to datum, redeemer and script context. |
| 37 | +All arguments are encoded as `BuiltinData`. |
| 38 | +Thus in Plutus Tx, a spending script has the following type: |
| 39 | + |
| 40 | +```haskell |
| 41 | +BuiltinData -> BuiltinData -> BuiltinData -> any |
| 42 | +``` |
| 43 | + |
| 44 | +To create a Plutus script using Plutus Tx, it is common to first write a function that takes the corresonding Haskell domain types and returns `Bool`. |
| 45 | +For example, the following function can be used to implement the main business logic of a Plutus V1 spending script: |
| 46 | + |
| 47 | +```haskell |
| 48 | +myV1SpendingScriptTyped :: MyDatum -> MyRedeemer -> PlutusLedgerApi.V1.ScriptContext -> Bool |
| 49 | +``` |
| 50 | + |
| 51 | +where `MyDatum` and `MyRedeemer` are your user-defined Haskell types specific to your contract. |
| 52 | +If you are writing a Plutus V2 script, use `PlutusLedgerApi.V2.ScriptContext`. |
| 53 | + |
| 54 | +From `myV1SpendingScriptTyped`, you can obtain `BuiltinData -> BuiltinData -> BuiltinData -> any`, and subsequently compile it to UPLC, via |
| 55 | + |
| 56 | +```haskell |
| 57 | +myV1SpendingScriptUntyped :: BuiltinData -> BuiltinData -> BuiltinData -> BuiltinUnit |
| 58 | +myV1SpendingScriptUntyped myDatum myRedeemer scriptContext = |
| 59 | + PlutusTx.Prelude.check |
| 60 | + ( myV1SpendingScriptTyped |
| 61 | + (PlutusTx.unsafeFromBuiltinData myDatum) |
| 62 | + (PlutusTx.unsafeFromBuiltinData myRedeemer) |
| 63 | + (PlutusTx.unsafeFromBuiltinData scriptContext) |
| 64 | + ) |
| 65 | + |
| 66 | +myV1SpendingScriptCompiled :: CompiledCode (BuiltinData -> BuiltinData -> BuiltinData -> BuiltinUnit) |
| 67 | +myV1SpendingScriptCompiled = $$(PlutusTx.compile [||myV1SpendingScriptUntyped||]) |
| 68 | +``` |
| 69 | + |
| 70 | +`unsafeFromBuiltinData` is a method from the [`UnsafeFromData`](http://localhost:3000/docs/working-with-scripts/ledger-language-version) class. |
| 71 | +Each call to `unsafeFromBuiltinData` decodes a `BuiltinData` into a value of a Haskell domain type, failing if the conversion fails. |
| 72 | +The `check` function takes a `Bool` and returns a `BuiltinUnit`, throwing an error if the input is `False`. |
| 73 | +It is needed because returning `False` does not cause the validation to fail; to fail the validation, an error needs to be thrown. |
| 74 | + |
| 75 | +In this example the script happens to return `BuiltinUnit`, but this is not a requirement for Plutus V1 or V2. |
| 76 | + |
| 77 | +### Minting, Certifying and Rewarding Scripts |
| 78 | + |
| 79 | +Unlike spending scripts, Plutus V1 and V2 scripts for minting, certifying and rewarding purposes take one fewer argument: there is no datum argument. |
| 80 | +Thus in Plutus Tx, a minting, certifying or rewarding script should have the following type: |
| 81 | + |
| 82 | +```haskell |
| 83 | +BuiltinData -> BuiltinData -> any |
| 84 | +``` |
| 85 | + |
| 86 | +Since this type signature is shared by minting, certifying and rewarding scripts, the same script can be used for multiple of these three purposes, for example |
| 87 | + |
| 88 | +```haskell |
| 89 | +myV1MintingAndRewardingScriptTyped :: MyRedeemer -> PlutusLedgerApi.V1.ScriptContext -> Bool |
| 90 | +myV1MintingAndRewardingScriptTyped myRedeemer scriptContext = |
| 91 | + case scriptContextPurpose scriptContext of |
| 92 | + Minting cs -> -- Perform minting validation |
| 93 | + Rewarding cred -> -- Perform rewarding validation |
| 94 | +``` |
| 95 | + |
| 96 | +Because spending scripts take one more argument, the same script cannot be used both for spending validation and for a different purpose (minting, certifying or rewarding). |
| 97 | + |
| 98 | +### Script Evaluation and Unsaturated Scripts |
| 99 | + |
| 100 | +As said before, evaluating a Plutus V1 and V2 script succeeds as long as the evaluation terminates without error, and the budget is not exceeded. |
| 101 | + |
| 102 | +This means, crucially, that an unsaturated script (a script expecting more arguments than it receives) succeeds trivially, since the evaluation terminates almost immediately and returns a lambda. |
| 103 | +Thus be careful: if, for example, you accidentally use a spending script (which expects three arguments) as a minting script (which will receive two arguments), it will always succeed, which is obviously not what you want. |
| 104 | + |
| 105 | +## Plutus V3 |
| 106 | + |
| 107 | +Plutus V3 has two additional [script purposes](https://plutus.cardano.intersectmbo.org/haddock/master/plutus-ledger-api/PlutusLedgerApi-V3-Contexts.html#t:ScriptPurpose) for validating governance actions: voting and proposing. |
| 108 | + |
| 109 | +Besides the usual differences between different Plutus ledger language versions, there are three additional key differences between Plutus V3 and V1/V2: |
| 110 | + |
| 111 | +1. All Plutus V3 scripts, regardless of script purpose, take a single argument: the script context. |
| 112 | + The datum (for spending scripts) and the redeemer are part of the Plutus V3 script context. |
| 113 | + This means the same script can be used for spending validation and for different purposes. |
| 114 | +2. The datum is now optional for spending scripts. |
| 115 | + The script context may or may not contain a datum, depending on whether the UTXO being spent has a datum associated with it. |
| 116 | +3. There is an additional condition for the evaluation of a Plutus V3 script to be considered successful: the return value must be a `BuiltinUnit`. |
| 117 | + |
| 118 | +The first two points are attributed to [CIP-69](https://developers.cardano.org/docs/governance/cardano-improvement-proposals/cip-0069/), whereas the third point is attributed to [CIP-117](https://developers.cardano.org/docs/governance/cardano-improvement-proposals/cip-0117/). |
| 119 | + |
| 120 | +In other words, all Plutus V3 scripts should have the following type in Plutus Tx: |
| 121 | + |
| 122 | +```haskell |
| 123 | +BuiltinData -> BuiltinUnit |
| 124 | +``` |
| 125 | + |
| 126 | +Updating a Plutus V1/V2 script to turn it into a Plutus V3 script mostly involves straightforward refactoring, except that for a spending script, the case where the datum is absent will need to be handled. |
| 127 | + |
| 128 | +--- |
| 129 | + |
| 130 | +[^1]: There is one exception to this: Plutus V1 can be used in transactions with reference inputs, even though reference inputs were introduced in the Babbage era. |
| 131 | + |
| 132 | +[^2]: For more information on script purposes, refer to [Script Purposes](script-purposes.md). |
0 commit comments