Skip to content

Commit 936f093

Browse files
authored
Merge pull request #129 from mlabs-haskell/gergely/add-missing-effects
Add missing effects
2 parents 1f18513 + 35128b1 commit 936f093

File tree

7 files changed

+78
-141
lines changed

7 files changed

+78
-141
lines changed

bot-plutus-interface.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ test-suite bot-plutus-interface-test
217217
, plutus-script-utils
218218
, plutus-tx
219219
, plutus-tx-plugin
220+
, pretty-diff
220221
, prettyprinter
221222
, QuickCheck
222223
, quickcheck-instances

flake.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/BotPlutusInterface/Balance.hs

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module BotPlutusInterface.Balance (
77
withFee,
88
) where
99

10+
import BotPlutusInterface.BodyBuilder qualified as BodyBuilder
1011
import BotPlutusInterface.CardanoCLI qualified as CardanoCLI
1112
import BotPlutusInterface.Effects (
1213
PABEffect,
@@ -19,14 +20,14 @@ import BotPlutusInterface.Files qualified as Files
1920
import BotPlutusInterface.Types (LogLevel (Debug), PABConfig)
2021
import Cardano.Api (ExecutionUnitPrices (ExecutionUnitPrices))
2122
import Cardano.Api.Shelley (ProtocolParameters (protocolParamPrices))
22-
import Control.Monad (foldM, void, zipWithM)
23+
import Control.Monad (foldM, void)
2324
import Control.Monad.Freer (Eff, Member)
2425
import Control.Monad.Trans.Class (lift)
2526
import Control.Monad.Trans.Either (EitherT, hoistEither, newEitherT, runEitherT)
27+
import Data.Bifunctor (bimap)
2628
import Data.Coerce (coerce)
2729
import Data.Either.Combinators (rightToMaybe)
2830
import Data.Kind (Type)
29-
import Data.List ((\\))
3031
import Data.Map (Map)
3132
import Data.Map qualified as Map
3233
import Data.Maybe (fromMaybe, mapMaybe)
@@ -46,7 +47,6 @@ import Ledger.Interval (
4647
LowerBound (LowerBound),
4748
UpperBound (UpperBound),
4849
)
49-
import Ledger.Scripts (Datum, DatumHash)
5050
import Ledger.Time (POSIXTimeRange)
5151
import Ledger.Tx (
5252
Tx (..),
@@ -63,9 +63,6 @@ import Plutus.V1.Ledger.Api (
6363
CurrencySymbol (..),
6464
TokenName (..),
6565
)
66-
67-
import BotPlutusInterface.BodyBuilder qualified as BodyBuilder
68-
import Data.Bifunctor (bimap)
6966
import Prettyprinter (pretty, viaShow, (<+>))
7067
import Prelude
7168

@@ -103,15 +100,15 @@ balanceTxIO pabConf ownPkh unbalancedTx =
103100
preBalancedTx <- hoistEither $ addTxCollaterals utxoIndex tx >>= addSignatories ownPkh privKeys requiredSigs
104101

105102
-- Balance the tx
106-
(balancedTx, minUtxos) <- loop utxoIndex privKeys [] preBalancedTx
103+
balancedTx <- loop utxoIndex privKeys preBalancedTx
107104

108105
-- Get current Ada change
109106
let adaChange = getAdaChange utxoIndex balancedTx
110107
-- If we have change but no change UTxO, we need to add an output for it
111108
-- We'll add a minimal output, run the loop again so it gets minUTxO, then update change
112109
balancedTxWithChange <-
113110
if adaChange /= 0 && not (hasChangeUTxO changeAddr balancedTx)
114-
then fst <$> loop utxoIndex privKeys minUtxos (addOutput changeAddr balancedTx)
111+
then loop utxoIndex privKeys (addOutput changeAddr balancedTx)
115112
else pure balancedTx
116113

117114
-- Get the updated change, add it to the tx
@@ -122,26 +119,18 @@ balanceTxIO pabConf ownPkh unbalancedTx =
122119
hoistEither $ addSignatories ownPkh privKeys requiredSigs fullyBalancedTx
123120
where
124121
changeAddr :: Address
125-
changeAddr = Ledger.pubKeyHashAddress (Ledger.PaymentPubKeyHash ownPkh) (pabConf.pcOwnStakePubKeyHash)
122+
changeAddr = Ledger.pubKeyHashAddress (Ledger.PaymentPubKeyHash ownPkh) pabConf.pcOwnStakePubKeyHash
126123
loop ::
127124
Map TxOutRef TxOut ->
128125
Map PubKeyHash DummyPrivKey ->
129-
[(TxOut, Integer)] ->
130126
Tx ->
131-
EitherT Text (Eff effs) (Tx, [(TxOut, Integer)])
132-
loop utxoIndex privKeys prevMinUtxos tx = do
127+
EitherT Text (Eff effs) Tx
128+
loop utxoIndex privKeys tx = do
133129
void $ lift $ Files.writeAll @w pabConf tx
134-
nextMinUtxos <-
135-
newEitherT $
136-
calculateMinUtxos @w pabConf (Tx.txData tx) $ Tx.txOutputs tx \\ map fst prevMinUtxos
137-
138-
let minUtxos = prevMinUtxos ++ nextMinUtxos
139-
140-
lift $ printBpiLog @w Debug $ "Min utxos:" <+> pretty minUtxos
141130

142131
-- Calculate fees by pre-balancing the tx, building it, and running the CLI on result
143132
txWithoutFees <-
144-
hoistEither $ balanceTxStep minUtxos utxoIndex changeAddr $ tx `withFee` 0
133+
hoistEither $ balanceTxStep utxoIndex changeAddr $ tx `withFee` 0
145134

146135
exBudget <- newEitherT $ BodyBuilder.buildAndEstimateBudget @w pabConf privKeys txWithoutFees
147136

@@ -152,11 +141,11 @@ balanceTxIO pabConf ownPkh unbalancedTx =
152141
lift $ printBpiLog @w Debug $ "Fees:" <+> pretty fees
153142

154143
-- Rebalance the initial tx with the above fees
155-
balancedTx <- hoistEither $ balanceTxStep minUtxos utxoIndex changeAddr $ tx `withFee` fees
144+
balancedTx <- hoistEither $ balanceTxStep utxoIndex changeAddr $ tx `withFee` fees
156145

157146
if balancedTx == tx
158-
then pure (balancedTx, minUtxos)
159-
else loop utxoIndex privKeys minUtxos balancedTx
147+
then pure balancedTx
148+
else loop utxoIndex privKeys balancedTx
160149

161150
getExecutionUnitPrices :: PABConfig -> ExecutionUnitPrices
162151
getExecutionUnitPrices pabConf =
@@ -176,24 +165,13 @@ multRational (num :% denom) s = (s * num) :% denom
176165
withFee :: Tx -> Integer -> Tx
177166
withFee tx fee = tx {txFee = Ada.lovelaceValueOf fee}
178167

179-
calculateMinUtxos ::
180-
forall (w :: Type) (effs :: [Type -> Type]).
181-
Member (PABEffect w) effs =>
182-
PABConfig ->
183-
Map DatumHash Datum ->
184-
[TxOut] ->
185-
Eff effs (Either Text [(TxOut, Integer)])
186-
calculateMinUtxos pabConf datums txOuts =
187-
zipWithM (fmap . (,)) txOuts <$> mapM (CardanoCLI.calculateMinUtxo @w pabConf datums) txOuts
188-
189168
balanceTxStep ::
190-
[(TxOut, Integer)] ->
191169
Map TxOutRef TxOut ->
192170
Address ->
193171
Tx ->
194172
Either Text Tx
195-
balanceTxStep minUtxos utxos changeAddr tx =
196-
Right (addLovelaces minUtxos tx)
173+
balanceTxStep utxos changeAddr tx =
174+
Right tx
197175
>>= balanceTxIns utxos
198176
>>= handleNonAdaChange changeAddr utxos
199177

@@ -256,23 +234,6 @@ txOutToTxIn (txOutRef, txOut) =
256234
PubKeyCredential _ -> Right $ Tx.pubKeyTxIn txOutRef
257235
ScriptCredential _ -> Left "Cannot covert a script output to TxIn"
258236

259-
-- | Add min lovelaces to each tx output
260-
addLovelaces :: [(TxOut, Integer)] -> Tx -> Tx
261-
addLovelaces minLovelaces tx =
262-
let lovelacesAdded =
263-
map
264-
( \txOut ->
265-
let outValue = txOutValue txOut
266-
lovelaces = Ada.getLovelace $ Ada.fromValue outValue
267-
minUtxo = fromMaybe 0 $ lookup txOut minLovelaces
268-
in txOut
269-
{ txOutValue =
270-
outValue <> Ada.lovelaceValueOf (max 0 (minUtxo - lovelaces))
271-
}
272-
)
273-
$ txOutputs tx
274-
in tx {txOutputs = lovelacesAdded}
275-
276237
balanceTxIns :: Map TxOutRef TxOut -> Tx -> Either Text Tx
277238
balanceTxIns utxos tx = do
278239
let txOuts = Tx.txOutputs tx

src/BotPlutusInterface/CardanoCLI.hs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
module BotPlutusInterface.CardanoCLI (
55
submitTx,
6-
calculateMinUtxo,
76
calculateMinFee,
87
buildTx,
98
signTx,
@@ -124,27 +123,6 @@ utxosAt pabConf address =
124123
. Text.pack
125124
}
126125

127-
calculateMinUtxo ::
128-
forall (w :: Type) (effs :: [Type -> Type]).
129-
Member (PABEffect w) effs =>
130-
PABConfig ->
131-
Map DatumHash Datum ->
132-
TxOut ->
133-
Eff effs (Either Text Integer)
134-
calculateMinUtxo pabConf datums txOut =
135-
join
136-
<$> callCommand @w
137-
ShellArgs
138-
{ cmdName = "cardano-cli"
139-
, cmdArgs =
140-
mconcat
141-
[ ["transaction", "calculate-min-required-utxo", "--babbage-era"]
142-
, txOutOpts pabConf datums [txOut]
143-
, ["--protocol-params-file", pabConf.pcProtocolParamsFile]
144-
]
145-
, cmdOutParser = mapLeft Text.pack . parseOnly UtxoParser.feeParser . Text.pack
146-
}
147-
148126
-- | Calculating fee for an unbalanced transaction
149127
calculateMinFee ::
150128
forall (w :: Type) (effs :: [Type -> Type]).

src/BotPlutusInterface/Contract.hs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ import Data.Vector qualified as V
5656
import Ledger (POSIXTime)
5757
import Ledger qualified
5858
import Ledger.Address (PaymentPubKeyHash (PaymentPubKeyHash))
59-
import Ledger.Constraints.OffChain (UnbalancedTx (..))
59+
import Ledger.Constraints.OffChain (UnbalancedTx (..), adjustUnbalancedTx)
60+
import Ledger.Params (Params (Params))
6061
import Ledger.Slot (Slot (Slot))
62+
import Ledger.TimeSlot (SlotConfig (..))
6163
import Ledger.Tx (CardanoTx (CardanoApiTx, EmulatorTx))
6264
import Ledger.Tx qualified as Tx
6365
import Plutus.ChainIndex.TxIdState (fromTx, transactionStatus)
@@ -189,20 +191,32 @@ handlePABReq contractEnv req = do
189191
either (error . show) (PosixTimeRangeToContainedSlotRangeResp . Right)
190192
<$> posixTimeRangeToContainedSlotRange @w posixTimeRange
191193
AwaitTxStatusChangeReq txId -> AwaitTxStatusChangeResp txId <$> awaitTxStatusChange @w contractEnv txId
194+
AdjustUnbalancedTxReq unbalancedTx -> AdjustUnbalancedTxResp <$> adjustUnbalancedTx' @w contractEnv unbalancedTx
192195
------------------------
193196
-- Unhandled requests --
194197
------------------------
195-
-- AwaitTimeReq t -> pure $ AwaitTimeResp t
196-
-- AwaitUtxoSpentReq txOutRef -> pure $ AwaitUtxoSpentResp ChainIndexTx
197-
-- AwaitUtxoProducedReq Address -> pure $ AwaitUtxoProducedResp (NonEmpty ChainIndexTx)
198-
-- AwaitTxOutStatusChangeReq TxOutRef
199-
-- ExposeEndpointReq ActiveEndpoint -> ExposeEndpointResp EndpointDescription (EndpointValue JSON.Value)
200-
-- YieldUnbalancedTxReq UnbalancedTx
201-
unsupported -> error ("Unsupported PAB effect: " ++ show unsupported)
198+
AwaitUtxoSpentReq _ -> error ("Unsupported PAB effect: " ++ show req)
199+
AwaitUtxoProducedReq _ -> error ("Unsupported PAB effect: " ++ show req)
200+
AwaitTxOutStatusChangeReq _ -> error ("Unsupported PAB effect: " ++ show req)
201+
ExposeEndpointReq _ -> error ("Unsupported PAB effect: " ++ show req)
202+
YieldUnbalancedTxReq _ -> error ("Unsupported PAB effect: " ++ show req)
202203

203204
printBpiLog @w Debug $ pretty resp
204205
pure resp
205206

207+
adjustUnbalancedTx' ::
208+
forall (w :: Type) (effs :: [Type -> Type]).
209+
ContractEnvironment w ->
210+
UnbalancedTx ->
211+
Eff effs (Either Tx.ToCardanoError UnbalancedTx)
212+
adjustUnbalancedTx' contractEnv unbalancedTx = do
213+
let slotConfig = SlotConfig 20000 1654524000
214+
networkId = contractEnv.cePABConfig.pcNetwork
215+
maybeParams = contractEnv.cePABConfig.pcProtocolParams >>= \pparams -> pure $ Params slotConfig pparams networkId
216+
case maybeParams of
217+
Just params -> pure $ snd <$> adjustUnbalancedTx params unbalancedTx
218+
_ -> pure . Left $ Tx.TxBodyError "no protocol params"
219+
206220
{- | Await till transaction status change to something from `Unknown`.
207221
Uses `chain-index` to query transaction by id.
208222
Important notes:

test/Spec/BotPlutusInterface/Balance.hs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,34 +59,31 @@ addUtxosForFees :: Assertion
5959
addUtxosForFees = do
6060
let txout = TxOut addr2 (Ada.lovelaceValueOf 1_000_000) Nothing
6161
tx = mempty {txOutputs = [txout]} `withFee` 500_000
62-
minUtxo = [(txout, 1_000_000)]
6362
utxoIndex = Map.fromList [utxo1, utxo2, utxo3]
6463
ownAddr = addr1
6564
balancedTx =
66-
Balance.balanceTxStep minUtxo utxoIndex ownAddr tx
65+
Balance.balanceTxStep utxoIndex ownAddr tx
6766

6867
txInputs <$> balancedTx @?= Right (Set.fromList [txIn1, txIn2])
6968

7069
addUtxosForNativeTokens :: Assertion
7170
addUtxosForNativeTokens = do
7271
let txout = TxOut addr2 (Value.singleton "11223344" "Token" 123) Nothing
7372
tx = mempty {txOutputs = [txout]} `withFee` 500_000
74-
minUtxo = [(txout, 1_000_000)]
7573
utxoIndex = Map.fromList [utxo1, utxo2, utxo3, utxo4]
7674
ownAddr = addr1
7775
balancedTx =
78-
Balance.balanceTxStep minUtxo utxoIndex ownAddr tx
76+
Balance.balanceTxStep utxoIndex ownAddr tx
7977

8078
txInputs <$> balancedTx @?= Right (Set.fromList [txIn1, txIn2, txIn3, txIn4])
8179

8280
addUtxosForChange :: Assertion
8381
addUtxosForChange = do
8482
let txout = TxOut addr2 (Ada.lovelaceValueOf 1_600_000) Nothing
8583
tx = mempty {txOutputs = [txout]} `withFee` 500_000
86-
minUtxo = [(txout, 1_000_000)]
8784
utxoIndex = Map.fromList [utxo1, utxo2, utxo3]
8885
ownAddr = addr1
8986
balancedTx =
90-
Balance.balanceTxStep minUtxo utxoIndex ownAddr tx
87+
Balance.balanceTxStep utxoIndex ownAddr tx
9188

9289
txInputs <$> balancedTx @?= Right (Set.fromList [txIn1, txIn2])

0 commit comments

Comments
 (0)