Skip to content
Merged
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Kupo + Ogmios Provider has been extracted to a separate package [purescript-cardano-kupmios-provider](https://github.com/mlabs-haskell/purescript-cardano-kupmios-provider) using module names in the format `Cardano.Kupmios.*` ([#1662](https://github.com/Plutonomicon/cardano-transaction-lib/issues/1662))
- Ogmios' mempool functionality has been extracted to a separate package [purescript-cardano-ogmios-mempool](https://github.com/mlabs-haskell/purescript-cardano-ogmios-mempool) using the module `Cardano.Ogmios.Mempool`. To use it, the user must create and manage the websocket connection (see [Test.Ctl.Testnet.Contract.OgmiosMempool](https://github.com/Plutonomicon/cardano-transaction-lib/blob/cd80e31d59b233e48ccb2a0b6635d5d8beb5b160/test/Testnet/Contract/OgmiosMempool.purs))
- Made adjustments to the [E2E testing documentation page](./doc/e2e-testing.md). Updated the [template](./templates/ctl-scaffold) to use the newly introduced `e2eConfigs` helper function that allows to define E2E configurations without unnecessary boilerplate. ([#1674](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1674))
- The transaction balancing module used in CTL has been extracted to a separate package [purescript-cardano-transaction-balancer](https://github.com/mlabs-haskell/purescript-cardano-transaction-balancer) using module names in the format `Cardano.Transaction.Balancer.*` ([#1680](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1680))
- Updated the `Contract.Transaction` interface to support pluggable transaction balancers. This enhancement should allow users to integrate custom balancers when the provided default solution does not satisfy specific domain requirements. ([#1680](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1680))
- The `balanceTx` and `balanceTxE` functions from `Contract.Transaction` have been deprecated. Users are now encouraged to use standalone transaction balancers directly (e.g. `defaultBalancer` and `defaultBalancerWithErr` respectively).
- The `balanceTxs` function has been deprecated in favor of the new balancer-agnostic `balanceMultipleTxs`.
- `Contract.Transaction` now exports `defaultBalancer` and `defaultBalancerWithErr` variants, both implementing the new `TxBalancer` interface.
- **[BREAKING CHANGE]** `withBalancedTx` and `withBalancedTxs` now accept a `TxBalancer` and its corresponding balancer context as arguments.
- The `submitTxFromConstraints` and `submitTxFromBuildPlan` functions have been deprecated in favor of `submitTxFromBlueprint`. The new function accepts a `TxBlueprint` with the steps and context needed to construct and balance a transaction, and returns a `TxReceipt` containing the balanced, signed transaction along with its hash.
- *Note that all mentioned deprecated functions are planned for removal in a future release.*

### Removed

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ CTL is being developed by MLabs. The following companies/funds have contributed
- [Equine](https://www.equine.gg/)
- [Liqwid Labs](https://liqwid.finance/)
- PlayerMint
- [Fourier Labs](https://fourierlabs.io/)
- Fourier Labs
- Ardana

## Use in production
Expand Down
4 changes: 2 additions & 2 deletions doc/balancing.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Transaction balancing in Cardano is the process of finding a set of inputs and o

## Balancer constraints

CTL allows tweaking the default balancer behavior by letting the user impose constraints on the UTxO set that is used in the process (`balanceTxWithConstraints`):
The default transaction balancer used in CTL (`defaultBalancer` / `defaultBalancerWithErr`) allows users to adjust its behavior by imposing various constraints:

- Using arbitrary address as user's own (for transaction balancing): `mustUseUtxosAtAddresses` / `mustUseUtxosAtAddress`
- Providing additional UTxOs to use: `mustUseAdditionalUtxos`
Expand All @@ -27,7 +27,7 @@ CTL allows tweaking the default balancer behavior by letting the user impose con

## Concurrent spending

Attempting to spend UTxOs concurrently leads to some of the transactions being rejected. To ensure that no concurrent spending is happening, CTL uses it's own UTxO locking machinery. `balanceTxs` or `balanceTxsWithConstraints` can be used to construct multiple transactions at once, ensuring that the sets of inputs do not intersect.
Attempting to spend UTxOs concurrently leads to some of the transactions being rejected. To ensure that no concurrent spending is happening, CTL uses it's own UTxO locking machinery. `balanceMultipleTxs` can be used to construct multiple transactions at once, ensuring that the sets of inputs do not intersect.

Obviously, the number of available UTxOs must be greater than the number of transactions. CTL will throw an exception if it's not the case.

Expand Down
12 changes: 7 additions & 5 deletions doc/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,19 +191,21 @@ Unlike PAB, CTL obscures less of the build-balance-sign-submit pipeline for tran
...
```

- Balance it using `Contract.Transaction.balanceTx`, and then sign it using `signTransaction`:
- Balance it using `Contract.Transaction.defaultBalancer`, and then sign it using `signTransaction`:
```purescript
contract = do
...
let
balanceTxConstraints :: BalanceTxConstraints.BalanceTxConstraintsBuilder
balanceTxConstraints =
balancerConstraints :: BalanceTxConstraints.BalanceTxConstraintsBuilder
balancerConstraints =
BalanceTxConstraints.mustUseUtxosAtAddress address
<> BalanceTxConstraints.mustSendChangeToAddress address
<> BalanceTxConstraints.mustNotSpendUtxoWithOutRef nonSpendableOref
-- `liftedE` will throw a runtime exception on `Left`s
balancedTx <-
balanceTx unbalancedTx usedUtxos balanceTxConstraints
balancedTx <- liftEither =<< defaultBalancer unbalancedTx
{ balancerConstraints
, extraUtxos
}
balancedSignedTx <- signTransaction balancedTx
...
```
Expand Down
22 changes: 14 additions & 8 deletions examples/AdditionalUtxos.purs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,20 @@ import Contract.Sync (withoutSync)
import Contract.Transaction
( ScriptRef(NativeScriptRef)
, awaitTxConfirmed
, balanceTx
, buildTx
, createAdditionalUtxos
, defaultBalancer
, emptyBalancerCtx
, signTransaction
, submit
, submitTxFromBlueprint
, withBalancedTx
)
import Contract.Utxos (UtxoMap)
import Contract.Value (Value)
import Contract.Value (lovelaceValueOf) as Value
import Ctl.Examples.PlutusV2.Scripts.AlwaysSucceeds (alwaysSucceedsScriptV2)
import Data.Map (difference, empty, filter) as Map
import Data.Map (difference, filter) as Map
import JS.BigInt (fromInt) as BigInt
import Test.QuickCheck (arbitrary)
import Test.QuickCheck.Gen (randomSampleOne)
Expand All @@ -74,7 +76,7 @@ contract testAdditionalUtxoOverlap = withoutSync do
validator <- alwaysSucceedsScriptV2
let vhash = PlutusScript.hash validator
{ unbalancedTx, datum } <- payToValidator vhash
withBalancedTx unbalancedTx Map.empty mempty \balancedTx -> do
withBalancedTx defaultBalancer unbalancedTx emptyBalancerCtx \balancedTx -> do
balancedSignedTx <- signTransaction balancedTx
txHash <- submit balancedSignedTx
when testAdditionalUtxoOverlap $ awaitTxConfirmed txHash
Expand Down Expand Up @@ -135,16 +137,20 @@ spendFromValidator validator additionalUtxos _datum = do
fromUtxoMap (Map.difference additionalUtxos scriptUtxos) <#> \output ->
SpendOutput output Nothing

plan = spendScriptOutputs <> spendPubkeyOutputs
buildSteps = spendScriptOutputs <> spendPubkeyOutputs

balancerConstraints :: BalancerConstraints
balancerConstraints =
mustUseAdditionalUtxos additionalUtxos

unbalancedTx <- buildTx plan
balancedTx <- balanceTx unbalancedTx additionalUtxos balancerConstraints
balancedSignedTx <- signTransaction balancedTx
txHash <- submit balancedSignedTx
{ txHash } <- submitTxFromBlueprint
{ buildSteps
, balancer: defaultBalancer
, balancerCtx:
{ balancerConstraints
, extraUtxos: additionalUtxos
}
}

awaitTxConfirmed txHash
logInfo' "Successfully spent additional utxos from the validator address."
33 changes: 20 additions & 13 deletions examples/AlwaysMints.purs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import Cardano.Types (PlutusScript)
import Cardano.Types.Int as Int
import Cardano.Types.PlutusScript as PlutusScript
import Cardano.Types.RedeemerDatum as RedeemerDatum
import Cardano.Types.Transaction as Transaction
import Contract.Config
( ContractParams
, KnownWallet(Eternl)
Expand All @@ -31,9 +30,13 @@ import Contract.Config
import Contract.Log (logInfo')
import Contract.Monad (Contract, launchAff_, liftContractM, runContract)
import Contract.TextEnvelope (decodeTextEnvelope, plutusScriptFromEnvelope)
import Contract.Transaction (awaitTxConfirmed, submitTxFromBuildPlan)
import Contract.Transaction
( awaitTxConfirmed
, defaultBalancer
, emptyBalancerCtx
, submitTxFromBlueprint
)
import Ctl.Examples.Helpers (mkAssetName) as Helpers
import Data.Map as Map

main :: Effect Unit
main = example $ testnetConfig
Expand All @@ -47,16 +50,20 @@ contract = do
mintingPolicy <- alwaysMintsPolicy
let scriptHash = PlutusScript.hash mintingPolicy
tokenName <- Helpers.mkAssetName "TheToken"
awaitTxConfirmed <<< Transaction.hash =<<
submitTxFromBuildPlan Map.empty mempty
[ MintAsset
scriptHash
tokenName
(Int.fromInt 100)
( PlutusScriptCredential (ScriptValue mintingPolicy)
RedeemerDatum.unit
)
]
{ txHash } <- submitTxFromBlueprint
{ buildSteps:
[ MintAsset
scriptHash
tokenName
(Int.fromInt 100)
( PlutusScriptCredential (ScriptValue mintingPolicy)
RedeemerDatum.unit
)
]
, balancer: defaultBalancer
, balancerCtx: emptyBalancerCtx
}
awaitTxConfirmed txHash
logInfo' "Tx submitted successfully!"

example :: ContractParams -> Effect Unit
Expand Down
54 changes: 33 additions & 21 deletions examples/AlwaysSucceeds.purs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import Cardano.Types.OutputDatum (OutputDatum(OutputDatumHash))
import Cardano.Types.PlutusData as PlutusData
import Cardano.Types.PlutusScript as Script
import Cardano.Types.RedeemerDatum as RedeemerDatum
import Cardano.Types.Transaction as Transaction
import Cardano.Types.TransactionUnspentOutput (toUtxoMap)
import Contract.Address (mkAddress)
import Contract.Config
Expand All @@ -48,8 +47,10 @@ import Contract.Monad (Contract, launchAff_, runContract)
import Contract.TextEnvelope (decodeTextEnvelope, plutusScriptFromEnvelope)
import Contract.Transaction
( awaitTxConfirmed
, defaultBalancer
, emptyBalancerCtx
, lookupTxHash
, submitTxFromBuildPlan
, submitTxFromBlueprint
)
import Contract.Utxos (utxosAt)
import Contract.Value as Value
Expand Down Expand Up @@ -86,14 +87,18 @@ payToAlwaysSucceeds vhash = do
mbStakeKeyHash <- join <<< head <$> ownStakePubKeyHashes
scriptAddress <- mkAddress (PaymentCredential $ ScriptHashCredential vhash)
(StakeCredential <<< PubKeyHashCredential <<< unwrap <$> mbStakeKeyHash)
Transaction.hash <$> submitTxFromBuildPlan Map.empty mempty
[ Pay $ TransactionOutput
{ address: scriptAddress
, amount: Value.lovelaceValueOf $ BigNum.fromInt 2_000_000
, datum: Just $ OutputDatumHash $ hashPlutusData PlutusData.unit
, scriptRef: Nothing
}
]
_.txHash <$> submitTxFromBlueprint
{ buildSteps:
[ Pay $ TransactionOutput
{ address: scriptAddress
, amount: Value.lovelaceValueOf $ BigNum.fromInt 2_000_000
, datum: Just $ OutputDatumHash $ hashPlutusData PlutusData.unit
, scriptRef: Nothing
}
]
, balancer: defaultBalancer
, balancerCtx: emptyBalancerCtx
}

spendFromAlwaysSucceeds
:: ScriptHash
Expand All @@ -117,17 +122,24 @@ spendFromAlwaysSucceeds vhash validator txId = do
)
)
$ head (lookupTxHash txId utxos)
spendTx <- submitTxFromBuildPlan (Map.union utxos $ toUtxoMap [ utxo ])
mempty
[ SpendOutput
utxo
( Just $ PlutusScriptOutput (ScriptValue validator) RedeemerDatum.unit
$ Just
$ DatumValue
$ PlutusData.unit
)
]
awaitTxConfirmed $ Transaction.hash spendTx
{ txHash } <- submitTxFromBlueprint
{ buildSteps:
[ SpendOutput
utxo
( Just
$ PlutusScriptOutput (ScriptValue validator) RedeemerDatum.unit
$ Just
$ DatumValue
$ PlutusData.unit
)
]
, balancer: defaultBalancer
, balancerCtx:
{ balancerConstraints: mempty
, extraUtxos: Map.union utxos $ toUtxoMap [ utxo ]
}
}
awaitTxConfirmed txHash
logInfo' "Successfully spent locked values."

alwaysSucceedsScript :: Contract PlutusScript
Expand Down
13 changes: 8 additions & 5 deletions examples/BalanceTxConstraints.purs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import Contract.Transaction
( TransactionHash
, TransactionInput
, awaitTxConfirmed
, balanceTx
, defaultBalancer
, signTransaction
, submit
)
Expand Down Expand Up @@ -166,8 +166,8 @@ contract (ContractParams p) = do
lookups :: Lookups.ScriptLookups
lookups = Lookups.plutusMintingPolicy mp

balanceTxConstraints :: BalancerConstraints
balanceTxConstraints =
balancerConstraints :: BalancerConstraints
balancerConstraints =
mustGenChangeOutsWithMaxTokenQuantity
(BigInt.fromInt 4)
<> mustUseUtxosAtAddress bobAddress
Expand All @@ -176,9 +176,12 @@ contract (ContractParams p) = do
<> mustUseCollateralUtxos bobsCollateral

void $ runChecks checks $ lift do
unbalancedTx /\ usedUtxos <- mkUnbalancedTx lookups constraints
unbalancedTx /\ extraUtxos <- mkUnbalancedTx lookups constraints

balancedTx <- balanceTx unbalancedTx usedUtxos balanceTxConstraints
balancedTx <- liftEither =<< defaultBalancer unbalancedTx
{ balancerConstraints
, extraUtxos
}

balancedSignedTx <-
(withKeyWallet p.bobKeyWallet <<< signTransaction)
Expand Down
15 changes: 9 additions & 6 deletions examples/ChangeGeneration.purs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ import Contract.PlutusData (OutputDatum(OutputDatum), PlutusData(Integer))
import Contract.Scripts (validatorHash)
import Contract.Transaction
( awaitTxConfirmed
, balanceTx
, buildTx
, defaultBalancer
, signTransaction
, submit
)
import Contract.Value as Value
import Contract.Wallet (getWalletAddress)
import Control.Monad.Error.Class (liftEither)
import Ctl.Examples.AlwaysSucceeds as AlwaysSucceeds
import Data.Array (length, replicate)
import Data.Lens ((^.))
Expand Down Expand Up @@ -71,11 +72,13 @@ checkChangeOutputsDistribution outputsToScript outputsToSelf expectedOutputs =
)

unbalancedTx <- buildTx plan
balancedTx <- balanceTx unbalancedTx Map.empty
-- just to check that attaching datums works
( mustSendChangeWithDatum $ OutputDatum $ Integer $ BigInt.fromInt
1000
)
balancedTx <- liftEither =<< defaultBalancer unbalancedTx
{ balancerConstraints:
-- just to check that attaching datums works
mustSendChangeWithDatum $ OutputDatum $ Integer $
BigInt.fromInt 1000
, extraUtxos: Map.empty
}
balancedSignedTx <- signTransaction balancedTx
let outputs = balancedTx ^. _body <<< _outputs
length outputs `shouldEqual` expectedOutputs
Expand Down
6 changes: 3 additions & 3 deletions examples/ContractTestUtils.purs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ import Contract.Transaction
( TransactionHash
, TransactionUnspentOutput
, awaitTxConfirmed
, balanceTx
, buildTx
, defaultBalancer
, emptyBalancerCtx
, lookupTxHash
, signTransaction
, submit
Expand All @@ -71,7 +72,6 @@ import Contract.Wallet
)
import Data.Array (head)
import Data.Lens (view)
import Data.Map as Map
import Effect.Exception (throw)

type ContractParams =
Expand Down Expand Up @@ -169,7 +169,7 @@ mkContract p = do
]

unbalancedTx <- buildTx plan
balancedTx <- balanceTx unbalancedTx Map.empty mempty
balancedTx <- liftEither =<< defaultBalancer unbalancedTx emptyBalancerCtx
balancedSignedTx <- signTransaction balancedTx

txId <- submit balancedSignedTx
Expand Down
Loading