Skip to content

Commit e038977

Browse files
committed
Implement pickTokensToDeposit
Add some tests to DepositSpec Signed-off-by: Sasha Bogicevic <[email protected]>
1 parent 3fa596d commit e038977

File tree

3 files changed

+37
-52
lines changed

3 files changed

+37
-52
lines changed

hydra-node/src/Hydra/Chain/Direct/Handlers.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ import Hydra.Tx (
8282
headSeedToTxIn,
8383
)
8484
import Hydra.Tx.ContestationPeriod (toNominalDiffTime)
85-
import Hydra.Tx.Deposit (DepositObservation (..), splitTokens, depositTx)
85+
import Hydra.Tx.Deposit (DepositObservation (..), depositTx, splitTokens)
8686
import Hydra.Tx.Observe (
8787
AbortObservation (..),
8888
CloseObservation (..),

hydra-tx/src/Hydra/Tx/Deposit.hs

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ depositTx networkId headId commitBlueprintTx upperSlot deadline amount tokens =
5656

5757
utxoToDeposit = utxoToDeposit' <> tokensToDepositUTxO
5858

59-
tokensToDepositUTxO = undefined -- pickTokensToDeposit leftoverUTxO' tokens
59+
tokensToDepositUTxO = pickTokensToDeposit leftoverUTxO' tokens
6060
leftoverOutput =
6161
let leftoverUTxO = (leftoverUTxO' `withoutUTxO` tokensToDepositUTxO)
6262
in if UTxO.null leftoverUTxO
@@ -72,57 +72,41 @@ depositTx networkId headId commitBlueprintTx upperSlot deadline amount tokens =
7272
depositInputs = (,BuildTxWith $ KeyWitness KeyWitnessForSpending) <$> depositInputsList
7373

7474
pickTokensToDeposit :: UTxO -> Map PolicyId PolicyAssets -> UTxO
75-
pickTokensToDeposit leftoverUTxO depositTokens =
76-
if null depositTokens
77-
then mempty
78-
else
79-
let x = concatMap (go mempty) (UTxO.toList leftoverUTxO)
80-
in combineTxOutAssets x
75+
pickTokensToDeposit leftoverUTxO depositTokens
76+
| Map.null depositTokens = mempty
77+
| otherwise = UTxO.fromList picked -- Assuming UTxO.fromList :: [(TxIn, TxOut CtxUTxO)] -> UTxO; adjust if needed.
8178
where
82-
go :: [(TxIn, TxOut CtxUTxO)] -> (TxIn, TxOut CtxUTxO) -> [(TxIn, TxOut CtxUTxO)]
83-
go defVal (i, o) = do
84-
let outputAssets = valueToPolicyAssets $ txOutValue o
85-
providedUTxOAssets = concatMap (\(pid, PolicyAssets a) -> (\(x, y) -> (pid, x, y)) <$> toList a) (Map.toList outputAssets)
86-
(k, PolicyAssets v) <- Map.assocs depositTokens
87-
88-
if k `elem` Map.keys outputAssets
89-
then do
90-
(wantedAssetName, wantedAssetVal) <- Map.toList v
91-
case find (\(pid, n, val) -> pid == k && wantedAssetName == n && wantedAssetVal <= val) providedUTxOAssets of
92-
Nothing -> defVal
93-
Just (pid', _an, _av) -> do
94-
let newValue = fromList [(AssetId pid' wantedAssetName, wantedAssetVal)]
95-
defVal <> [(i, mkTxOutValueKeepingLovelace o newValue)]
96-
else defVal
97-
98-
combineTxOutAssets :: [(TxIn, TxOut CtxUTxO)] -> UTxO.UTxO
99-
combineTxOutAssets =
100-
foldl'
101-
( \finalUTxO (i, o) ->
102-
case UTxO.findBy (existingTxId i) finalUTxO of
103-
Nothing -> finalUTxO <> UTxO.singleton i o
104-
Just (existingInput, existingOutput) ->
105-
let val = valueToPolicyAssets $ txOutValue o
106-
in UTxO.singleton existingInput (addTxOutValue existingOutput val)
107-
)
108-
mempty
109-
110-
existingTxId :: TxIn -> (TxIn, TxOut CtxUTxO) -> Bool
111-
existingTxId txIn (a, _) = a == txIn
112-
113-
mkTxOutValueKeepingLovelace :: TxOut ctx -> Value -> TxOut ctx
114-
mkTxOutValueKeepingLovelace (TxOut addr val datum refScript) newValue =
115-
TxOut addr (lovelaceToValue (selectLovelace val) <> newValue) datum refScript
116-
117-
addTxOutValue :: TxOut ctx -> Map PolicyId PolicyAssets -> TxOut ctx
118-
addTxOutValue (TxOut addr val datum refScript) newAssets =
119-
TxOut addr (lovelaceToValue (selectLovelace val) <> assetsToVal (valueToPolicyAssets val) <> assetsToVal newAssets) datum refScript
79+
-- Build list of (TxIn, new TxOut) where new TxOut has original lovelace + exact required quantities of matched assets.
80+
picked :: [(TxIn, TxOut CtxUTxO)]
81+
picked =
82+
[ (i, mkTxOutValueKeepingLovelace o newValue)
83+
| (i, o) <- UTxO.toList leftoverUTxO
84+
, let outputAssets = valueToPolicyAssets (txOutValue o) -- Map PolicyId PolicyAssets from this TxOut.
85+
, let pickedPolicyAssets = pickMatchedAssets outputAssets depositTokens -- Map PolicyId PolicyAssets with matched.
86+
, not (Map.null pickedPolicyAssets)
87+
, let newValue = foldMap (uncurry policyAssetsToValue) (Map.toList pickedPolicyAssets)
88+
]
89+
90+
-- For a given output's assets and the required depositTokens, build a map of matched policies/assets (exact required qty).
91+
pickMatchedAssets :: Map PolicyId PolicyAssets -> Map PolicyId PolicyAssets -> Map PolicyId PolicyAssets
92+
pickMatchedAssets outputAssets = Map.foldrWithKey go mempty
12093
where
121-
assetsToVal :: Map PolicyId PolicyAssets -> Value
122-
assetsToVal m = foldMap (uncurry policyAssetsToValue) $ toList m
123-
124-
bumpIndex :: TxIn -> TxIn
125-
bumpIndex (TxIn i (TxIx n)) = TxIn i (TxIx $ n + 1)
94+
go :: PolicyId -> PolicyAssets -> Map PolicyId PolicyAssets -> Map PolicyId PolicyAssets
95+
go pid (PolicyAssets requiredAssets) acc = case Map.lookup pid outputAssets of
96+
Nothing -> acc
97+
Just (PolicyAssets availAssets) ->
98+
let matchedAssets = Map.foldrWithKey (matchAsset availAssets) mempty requiredAssets
99+
in if Map.null matchedAssets then acc else Map.insert pid (PolicyAssets matchedAssets) acc
100+
101+
matchAsset :: Map AssetName Quantity -> AssetName -> Quantity -> Map AssetName Quantity -> Map AssetName Quantity
102+
matchAsset availAssets name reqQty matched = case Map.lookup name availAssets of
103+
Just availQty | reqQty <= availQty -> Map.insert name reqQty matched
104+
_ -> matched
105+
106+
-- Helper to create TxOut with original lovelace + new value (unchanged from original).
107+
mkTxOutValueKeepingLovelace :: TxOut ctx -> Value -> TxOut ctx
108+
mkTxOutValueKeepingLovelace (TxOut addr val datum refScript) newValue =
109+
TxOut addr (lovelaceToValue (selectLovelace val) <> newValue) datum refScript
126110

127111
mkDepositOutput ::
128112
NetworkId ->

hydra-tx/test/Hydra/Tx/DepositSpec.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ spec =
6161

6262
toDeposit `shouldBe` utxoWithTokens [(testPolicyId, testAssetName, Quantity 100)]
6363

64-
fit "handles multiple assets within the same policy" $ do
64+
it "handles multiple assets within the same policy" $ do
6565
let testUTxO =
6666
utxoWithTokens
6767
[ (testPolicyId, testAssetName, Quantity 100)
@@ -86,6 +86,7 @@ spec =
8686
, (testPolicyId, testAssetName2, 150)
8787
]
8888
toDeposit `shouldBe` additionalUTxO
89+
8990
describe "splitTokens" $ do
9091
describe "tests" $ do
9192
it "returns empty results when no tokens are specified" $ do

0 commit comments

Comments
 (0)