Skip to content

Commit 698c014

Browse files
committed
add BalanceConfig
1 parent 20e8219 commit 698c014

File tree

2 files changed

+56
-81
lines changed

2 files changed

+56
-81
lines changed

src/BotPlutusInterface/Balance.hs

Lines changed: 51 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{-# LANGUAGE NamedFieldPuns #-}
33

44
module BotPlutusInterface.Balance (
5-
BalanceTxConstraint (TxWithScript, TxWithoutScript, TxWithSeparateChange),
5+
BalanceConfig (BalanceConfig, bcHasScripts, bcSeparateChange),
66
balanceTxStep,
77
balanceTxIO,
88
balanceTxIO',
@@ -21,7 +21,7 @@ import BotPlutusInterface.Effects (
2121
import BotPlutusInterface.Files (DummyPrivKey, unDummyPrivateKey)
2222
import BotPlutusInterface.Files qualified as Files
2323
import BotPlutusInterface.Types (CollateralUtxo, LogLevel (Debug), PABConfig, collateralTxOutRef)
24-
import Cardano.Api (ExecutionUnitPrices (ExecutionUnitPrices))
24+
import Cardano.Api (ExecutionUnitPrices (ExecutionUnitPrices), UTxO (UTxO))
2525
import Cardano.Api.Shelley (ProtocolParameters (protocolParamPrices))
2626
import Control.Monad (foldM, void, zipWithM)
2727
import Control.Monad.Freer (Eff, Member)
@@ -30,6 +30,7 @@ import Control.Monad.Trans.Either (EitherT, hoistEither, newEitherT, runEitherT)
3030
import Control.Monad.Trans.Except (throwE)
3131
import Data.Bifunctor (bimap)
3232
import Data.Coerce (coerce)
33+
import Data.Default (Default (def))
3334
import Data.Either.Combinators (rightToMaybe)
3435
import Data.Kind (Type)
3536
import Data.List ((\\))
@@ -77,67 +78,41 @@ import BotPlutusInterface.Collateral (removeCollateralFromMap)
7778
import Prettyprinter (pretty, viaShow, (<+>))
7879
import Prelude
7980

80-
data TxWithScript
81+
-- Config for balancing a `Tx`.
82+
data BalanceConfig = BalanceConfig
83+
{ bcHasScripts :: Bool -- ^ This field represents whether the current `Tx` that needs to be balanced uses scripts.
84+
, bcSeparateChange :: Bool -- ^ This field represents whether the ada change should be in separate UTxO.
85+
}
86+
deriving stock (Show, Eq)
8187

82-
data TxWithoutScript
83-
84-
data BalanceTxConstraint (a :: Type) where
85-
TxWithoutScript :: BalanceTxConstraint TxWithoutScript
86-
TxWithScript :: BalanceTxConstraint TxWithScript
87-
TxWithSeparateChange :: BalanceTxConstraint a
88-
89-
instance Eq (BalanceTxConstraint a) where
90-
TxWithScript == TxWithScript = True
91-
TxWithoutScript == TxWithoutScript = True
92-
TxWithSeparateChange == TxWithSeparateChange = True
93-
_ == _ = False
94-
95-
instance Ord (BalanceTxConstraint a) where
96-
_ <= TxWithSeparateChange = True
97-
TxWithScript <= TxWithScript = True
98-
TxWithSeparateChange <= TxWithScript = False
99-
TxWithoutScript <= TxWithoutScript = True
100-
_ <= TxWithoutScript = False
101-
102-
class KnownBalanceConstraint (a :: Type) where
103-
knownConstraint :: BalanceTxConstraint a
104-
105-
instance KnownBalanceConstraint TxWithScript where
106-
knownConstraint = TxWithScript
107-
108-
instance KnownBalanceConstraint TxWithoutScript where
109-
knownConstraint = TxWithoutScript
88+
instance Default BalanceConfig where
89+
def = BalanceConfig {bcHasScripts = False, bcSeparateChange = False}
11090

11191
{- | Collect necessary tx inputs and collaterals, add minimum lovelace values and balance non ada
112-
assets. `balanceTxIO` assumes that the `Tx` we are balancing is of type `TxWithoutScript`.
113-
If you want to add custom constraints while balancing the `Tx` like, saying that `Tx` contains
114-
scripts refer to `balanceTxIO'`.
92+
assets. `balanceTxIO` calls `balanceTxIO' with default `BalanceConfig`.
11593
-}
11694
balanceTxIO ::
117-
forall (w :: Type) (effs :: [Type -> Type]) (a :: Type).
118-
(Member (PABEffect w) effs, KnownBalanceConstraint a) =>
119-
[BalanceTxConstraint a] ->
95+
forall (w :: Type) (effs :: [Type -> Type]).
96+
(Member (PABEffect w) effs) =>
12097
PABConfig ->
12198
PubKeyHash ->
12299
UnbalancedTx ->
123100
Eff effs (Either Text Tx)
124-
balanceTxIO = balanceTxIO' @w . Set.fromList
101+
balanceTxIO = balanceTxIO' @w def
125102

126-
{- | This is just a more flexible version of `balanceTxIO` which let us specify the `BalanceTxConstraint`(s)
127-
- for the `Tx` that we are balancing.
128-
-}
103+
-- | `balanceTxIO'` is more flexible version of `balanceTxIO`, this let us specify custom `BalanceConfig`.
129104
balanceTxIO' ::
130-
forall (w :: Type) (effs :: [Type -> Type]) (a :: Type).
131-
(Member (PABEffect w) effs, KnownBalanceConstraint a) =>
132-
Set (BalanceTxConstraint a) ->
105+
forall (w :: Type) (effs :: [Type -> Type]).
106+
(Member (PABEffect w) effs) =>
107+
BalanceConfig ->
133108
PABConfig ->
134109
PubKeyHash ->
135110
UnbalancedTx ->
136111
Eff effs (Either Text Tx)
137-
balanceTxIO' balanceTxconstraints pabConf ownPkh unbalancedTx =
112+
balanceTxIO' balanceCfg pabConf ownPkh unbalancedTx =
138113
runEitherT $
139114
do
140-
(utxos, mcollateral) <- newEitherT $ utxosAndCollateralAtAddress @w balanceTxconstraints pabConf changeAddr
115+
(utxos, mcollateral) <- newEitherT $ utxosAndCollateralAtAddress @w balanceCfg pabConf changeAddr
141116
privKeys <- newEitherT $ Files.readPrivateKeys @w pabConf
142117

143118
let utxoIndex :: Map TxOutRef TxOut
@@ -146,9 +121,6 @@ balanceTxIO' balanceTxconstraints pabConf ownPkh unbalancedTx =
146121
requiredSigs :: [PubKeyHash]
147122
requiredSigs = map Ledger.unPaymentPubKeyHash $ Map.keys (unBalancedTxRequiredSignatories unbalancedTx)
148123

149-
txType :: BalanceTxConstraint a
150-
txType = knownConstraint @a
151-
152124
lift $ printBpiLog @w Debug $ viaShow utxoIndex
153125

154126
-- We need this folder on the CLI machine, which may not be the local machine
@@ -160,15 +132,16 @@ balanceTxIO' balanceTxconstraints pabConf ownPkh unbalancedTx =
160132
(unBalancedTxValidityTimeRange unbalancedTx)
161133
(unBalancedTxTx unbalancedTx)
162134

163-
-- Adds required collaterals in the `Tx`, if the `Tx` is of type `TxWithScript`.
164-
-- Also adds signatures for fee calculation
165-
preBalancedTx <- case txType of
166-
TxWithScript ->
167-
maybe
168-
(throwE "Tx uses script but no collateral was provided.")
169-
(hoistEither . addSignatories ownPkh privKeys requiredSigs . flip addTxCollaterals tx)
170-
mcollateral
171-
_ -> hoistEither $ addSignatories ownPkh privKeys requiredSigs tx
135+
-- Adds required collaterals in the `Tx`, if `bcHasScripts`
136+
-- is true. Also adds signatures for fee calculation
137+
preBalancedTx <-
138+
if bcHasScripts balanceCfg
139+
then
140+
maybe
141+
(throwE "Tx uses script but no collateral was provided.")
142+
(hoistEither . addSignatories ownPkh privKeys requiredSigs . flip addTxCollaterals tx)
143+
mcollateral
144+
else hoistEither $ addSignatories ownPkh privKeys requiredSigs tx
172145

173146
-- Balance the tx
174147
(balancedTx, minUtxos) <- balanceTxLoop utxoIndex privKeys [] preBalancedTx
@@ -177,15 +150,18 @@ balanceTxIO' balanceTxconstraints pabConf ownPkh unbalancedTx =
177150
let adaChange = getAdaChange utxoIndex balancedTx
178151
bTx = fst <$> balanceTxLoop utxoIndex privKeys minUtxos (addOutput changeAddr balancedTx)
179152

153+
-- Checks if there's ada change left, if there is then we check
154+
-- if `bcSeparateChange` is true, if this is the case then we create a new UTxO at
155+
-- the changeAddr.
180156
balancedTxWithChange <-
181157
case adaChange /= 0 of
182-
True | TxWithSeparateChange `elem` balanceTxconstraints -> bTx
158+
True | bcSeparateChange balanceCfg -> bTx
183159
True | not (hasChangeUTxO changeAddr balancedTx) -> bTx
184160
_ -> pure balancedTx
185161

186162
-- Get the updated change, add it to the tx
187163
let finalAdaChange = getAdaChange utxoIndex balancedTxWithChange
188-
fullyBalancedTx = addAdaChange balanceTxconstraints changeAddr finalAdaChange balancedTxWithChange
164+
fullyBalancedTx = addAdaChange balanceCfg changeAddr finalAdaChange balancedTxWithChange
189165

190166
-- finally, we must update the signatories
191167
hoistEither $ addSignatories ownPkh privKeys requiredSigs fullyBalancedTx
@@ -230,31 +206,30 @@ balanceTxIO' balanceTxconstraints pabConf ownPkh unbalancedTx =
230206

231207
-- `utxosAndCollateralAtAddress` returns all the utxos that can be used as an input of a `Tx`,
232208
-- i.e. we filter out `CollateralUtxo` present at the user's address, so it can't be used as input of a `Tx`.
233-
-- This function throws error if `TxWithScript` constraint is present but there's no `CollateralUtxo`
234-
-- in the environment.
235209
utxosAndCollateralAtAddress ::
236-
forall (w :: Type) (effs :: [Type -> Type]) (a :: Type).
237-
(Member (PABEffect w) effs, KnownBalanceConstraint a) =>
238-
Set (BalanceTxConstraint a) ->
210+
forall (w :: Type) (effs :: [Type -> Type]).
211+
(Member (PABEffect w) effs) =>
212+
BalanceConfig ->
239213
PABConfig ->
240214
Address ->
241215
Eff effs (Either Text (Map TxOutRef Tx.ChainIndexTxOut, Maybe CollateralUtxo))
242-
utxosAndCollateralAtAddress _ pabConf changeAddr =
216+
utxosAndCollateralAtAddress balanceCfg pabConf changeAddr =
243217
runEitherT $ do
244218
utxos <- newEitherT $ CardanoCLI.utxosAt @w pabConf changeAddr
245219
inMemCollateral <- lift $ getInMemCollateral @w
246220

247-
case knownConstraint @a of
248-
TxWithScript ->
221+
-- check if `bcHasScripts` is true, if this is the case then we search of
222+
-- collateral UTxO in the environment, if such collateral is not present we throw Error.
223+
if bcHasScripts balanceCfg
224+
then
249225
maybe
250226
( throwE $
251227
"The given transaction uses script, but there's no collateral provided."
252228
<> "This usually means that, we failed to create Tx and update our ContractEnvironment."
253229
)
254230
(const $ pure (removeCollateralFromMap inMemCollateral utxos, inMemCollateral))
255231
inMemCollateral
256-
TxWithoutScript -> pure (removeCollateralFromMap inMemCollateral utxos, Nothing)
257-
_ -> pure (utxos, Nothing)
232+
else pure (removeCollateralFromMap inMemCollateral utxos, Nothing)
258233

259234
hasChangeUTxO :: Address -> Tx -> Bool
260235
hasChangeUTxO changeAddr tx =
@@ -421,14 +396,14 @@ handleNonAdaChange changeAddr utxos tx =
421396
then Right $ if Value.isZero nonAdaChange then tx else tx {txOutputs = outputs}
422397
else Left "Not enough inputs to balance tokens."
423398

424-
{- | `addAdaChange` checks if `TxWithSeparateChange` is present in the provided balancing
425-
constraints, if it is then we add the ada change to seperate `TxOut`, else we add it to
426-
any `TxOut` present at changeAddr.
399+
{- | `addAdaChange` checks if `bcSeparateChange` is true,
400+
if it is then we add the ada change to seperate `TxOut` at changeAddr that contains only ada,
401+
else we add it to any `TxOut` present at changeAddr.
427402
-}
428-
addAdaChange :: forall (a :: Type). Set (BalanceTxConstraint a) -> Address -> Integer -> Tx -> Tx
403+
addAdaChange :: BalanceConfig -> Address -> Integer -> Tx -> Tx
429404
addAdaChange _ _ 0 tx = tx
430-
addAdaChange balanceTxconstraints changeAddr change tx
431-
| TxWithSeparateChange `elem` balanceTxconstraints =
405+
addAdaChange balanceCfg changeAddr change tx
406+
| bcSeparateChange balanceCfg =
432407
tx
433408
{ txOutputs =
434409
List.reverse $

src/BotPlutusInterface/Contract.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import Control.Monad.Trans.Either (EitherT, eitherT, firstEitherT, hoistEither,
5151
import Control.Monad.Trans.Except (ExceptT, throwE)
5252
import Data.Aeson (ToJSON, Value (Array, Bool, Null, Number, Object, String))
5353
import Data.Aeson.Extras (encodeByteString)
54+
import Data.Default (def)
5455
import Data.Either.Combinators (maybeToLeft, swapEither)
5556
import Data.Function (fix)
5657
import Data.HashMap.Strict qualified as HM
@@ -297,14 +298,13 @@ balanceTx contractEnv unbalancedTx = do
297298
eitherPreBalancedTx <-
298299
if PreBalance.txUsesScripts (unBalancedTxTx unbalancedTx)
299300
then
300-
PreBalance.balanceTxIO @w
301-
[PreBalance.TxWithScript]
301+
PreBalance.balanceTxIO' @w
302+
def {PreBalance.bcHasScripts = True}
302303
pabConf
303304
pabConf.pcOwnPubKeyHash
304305
unbalancedTx
305306
else
306307
PreBalance.balanceTxIO @w
307-
[PreBalance.TxWithoutScript]
308308
pabConf
309309
pabConf.pcOwnPubKeyHash
310310
unbalancedTx
@@ -508,8 +508,8 @@ makeCollateral cEnv = runEitherT $ do
508508

509509
balancedTx <-
510510
newEitherT $
511-
PreBalance.balanceTxIO @w
512-
[PreBalance.TxWithoutScript, PreBalance.TxWithSeparateChange]
511+
PreBalance.balanceTxIO' @w
512+
def {PreBalance.bcHasScripts = False, PreBalance.bcSeparateChange = True}
513513
pabConf
514514
pabConf.pcOwnPubKeyHash unbalancedTx
515515

0 commit comments

Comments
 (0)