Skip to content

Commit

Permalink
Merge remote-tracking branch 'plutonomicon/develop' into dshuiski/pur…
Browse files Browse the repository at this point in the history
…s-0.15-migration
  • Loading branch information
bladyjoker committed Dec 11, 2023
2 parents a5879fd + aad4b64 commit 7620749
Show file tree
Hide file tree
Showing 30 changed files with 502 additions and 248 deletions.
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Support for generic CIP-30 wallets by name ([#1524](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1524))
- Full additional utxos support for Blockfrost backend ([#1537](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1537))
- New `submitTxE`, an error returning variant of `submitTx`
- 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 Expand Up @@ -138,6 +139,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- A problem with collateral selection not respecting `mustNotSpendUtxosWithOutRefs` ([#1509](https://github.com/Plutonomicon/cardano-transaction-lib/issues/1509))
- A problem with too many change UTxOs being generated ([#1530](https://github.com/Plutonomicon/cardano-transaction-lib/issues/1530))
- A problem where tx evaluation with additional utxos failed with an Ogmios `AdditionalUtxoOverlap` exception if some additional utxos got confirmed in the meantime ([#1537](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1537))
- `Contract.PlutusData.redeemerHash` definition ([#1565](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1565))

### Removed

Expand Down Expand Up @@ -174,7 +176,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- `startPlutipCluster` error message now includes cluster startup failure details. ([#1407](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1407))
- `PlutipTest` is now known as `Contract.Test.ContractTest`. It has been semantically untied from Plutip, because we now have another test runner for tests that rely on particular funds distributions - [Blockfrost](./doc/blockfrost.md). See `Contract.Test.Blockfrost.runContractTestsWithBlockfrost` ([#1260](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1260))
- `Contract.Staking.getPoolParameters` has been moved to `Contract.Backend.Ogmios.getPoolParameters`. This function only runs with Ogmios backend, because Blockfrost [does not provide](https://github.com/blockfrost/blockfrost-backend-ryo/issues/82) all the required values ([#1260](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1260))
- Use of [CIP-40](https://cips.cardano.org/cips/cip40/) collateral output is now enabled with CIP-30 wallets ([#1260](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1260)).
- Use of [CIP-40](https://cips.cardano.org/cip/CIP-0040/) collateral output is now enabled with CIP-30 wallets ([#1260](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1260)).
- `reindexSpentScriptRedeemers` is no longer in Contract (it's pure) ([#1260](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1260))

### Removed
Expand Down Expand Up @@ -231,7 +233,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

### Fixed

- Added missing `stakePoolTargetNum` ("`nOpt`") protocol parameter (see [CIP-9](https://cips.cardano.org/cips/cip9/)) ([#571](https://github.com/Plutonomicon/cardano-transaction-lib/issues/571))
- Added missing `stakePoolTargetNum` ("`nOpt`") protocol parameter (see [CIP-9](https://cips.cardano.org/cip/CIP-0009)) ([#571](https://github.com/Plutonomicon/cardano-transaction-lib/issues/571))
- CIP-30 `signData` response handling ([#1289](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1289))

### Runtime Dependencies
Expand Down Expand Up @@ -386,7 +388,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Constraint for attaching a reference input to a transaction: `mustReferenceOutput` ([#946](https://github.com/Plutonomicon/cardano-transaction-lib/pull/946))
- `DatumPresence` data type, which tags paying constraints that accept datum, to mark whether the datum should be inline or hashed in the transaction output. ([#931](https://github.com/Plutonomicon/cardano-transaction-lib/pull/931))
- Utility conversion functions `serializeData` and `deserializeData` between `PlutusData` and `CborBytes` to `Contract.PlutusData`. ([#1001](https://github.com/Plutonomicon/cardano-transaction-lib/issues/1001))
- Added [CIP-30](https://cips.cardano.org/cips/cip30/) methods: `getNetworkId`, `getChangeAddress`, `getRewardAddresses`, `getUnusedAddresses`, `signData`, `isWalletAvailable`, `isEnabled`, `apiVersion`, `name` and `icon` to `Contract.Wallet` ([#974](https://github.com/Plutonomicon/cardano-transaction-lib/issues/974))
- Added [CIP-30](https://cips.cardano.org/cip/CIP-0030) methods: `getNetworkId`, `getChangeAddress`, `getRewardAddresses`, `getUnusedAddresses`, `signData`, `isWalletAvailable`, `isEnabled`, `apiVersion`, `name` and `icon` to `Contract.Wallet` ([#974](https://github.com/Plutonomicon/cardano-transaction-lib/issues/974))

### Changed

Expand Down
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 selecting 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
2 changes: 1 addition & 1 deletion doc/query-layers.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Note that it is possible to set `timeout` to `Seconds infinity`.

### Synchronization and wallet UTxO locking

`Contract.Utxos.utxosAt` function returns a set of UTxOs at a given address by calling Kupo or Blockfrost, depending on the backend. It seems reasonable to assume that if we call `utxosAt` at all wallet's addresses we will get the same set of UTxOs that [CIP-30](https://cips.cardano.org/cips/cip30/) `getUtxos` method would return (eventually). But it is not, in fact, true.
`Contract.Utxos.utxosAt` function returns a set of UTxOs at a given address by calling Kupo or Blockfrost, depending on the backend. It seems reasonable to assume that if we call `utxosAt` at all wallet's addresses we will get the same set of UTxOs that [CIP-30](https://cips.cardano.org/cip/CIP-0030/) `getUtxos` method would return (eventually). But it is not, in fact, true.

*UTxO locking* is a wallet feature that allows to hide certain UTxOs from results of CIP-30 calls, making them invisible to dApps. Among the wallets we support, it is currently only present in Eternl:

Expand Down
38 changes: 29 additions & 9 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 @@ -43,6 +42,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.AlwaysMints (alwaysMintsPolicy)
import Ctl.Examples.Helpers (mkCurrencySymbol, mkTokenName) as Helpers
import Data.Array (head)
import Data.Array (sort) as Array
import Data.Map (keys, member) as Map
import Data.Map (fromFoldable, keys, member) as Map
import Data.Set (findMin) as Set
import JS.BigInt (BigInt, fromInt)

Expand All @@ -63,6 +63,7 @@ newtype ContractParams = ContractParams
type ContractResult =
{ txHash :: TransactionHash
, changeAddress :: Address
, nonSpendableAddress :: Address
, mintedToken :: CurrencySymbol /\ TokenName
, nonSpendableOref :: TransactionInput
}
Expand Down Expand Up @@ -100,8 +101,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 @@ -120,6 +121,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 @@ -133,9 +139,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)
liftedM "Failed to get utxos at Alice's address"
(Set.findMin <<< Map.keys <$> utxosAt aliceAddress)

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

void $ runChecks checks $ lift do
unbalancedTx <- mkUnbalancedTx lookups constraints
Expand All @@ -171,4 +185,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
}
24 changes: 12 additions & 12 deletions flake.lock

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

6 changes: 5 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
description = "cardano-transaction-lib";

nixConfig.bash-prompt = "\\[\\e[0m\\][\\[\\e[0;2m\\]nix-develop \\[\\e[0;1m\\]CTL@\\[\\033[33m\\]$(git rev-parse --abbrev-ref HEAD) \\[\\e[0;32m\\]\\w\\[\\e[0m\\]]\\[\\e[0m\\]$ \\[\\e[0m\\]";
nixConfig = {
extra-substituters = [ "https://plutonomicon.cachix.org" ];
extra-trusted-public-keys = [ "plutonomicon.cachix.org-1:evUxtNULjCjOipxwAnYhNFeF/lyYU1FeNGaVAnm+QQw=" ];
bash-prompt = "\\[\\e[0m\\][\\[\\e[0;2m\\]nix-develop \\[\\e[0;1m\\]CTL@\\[\\033[33m\\]$(git rev-parse --abbrev-ref HEAD) \\[\\e[0;32m\\]\\w\\[\\e[0m\\]]\\[\\e[0m\\]$ \\[\\e[0m\\]";
};

inputs = {
nixpkgs.follows = "haskell-nix/nixpkgs-unstable";
Expand Down
1 change: 1 addition & 0 deletions spago.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ You can edit this file as you like.
, "aff-promise"
, "aff-retry"
, "affjax"
, "ansi"
, "argonaut"
, "argonaut-codecs"
, "arraybuffer-types"
Expand Down
1 change: 1 addition & 0 deletions src/Contract/BalanceTxConstraints.purs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Ctl.Internal.BalanceTx.Constraints
, mustSendChangeWithDatum
, mustUseAdditionalUtxos
, mustUseCoinSelectionStrategy
, mustUseCollateralUtxos
, mustUseUtxosAtAddress
, mustUseUtxosAtAddresses
) as BalanceTxConstraints
5 changes: 3 additions & 2 deletions src/Contract/Transaction.purs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ import Contract.UnbalancedTx (mkUnbalancedTx)
import Control.Monad.Error.Class (catchError, liftEither, throwError)
import Control.Monad.Reader (ReaderT, asks, runReaderT)
import Control.Monad.Reader.Class (ask)
import Ctl.Internal.BalanceTx (FinalizedTransaction)
import Ctl.Internal.BalanceTx (FinalizedTransaction(FinalizedTransaction)) as FinalizedTransaction
import Ctl.Internal.BalanceTx (balanceTxWithConstraints) as BalanceTx
import Ctl.Internal.BalanceTx.Constraints (BalanceTxConstraintsBuilder)
import Ctl.Internal.BalanceTx.Error
Expand All @@ -60,6 +58,7 @@ import Ctl.Internal.BalanceTx.Error
, CouldNotConvertScriptOutputToTxInput
, CouldNotGetChangeAddress
, CouldNotGetCollateral
, InsufficientCollateralUtxos
, CouldNotGetUtxos
, CollateralReturnError
, CollateralReturnMinAdaValueCalcError
Expand All @@ -72,6 +71,8 @@ import Ctl.Internal.BalanceTx.Error
, Expected(Expected)
, explainBalanceTxError
) as BalanceTxError
import Ctl.Internal.BalanceTx.Types (FinalizedTransaction)
import Ctl.Internal.BalanceTx.Types (FinalizedTransaction(FinalizedTransaction)) as FinalizedTransaction
import Ctl.Internal.BalanceTx.UnattachedTx (UnindexedTx)
import Ctl.Internal.Cardano.Types.NativeScript
( NativeScript
Expand Down
Loading

0 comments on commit 7620749

Please sign in to comment.