Skip to content

Commit

Permalink
Merge pull request #1628 from Plutonomicon/klntsky/new-constraints-in…
Browse files Browse the repository at this point in the history
…terface

New constraints interface
  • Loading branch information
klntsky authored Jul 23, 2024
2 parents 2c8e8fb + 25a2703 commit 3a0e43b
Show file tree
Hide file tree
Showing 86 changed files with 2,103 additions and 3,123 deletions.
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [[Unreleased]](#unreleased)
- [Deprecated](#deprecated)
- [Added](#added)
- [Removed](#removed)
- [Changed](#changed)
Expand Down Expand Up @@ -69,14 +70,33 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## [Unreleased]

### Deprecated

> [!WARNING]
> **IMPORTANT** Constraints interface (`Contract.TxConstraints` & `Contract.ScriptLookups`) has been deprecated and will be removed in a future version. Please use [`purescript-cardano-transaction-builder`](https://github.com/mlabs-haskell/purescript-cardano-transaction-builder) (via `Contract.Transaction.buildTx`) for new contracts. The motivation for deprecation is that it was unnecessarily complex, not flexible enough, and existed only because of the desire to provide code-level compatibility with PAB. See [this Catalyst proposal](https://cardano.ideascale.com/c/idea/101478) for more info.
### Added

- `Contract.Transaction.buildTx :: Array TransactionBuilderStep -> Contract Transaction` that provides a `Contract`-based interface for the [new transaction builder](https://github.com/mlabs-haskell/purescript-cardano-transaction-builder).
- `submitTxFromBuildPlan :: UtxoMap -> BalanceTxConstraintsBuilder -> Array TransactionBuilderStep -> Contract Transaction` - a convenience function that executes the whole transaction creation pipeline starting from a build plan for [the new transaction builder](https://github.com/mlabs-haskell/purescript-cardano-transaction-builder).
- `Contract.ClientError.pprintClientError` to provide readable error reports.
- `Contract.Staking.getStakeCredentialDelegationsAndRewards` utility function

### Removed

- `Contract.Scripts.applyArgs` - use `Cardano.Plutus.ApplyArgs.applyArgs` from [purescript-uplc-apply-args](https://github.com/mlabs-haskell/purescript-uplc-apply-args)
- **IMPORTANT** `UnbalancedTx` type has been removed. This change was motivated by the fact that `UnbalancedTx` existed simply to tie together transaction building and balancing by keeping extra context. Now that transaction builder is placed in [its own package](https://github.com/mlabs-haskell/purescript-cardano-transaction-builder), there is no more need in `UnbalancedTx`, that is not used with the new builder.
- **IMPORTANT** `Contract.Scripts.applyArgs` - use `Cardano.Plutus.ApplyArgs.applyArgs` from [purescript-uplc-apply-args](https://github.com/mlabs-haskell/purescript-uplc-apply-args)
- **IMPORTANT** `balanceTxWithConstraints` - use `balanceTx`
- `Contract.Transaction.submitTxFromConstraintsReturningFee` - too niche use case to be allowed in the public API.
- `Contract.Transaction` lens values. Use lenses from `Cardano.Types.Transaction`

### Changed

- `Contract.Transaction.mkUnbalancedTx` now returns a tuple: a transaction and its used UTxOs.
- `Contract.Transaction.balanceTx` accepts two extra argument: a list of used UTxOs (set to `Data.Map.empty` if none of them are coming from the outside of the wallet) and balancer constraints (set to `mempty` if not needed)
- Default synchronization parameters: all [wallet <-> query layer synchronization primitives](./doc/query-layers.md) are now off by default. The reason is that the runtime overhead made the users unhappy and it was not worth it for most of the users. If your dApp sends transactions in quick succession, consider enabling the synchronization again.
- `BalanceTxConstraintsBuilder` has been renamed to `BalancerConstraints`. It is still available under the old name as a type synonym.

### Fixed

## [v8.0.0]
Expand Down
31 changes: 6 additions & 25 deletions doc/babbage-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,29 @@ This document is a reference/explainer for the new CTL APIs introduced for Babba
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Reference Inputs](#reference-inputs)
- [Reference Scripts](#reference-scripts)
- [Reference Inputs & Reference Scripts](#reference-inputs--reference-scripts)
- [Inline Data](#inline-data)
- [Collateral Output](#collateral-output)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Reference Inputs
## Reference Inputs & Reference Scripts

[Reference inputs](https://cips.cardano.org/cip/CIP-0031#reference-inputs) allow looking at an output without spending it in Plutus scripts.

There are two ways to use an input as a reference in the constraints API:

1. via `mustReferenceOutput`, which allows Plutus scripts to access the information (e.g. datum, locked value) contained in the output.

[Usage example](../examples/PlutusV2/ReferenceInputs.purs)

2. by providing constraints which accept a value of the type `InputWithScriptRef` with the `RefInput` constructor. These allow scripts (validating or minting) to be reused by reference between multiple transactions without including them in those transactions, explained further in [Reference Scripts](#reference-scripts).

[Usage example](../examples/PlutusV2/ReferenceInputsAndScripts.purs)

## Reference Scripts

[Reference Scripts](https://cips.cardano.org/cip/CIP-0033) allows the use of scripts without attaching them to the transaction (and using a reference instead).

Reference scripts can be utilized in CTL by first creating a reference point for the script to be used later via `mustPayToScriptWithScriptRef` (or its variants).
Reference scripts can be utilized in CTL by first creating a UTxO containing the script to be used later.

This constraint utilises a new `ScriptRef` type that includes either a native script or a Plutus script.

Then, `mustSpendScriptOutputUsingScriptRef` (or its variants) can be used to use a reference script. It accepts a value of type `InputWithScriptRef` that specifies whether the UTxO with the reference script should be spent or referenced.

[Usage example](../examples/PlutusV2/ReferenceScripts.purs)
[Usage example](../examples/PlutusV2/ReferenceInputsAndScripts.purs)

## Inline Data

[CIP-32](https://cips.cardano.org/cip/CIP-0032) introduces the inline data feature that allows storing datum values directly in transaction outputs, instead of just the hashes.

In CTL, alternating between datum storage options can be achieved by specifying a `DatumPresence` value with constraints that accept it, like `mustPayToPubKeyWithDatum`.

[Usage example](../examples/PlutusV2/InlineDatum.purs)

## Collateral Output

[CIP-40](https://cips.cardano.org/cip/CIP-0040) introduces explicit collateral output. On validation failure, previously the entire collateral was consumed. Now, if excess collateral is supplied, even with native assets, the surplus can be returned on validation failure.

Collateral output is automatically added to transactions in CTL. To trigger a collateral return, the `mustNotBeValid` constraint should be explicitly specified, otherwise a script error would be detected earlier and the transaction will not be sent.

[Usage example](../examples/Lose7Ada.purs)
6 changes: 3 additions & 3 deletions doc/balancing.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Configuring balancing process](#configuring-balancing-process)
- [Configuring the balancing process](#configuring-the-balancing-process)
- [Balancer constraints](#balancer-constraints)
- [Concurrent spending](#concurrent-spending)
- [Balancing a Tx for other wallet](#balancing-a-tx-for-other-wallet)
Expand All @@ -10,7 +10,7 @@

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

# Configuring balancing process
# Configuring the balancing process

Transaction balancing in Cardano is the process of finding a set of inputs and outputs that that sum up to zero, covering all the required fees for the transaction to be valid.

Expand All @@ -37,7 +37,7 @@ Setting `mustUseUtxosAtAddress`, `mustSendChangeToAddress` and `mustUseCollatera

## Synchronization

Before balancing, CTL tries to synchronize the wallet state with the query layer, i.e. waits until all UTxOs that the wallet returns are visible in the query layer. Thus the situation when the query layer refuses to validate a Tx (either during ex-units evaluation or on Tx submission) is only possible due to a rollback or a synchronization timeout. Please see [our docs for query layer synchronization](./query-layers.md).
It's possible to make CTL try to synchronize the wallet state with the query layer, i.e. wait until all UTxOs that the wallet returns are visible in the query layer. Thus the situation when the query layer refuses to validate a Tx (either during ex-units evaluation or on Tx submission) is only possible due to a rollback or a synchronization timeout. Please see [our docs for query layer synchronization](./query-layers.md).

## Balancing process limitations

Expand Down
10 changes: 10 additions & 0 deletions doc/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This document outlines development workflows for CTL itself. You may also wish t
- [JS](#js)
- [Switching development networks](#switching-development-networks)
- [Maintaining the template](#maintaining-the-template)
- [Updating the template](#updating-the-template)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -148,4 +149,13 @@ Set new `network.name` and `network.magic` in `runtime.nix`. Also see [Changing

[The template](../templates/ctl-scaffold/) must be kept up-to-date with the repo. Although there are some checks for common problems in CI, it's still possible to forget to update the `package-lock.json` file.

## Updating the template

1. Update the revision of CTL in the template's `flake.nix`
2. Update the npm packages in the `package.json` (if needed)
3. Run `npm i` to update the lockfile (if there are NPM dependency version changes)
4. Update the revisions in the template's `packages.dhall` (CTL version must match the one in `flake.nix`)
5. Run `spago2nix generate`
6. Run `nix develop`

[This helper script](../scripts/template-check.sh) can be used to make sure the template can be initialized properly from a given revision.
53 changes: 26 additions & 27 deletions doc/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ This guide will help you get started writing contracts with CTL. Please also see
- [Executing contracts and the `ContractEnv`](#executing-contracts-and-the-contractenv)
- [Making the `ContractEnv`](#making-the-contractenv)
- [Building and submitting transactions](#building-and-submitting-transactions)
- [Using compiled scripts](#using-compiled-scripts)
- [Testing](#testing)
- [Without a light wallet](#without-a-light-wallet)
- [With a light wallet](#with-a-light-wallet)
- [Plutip integration](#plutip-integration)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -140,9 +135,13 @@ main = Contract.Monad.launchAff_ do -- we re-export this for you
, kupoConfig: defaultKupoServerConfig
}
, networkId: TestnetId
, logLevel: Trace
, walletSpec: Just ConnectToNami
, logLevel: Trace
, customLogger: Nothing
, suppressLogs: false
, hooks: emptyHooks
, timeParams: defaultTimeParams
, synchronizationParams: defaultSynchronizationParams
}
runContract config someContract
Expand All @@ -167,49 +166,49 @@ customOgmiosWsConfig =

Unlike PAB, CTL obscures less of the build-balance-sign-submit pipeline for transactions and most of the steps are called individually. The general workflow in CTL is similar to the following:

- Build a transaction using `Contract.ScriptLookups`, `Contract.TxConstraints` and `Contract.BalanceTxConstraints` (it is also possible to directly build a `Transaction` if you require even greater low-level control over the process, although we recommend the constraints/lookups approach for most users):
- Build a transaction using [`cardano-transaction-builder`](https://github.com/mlabs-haskell/purescript-cardano-transaction-builder):

```purescript
contract = do
let
constraints :: TxConstraints Unit Unit
constraints =
TxConstraints.mustPayToScript vhash unitDatum
(Value.lovelaceValueOf $ BigInt.fromInt 2_000_000)
lookups :: ScriptLookups PlutusData
lookups = ScriptLookups.validator validator
balanceTxConstraints :: BalanceTxConstraints.BalanceTxConstraintsBuilder
balanceTxConstraints =
BalanceTxConstraints.mustUseUtxosAtAddress address
<> BalanceTxConstraints.mustSendChangeToAddress address
<> BalanceTxConstraints.mustNotSpendUtxoWithOutRef nonSpendableOref
-- `liftedE` will throw a runtime exception on `Left`s
unbalancedTx <- liftedE $ Lookups.mkUnbalancedTx lookups constraints
plan =
[ Pay $ TransactionOutput
{ address: address
, amount: Value.lovelaceValueOf $ BigNum.fromInt 1_000_000
, datum: Just $ OutputDatumHash $ hashPlutusData PlutusData.unit
, scriptRef: Nothing
}
]
unbalancedTx <- buildTx plan
...
```

- Balance it using `Contract.Transaction.balanceTx` (or `Contract.Transaction.balanceTxWithConstraints` if you need to adjust the balancer behaviour) and then sign it using `signTransaction`:
- Balance it using `Contract.Transaction.balanceTx`, and then sign it using `signTransaction`:
```purescript
contract = do
...
let
balanceTxConstraints :: BalanceTxConstraints.BalanceTxConstraintsBuilder
balanceTxConstraints =
BalanceTxConstraints.mustUseUtxosAtAddress address
<> BalanceTxConstraints.mustSendChangeToAddress address
<> BalanceTxConstraints.mustNotSpendUtxoWithOutRef nonSpendableOref
-- `liftedE` will throw a runtime exception on `Left`s
balancedTx <-
liftedE $ balanceTxWithConstraints unbalancedTx balanceTxConstraints
balanceTx unbalancedTx usedUtxos balanceTxConstraints
balancedSignedTx <- signTransaction balancedTx
...
```

- Submit using `Contract.Transaction.submit`:
- Submit using `Contract.Transaction.submit` and await for confirmation using `awaitTxConfirmed`:

```purescript
contract = do
...
txId <- submit balancedSignedTx
awaitTxConfirmed txId
logInfo' $ "Tx ID: " <> show txId
```
```

### Using compiled scripts

Expand Down
50 changes: 12 additions & 38 deletions doc/plutus-comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ This document outlines the core differences between CTL and Plutus Application B
- [Library vs. process](#library-vs-process)
- [The `Contract` type](#the-contract-type)
- [API differences](#api-differences)
- [Transaction manipulation API](#transaction-manipulation-api)
- [Constraints and lookups](#constraints-and-lookups)
- [Babbage-era constraints](#babbage-era-constraints)
- [Typed scripts](#typed-scripts)
- [DEPRECATION WARNING](#deprecation-warning)
- [**DEPRECATED** Transaction manipulation API](#deprecated-transaction-manipulation-api)
- [**DEPRECATED** Constraints and lookups](#deprecated-constraints-and-lookups)
- [**DEPRECATED** Babbage-era constraints](#deprecated-babbage-era-constraints)
- [Working with scripts](#working-with-scripts)
- [Using scripts from the frontend](#using-scripts-from-the-frontend)
- [Applying arguments to parameterized scripts](#applying-arguments-to-parameterized-scripts)
Expand All @@ -25,7 +25,7 @@ This document outlines the core differences between CTL and Plutus Application B

Unlike contracts written for PAB, which are compiled to a single process, CTL is a library. CTL itself can be [imported as a Purescript library](./ctl-as-dependency.md) and offchain contracts written in CTL compile to Javascript that can be run in the browser or NodeJS. Accordingly, there is no need to activate endpoints in CTL -- contracts are executed by calling effectful functions written using the library. This distinction has influenced our adaption of Plutus' `Contract` type, as outlined [below](#the-contract-type).

Note, however, that CTL still requires a number of runtime dependencies. In some respects, this is similar to PAB, which also needs to communicate with plutus-chain-index and a running node. Please see the [documentation](./runtime.md) for more details on CTL's runtime.
Note, however, that CTL still requires a number of runtime dependencies. In some respects, this is similar to PAB, which also needs to communicate with plutus-chain-index and a running node. Please see the [runtime documentation](./runtime.md) for more details.

### The `Contract` type

Expand Down Expand Up @@ -66,13 +66,17 @@ Finally, CTL's `Contract` is not parameterized by an error type as in Plutus. `C

## API differences

### Transaction manipulation API
### DEPRECATION WARNING

The original constraints interface has been deprecated and will be removed. Use [`cardano-transaction-builder`](https://github.com/mlabs-haskell/purescript-cardano-transaction-builder) for any new code.

### **DEPRECATED** Transaction manipulation API

| Plutus | CTL |
| --------------------------- | ----------------------------- |
| `submitTxConstraintsWith` | `submitTxFromConstraints` |

### Constraints and lookups
### **DEPRECATED** Constraints and lookups

CTL has adapted Plutus' Alonzo-era constraints/lookups interface fairly closely and it functions largely the same. One key difference is that CTL does not, and cannot, have the notion of a "current" script. All scripts must be explicitly provided to CTL (serialized as CBOR, see below). This has led us to depart from Plutus' naming conventions for certain constraints/lookups:

Expand All @@ -87,7 +91,7 @@ CTL has adapted Plutus' Alonzo-era constraints/lookups interface fairly closely

Additionally, we implement `NativeScript` (multi-signature phase-1 script) support, which is not covered by Plutus.

#### Babbage-era constraints
#### **DEPRECATED** Babbage-era constraints

CIPs 0031-0033 brought several improvements to Plutus and are supported from the Babbage era onwards:

Expand All @@ -97,36 +101,6 @@ CIPs 0031-0033 brought several improvements to Plutus and are supported from the

CTL has upgraded its constraints interface to work with these new features. At the time of writing, however, `plutus-apps` has not yet upgraded their constraints/lookups interface to support these new features. This means a direct comparison between `plutus-apps` and CTL regarding Babbage-era features is not currently possible. It also implies that, moving forward, CTL's constraints implementation will increasingly no longer match that of `plutus-apps`' to the same degree.

### Typed scripts

Another difference between Plutus and CTL is our implementation of typed scripts. Recall that Plutus' `ValidatorTypes` class:

```haskell
class ValidatorTypes (a :: Type) where
type RedeemerType a :: Type
type DatumType a :: Type

type instance RedeemerType a = ()
type instance DatumType a = ()
```

Purescript lacks most of Haskell's more advanced type-level faculties, including type/data families. Purescript does, however, support functional dependencies, allowing us to encode `ValidatorTypes` as follows:

```purescript
class ValidatorTypes :: Type -> Type -> Type -> Constraint
class
( DatumType validator datum
, RedeemerType validator redeemer
) <=
ValidatorTypes validator datum redeemer

class DatumType :: Type -> Type -> Constraint
class DatumType validator datum | validator -> datum

class RedeemerType :: Type -> Type -> Constraint
class RedeemerType validator redeemer | validator -> redeemer
```

### Working with scripts

#### Using scripts from the frontend
Expand Down
Loading

0 comments on commit 3a0e43b

Please sign in to comment.