Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] Indigo develop collateral tx chaining fix #9

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 47 additions & 42 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,49 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [[Unreleased]](#unreleased)
- [Added](#added)
- [Changed](#changed)
- [Fixed](#fixed)
- [Removed](#removed)
- [[v5.0.0]](#v500)
- [Added](#added-1)
- [Changed](#changed-1)
- [Removed](#removed-1)
- [Fixed](#fixed-1)
- [Runtime Dependencies](#runtime-dependencies)
- [[v4.0.2] - 2023-01-17](#v402---2023-01-17)
- [Fixed](#fixed-2)
- [[v4.0.1] - 2022-12-20](#v401---2022-12-20)
- [Added](#added-2)
- [[v4.0.0] - 2022-12-15](#v400---2022-12-15)
- [Added](#added-3)
- [Changed](#changed-2)
- [Removed](#removed-2)
- [Fixed](#fixed-3)
- [Runtime Dependencies](#runtime-dependencies-1)
- [[3.0.0] - 2022-11-21](#300---2022-11-21)
- [Added](#added-4)
- [Changed](#changed-3)
- [Removed](#removed-3)
- [Fixed](#fixed-4)
- [Runtime Dependencies](#runtime-dependencies-2)
- [[2.0.0] - 2022-09-12](#200---2022-09-12)
- [Added](#added-5)
- [Changed](#changed-4)
- [Removed](#removed-4)
- [Fixed](#fixed-5)
- [[2.0.0-alpha] - 2022-07-05](#200-alpha---2022-07-05)
- [Added](#added-6)
- [Removed](#removed-5)
- [Changed](#changed-5)
- [Fixed](#fixed-6)
- [[1.1.0] - 2022-06-30](#110---2022-06-30)
- [Fixed](#fixed-7)
- [[1.0.1] - 2022-06-17](#101---2022-06-17)
- [Fixed](#fixed-8)
- [[1.0.0] - 2022-06-10](#100---2022-06-10)
- [Changelog](#changelog)
- [\[Unreleased\]](#unreleased)
- [Added](#added)
- [Changed](#changed)
- [Fixed](#fixed)
- [Removed](#removed)
- [\[v5.0.0\]](#v500)
- [Added](#added-1)
- [Changed](#changed-1)
- [Removed](#removed-1)
- [Fixed](#fixed-1)
- [Runtime Dependencies](#runtime-dependencies)
- [\[v4.0.2\] - 2023-01-17](#v402---2023-01-17)
- [Fixed](#fixed-2)
- [\[v4.0.1\] - 2022-12-20](#v401---2022-12-20)
- [Added](#added-2)
- [\[v4.0.0\] - 2022-12-15](#v400---2022-12-15)
- [Added](#added-3)
- [Changed](#changed-2)
- [Removed](#removed-2)
- [Fixed](#fixed-3)
- [Runtime Dependencies](#runtime-dependencies-1)
- [\[3.0.0\] - 2022-11-21](#300---2022-11-21)
- [Added](#added-4)
- [Changed](#changed-3)
- [Removed](#removed-3)
- [Fixed](#fixed-4)
- [Runtime Dependencies](#runtime-dependencies-2)
- [\[2.0.0\] - 2022-09-12](#200---2022-09-12)
- [Added](#added-5)
- [Changed](#changed-4)
- [Removed](#removed-4)
- [Fixed](#fixed-5)
- [\[2.0.0-alpha\] - 2022-07-05](#200-alpha---2022-07-05)
- [Added](#added-6)
- [Removed](#removed-5)
- [Changed](#changed-5)
- [Fixed](#fixed-6)
- [\[1.1.0\] - 2022-06-30](#110---2022-06-30)
- [Fixed](#fixed-7)
- [\[1.0.1\] - 2022-06-17](#101---2022-06-17)
- [Fixed](#fixed-8)
- [\[1.0.0\] - 2022-06-10](#100---2022-06-10)

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

Expand All @@ -66,6 +67,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- `Contract.JsSdk` module containing helper functions for developers who want to use CTL from JS. See also: [this new guide](./doc/using-from-js.md) ([#1453](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1453))
- New [docs for contract environment](./doc/contract-environment.md) ([#1453](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1453))
- Cluster configuration options to `PlutipConfig`: `epochSize`, `maxTxSize` and `raiseExUnitsToMax` - see [Plutip docs](./doc/plutip-testing.md) ([#1494](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1494))
- [HD wallet support](./doc/key-management.md) with mnemonic seed phrases ([#1498](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1498))
- Ogmios-specific functions for Local TX Monitor Ouroboros Mini-Protocol in `Contract.Backend.Ogmios` ([#1508](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1508/))
- New `mustSendChangeWithDatum` balancer constraint that adds datum to all change outputs ([#1510](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1510/))
- Allow providing a custom set of UTxOs for collateral selection, overriding the wallet (`mustUseCollateralUtxos` balancer constraint) ([#1513](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1513))

### Changed

Expand Down
117 changes: 6 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,115 +1,10 @@
# cardano-transaction-lib

[![Hercules-ci][herc badge]][herc link]
[![Cachix Cache][cachix badge]][cachix link]
[![PureScript code documentation][docs badge]][docs link]
This repository is a fork from https://github.com/Plutonomicon/cardano-transaction-lib and contains any necessary changes that provide either improvements that are currently not present in CTL or patches that are specific to Indigo which will most likely not be implemented in the upstream repository.

[herc badge]: https://img.shields.io/badge/ci--by--hercules-green.svg
[herc link]: https://hercules-ci.com/github/Plutonomicon/cardano-transaction-lib
[cachix badge]: https://img.shields.io/badge/cachix-public_plutonomicon-blue.svg
[cachix link]: https://public-plutonomicon.cachix.org
[docs badge]: https://img.shields.io/badge/docs-PureScript%20code%20documentation-%2377F
[docs link]: https://plutonomicon.github.io/cardano-transaction-lib/
### Improvements (Potential PRs):
* Sharing wallets between Plutip tests: https://github.com/IndigoProtocol/cardano-transaction-lib/pull/1

**cardano-transaction-lib** (CTL) is a Purescript library for building smart contract transactions on Cardano. It aims to port the functionality and interface of Plutus off-chain code to the browser environment and NodeJS.

**Table of Contents**

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Documentation](#documentation)
- [Light wallet support](#light-wallet-support)
- [Roadmap](#roadmap)
- [Architecture](#architecture)
- [Additional resources/tools:](#additional-resourcestools)
- [Available support channels info](#available-support-channels-info)

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

## Documentation

Please explore our documentation to discover how to use CTL, how to set up its runtime, and how it compares to Plutus/PAB:

- [Super quick start](./doc/getting-started.md#setting-up-a-new-project)
- [Adding CTL as a dependency](./doc/ctl-as-dependency.md)
- [CTL's runtime dependencies](./doc/runtime.md)
- [Blockfrost support](./doc/blockfrost.md)
- [Getting started writing CTL contracts](./doc/getting-started.md)
- [Managing contract environment](./doc/contract-environment.md)
- [Using CTL from JS](./doc/using-from-js.md)
- [Importing Plutus Scripts](./doc/importing-scripts.md)
- [Migrating from Plutus to CTL](./doc/plutus-comparison.md)
- [Overview of testing approaches](./doc/testing.md)
- [Testing contracts with Plutip](./doc/plutip-testing.md)
- [End-to-end testing with headless browsers](./doc/e2e-testing.md)
- [Utilities for testing](./doc/test-utils.md)
- [CIP-25 NFT standard support](./doc/cip-25-nfts.md)
- [Transaction balancing](./doc/balancing.md)
- [Transaction chaining](./doc/tx-chaining.md)
- [Ada staking support](./doc/staking.md)
- [SECP256k1 support (CIP-49)](./doc/secp256k1-support.md)
- [Custom query layers](./doc/custom-query-layers.md)
- [FAQs](./doc/faq.md)
- [Feature overview video](./doc/video-intro.md)
- [Development workflows for CTL](./doc/development.md)

You can also access [PureScript documentation for CTL and its dependencies](https://plutonomicon.github.io/cardano-transaction-lib/) for the most recent `develop` version, or [generate it yourself](./doc/development.md#generating-ps-documentation).

### Light wallet support

Support is planned for the following light wallets:

- [x] [Nami](https://namiwallet.io/)
- [x] [Gero](https://gerowallet.io/)
- [x] [Flint](https://flint-wallet.com/)
- [x] [Lode](https://lodewallet.io/)
- [x] [Eternl (formerly CCvault)](https://eternl.io/)
- [x] [NuFi](https://nu.fi/)
- [ ] [Lace](https://www.lace.io/)
- [ ] [Typhon](https://typhonwallet.io/)
- [ ] [Yoroi](https://yoroi-wallet.com/)

## Roadmap

- [x] **Stage 1** Build a simple transaction in the browser that works with at least one light wallet (Nami)
- [x] **Stage 2** Once we can construct a simple user-to-user transaction, we will try to use the library to submit the tx with nami
- [x] **Stage 3** Once we have a simple working transaction, we will seek to build a Plutus smart contract transaction with datum from scratch
- [x] **Stage 4** Once we can construct Plutus smart contract transactions, we will seek to build a library/DSL/interface such that transactions can be built using constraints and lookups - as close as possible to a cut-and-paste solution from Plutus' `Contract` monad code in Haskell (but with no guarantee that code changes are not necessary)
- [x] **Stage 4.1** Investigate supporting compatibility with the Vasil hardfork and improvements to our initial `Contract` API
- [ ] **Stage 5** Once we have a basic `Contract`-style API, we will further refine its public interface, expand wallet support (see [below](#light-wallet-support)), expose a test interface (**DONE** - see [here](doc/plutip-testing.md)), provide a more ergonomic JS/TS API, support stake validators (**DONE**), and support CIP workflows on the public testnet (**In progress**)
- [ ] **Stage 6** Once CTL's `Contract` interface has been stabilized, we will add support for even more wallets and attempt to deprecate CTL's currently required Haskell server (**DONE**)

## Architecture

CTL is directly inspired by the Plutus Application Backend (PAB). Unlike PAB, however, CTL is a library and not a standalone process. Over the course of CTL's development, several questions have been raised as to how best create PAB-as-a-library:

1. How do we get the transaction in the right format?
- This is handled by `cardano-serialization-lib`, a Rust library available as WASM
2. How do we query the chain?
- This has been solved using Ogmios & Kupo
- We [will support](https://cardano.ideascale.com/c/idea/420791) an alternative [BlockFrost](https://blockfrost.io/) backend as well in the future
3. How do we query for datums (i.e. the datums themselves and not just their hashes)?
- `Kupo` solves this problem
4. How do we get wallet data?
- This is done via browser-based light wallet integration in the browser based on CIP-30
5. How closely should we follow Plutus' `Contract` API?
- CTL's `Contract` model is **significantly** less restrictive than Plutus' and allows for arbitrary effects within the `Contract` monad
- Certain features cannot be directly translated into Purescript from Haskell due to differences between the two languages
- Some of the Plutus conventions do not make sense for us, due to differences between on-chain and off-chain

## Additional resources/tools:

- [`cardano-serialization-lib`](https://github.com/Emurgo/cardano-serialization-lib/)
- [Ogmios](https://ogmios.dev) for chain queries
- [Kupo](https://cardanosolutions.github.io/kupo/) for chain queries
- [CIP-30](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030) (wallet interface - Nami partially implements this)
- [Nami docs](https://github.com/Berry-Pool/nami-wallet)
- [Alonzo CDDL spec](https://github.com/input-output-hk/cardano-ledger/blob/0738804155245062f05e2f355fadd1d16f04cd56/alonzo/impl/cddl-files/alonzo.cddl)

## Available support channels info

You can find help, more information and ongoing discusion about the project here:

- [Plutonomicon Discord](https://discord.gg/JhbexnV9Pc)
- #ctl channel at MLabs' Slack
### Patches (Breaking Changes):
* Using a CSL fork to serialize/deserialize unsorted maps: https://github.com/IndigoProtocol/cardano-transaction-lib/pull/2
* Having `epochSize` in `PlutipConfig` to prevent `CannotFindTimeInEraSummaries` error: https://github.com/Plutonomicon/cardano-transaction-lib/issues/1057
14 changes: 8 additions & 6 deletions doc/balancing.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ Transaction balancing in Cardano is the process of finding a set of inputs and o

CTL allows tweaking the default balancer behavior by letting the user impose constraints on the UTxO set that is used in the process (`balanceTxWithConstraints`):

- providing additional UTxOs to use: `mustUseUtxosAtAddresses` / `mustUseUtxosAtAddress` / `mustUseAdditionalUtxos`
- overriding change address: `mustSendChangeToAddress`
- prevent certain UTxOs from being spent: `mustNotSpendUtxosWithOutRefs` / `mustNotSpendUtxoWithOutRef`
- distribute token outputs equally between change UTxOs: `mustGenChangeOutsWithMaxTokenQuantity`
- Using arbitrary address as user's own (for transaction balancing): `mustUseUtxosAtAddresses` / `mustUseUtxosAtAddress`
- Providing additional UTxOs to use: `mustUseAdditionalUtxos`
- Bypassing wallet's collateral selection and select collateral UTxOs from a given set: `mustUseCollateralUtxos`
- Overriding change address: `mustSendChangeToAddress`
- Preventing certain UTxOs from being spent: `mustNotSpendUtxosWithOutRefs` / `mustNotSpendUtxoWithOutRef`
- Distributing token outputs equally between change UTxOs: `mustGenChangeOutsWithMaxTokenQuantity`

## Concurrent spending

Expand All @@ -31,11 +33,11 @@ Obviously, the number of available UTxOs must be greater than the number of tran

## Balancing a Tx for other wallet

Setting `mustUseUtxosAtAddress` and `mustSendChangeToAddress` at the same time allows to build a transaction without any connection to the current wallet. For example, it's possible to balance it on server-side and send to the user to sign, or balance a Tx on one user's side while leaving fees at the expense of some other user.
Setting `mustUseUtxosAtAddress`, `mustSendChangeToAddress` and `mustUseCollateralUtxos` at the same time allows to build a transaction without any connection to the current wallet. For example, it's possible to balance it on server-side and send to the user to sign, or balance a Tx on one user's side while leaving fees at the expense of some other user.

## Synchronization

Before balancing, CTL synchronizes the wallet 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. Please see [our docs for query layer synchronization](./query-layers.md).
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).

## Balancing process limitations

Expand Down
36 changes: 28 additions & 8 deletions examples/BalanceTxConstraints.purs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ module Ctl.Examples.BalanceTxConstraints

import Contract.Prelude

import Contract.Address
( Address
)
import Contract.Address (Address)
import Contract.BalanceTxConstraints
( BalanceTxConstraintsBuilder
, mustGenChangeOutsWithMaxTokenQuantity
, mustNotSpendUtxoWithOutRef
, mustSendChangeToAddress
, mustUseCollateralUtxos
, mustUseUtxosAtAddress
) as BalanceTxConstraints
import Contract.Log (logInfo')
Expand Down Expand Up @@ -42,6 +41,7 @@ import Contract.Value (singleton, valueOf) as Value
import Contract.Wallet
( KeyWallet
, getWalletAddressesWithNetworkTag
, getWalletCollateral
, ownPaymentPubKeyHashes
, withKeyWallet
)
Expand All @@ -51,7 +51,7 @@ import Ctl.Examples.Helpers (mkCurrencySymbol, mkTokenName) as Helpers
import Data.Array (head)
import Data.Array (sort) as Array
import Data.BigInt (BigInt, fromInt)
import Data.Map (keys, member) as Map
import Data.Map (fromFoldable, keys, member) as Map
import Data.Set (findMin) as Set

newtype ContractParams = ContractParams
Expand All @@ -62,6 +62,7 @@ newtype ContractParams = ContractParams
type ContractResult =
{ txHash :: TransactionHash
, changeAddress :: Address
, nonSpendableAddress :: Address
, mintedToken :: CurrencySymbol /\ TokenName
, nonSpendableOref :: TransactionInput
}
Expand Down Expand Up @@ -99,8 +100,8 @@ assertSelectedUtxoIsNotSpent
:: ContractCheck ContractResult
assertSelectedUtxoIsNotSpent =
assertionToCheck "Non-spendable UTxO hasn't been spent"
\{ changeAddress, nonSpendableOref } -> do
utxos <- lift $ utxosAt changeAddress
\{ nonSpendableAddress, nonSpendableOref } -> do
utxos <- lift $ utxosAt nonSpendableAddress
let
assertionFailure :: ContractAssertionFailure
assertionFailure =
Expand All @@ -119,6 +120,11 @@ contract :: ContractParams -> Contract Unit
contract (ContractParams p) = do
logInfo' "Examples.BalanceTxConstraints"

aliceAddress <-
liftedM "Failed to get Alice's address"
$ head
<$> (withKeyWallet p.aliceKeyWallet getWalletAddressesWithNetworkTag)

alicePubKeyHash <-
liftedM "Failed to get own PKH" $ head <$> ownPaymentPubKeyHashes

Expand All @@ -132,9 +138,16 @@ contract (ContractParams p) = do
$ head
<$> (withKeyWallet p.bobKeyWallet getWalletAddressesWithNetworkTag)

bobsCollateralArray <- withKeyWallet p.bobKeyWallet do
fold <$> getWalletCollateral
let
bobsCollateral =
Map.fromFoldable $ bobsCollateralArray <#> unwrap >>>
\{ input, output } -> Tuple input output

nonSpendableOref <-
liftedM "Failed to get utxos at Bob's address"
(Set.findMin <<< Map.keys <$> utxosAt bobAddress)
(Set.findMin <<< Map.keys <$> utxosAt aliceAddress)

mp /\ cs <- Helpers.mkCurrencySymbol alwaysMintsPolicy
tn <- Helpers.mkTokenName "The Token"
Expand All @@ -153,6 +166,7 @@ contract (ContractParams p) = do
<> BalanceTxConstraints.mustUseUtxosAtAddress bobAddress
<> BalanceTxConstraints.mustSendChangeToAddress bobAddress
<> BalanceTxConstraints.mustNotSpendUtxoWithOutRef nonSpendableOref
<> BalanceTxConstraints.mustUseCollateralUtxos bobsCollateral

void $ runChecks checks $ lift do
unbalancedTx <-
Expand All @@ -172,4 +186,10 @@ contract (ContractParams p) = do
logInfo' "Tx submitted successfully!"

let changeAddress = (unwrap bobAddress).address
pure { txHash, changeAddress, mintedToken: cs /\ tn, nonSpendableOref }
pure
{ txHash
, changeAddress
, nonSpendableAddress: (unwrap aliceAddress).address
, mintedToken: cs /\ tn
, nonSpendableOref
}
8 changes: 4 additions & 4 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
};

# TODO use a tag for blockfrost as soon as they tag a recent commit (we need it as a flake)
blockfrost.url = "github:blockfrost/blockfrost-backend-ryo/49269a9adb27b370209a61de2f5407945112860a";
blockfrost.url = "github:blockfrost/blockfrost-backend-ryo/587aa6800f4c0dfaf285c1313fed3043848c4a84";
db-sync.url = "github:input-output-hk/cardano-db-sync/13.1.0.0";

# Plutip server related inputs
Expand Down Expand Up @@ -138,6 +138,7 @@
packageLock = ./package-lock.json;
shell = {
withRuntime = true;
withChromium = false;
shellHook = exportOgmiosFixtures;
packageLockOnly = true;
packages = with pkgs; [
Expand Down
Loading