Skip to content
This repository has been archived by the owner on Aug 18, 2020. It is now read-only.

Commit

Permalink
[CBR-462] Fix fee estimation when transaction's amount matches accoun…
Browse files Browse the repository at this point in the history
…t's balance

When calling

```
reduceChangeOutputs
  :: forall dom. CoinSelDom dom
  => Fee dom
  -> [Value dom]
  -> ([Value dom], Fee dom)
```

If the `[Value dom]` is a singleton array with a zero coin, we're going
to end up dividing by zero and silently obliterating fee as we do it.
This happens when making a transaction with no change, i.e., when the
transaction's amount matches exactly the source account's balance.

This commit provides a fix handling this special edge-case.
  • Loading branch information
KtorZ committed Oct 3, 2018
1 parent 112791e commit 78c113e
Showing 1 changed file with 18 additions and 4 deletions.
22 changes: 18 additions & 4 deletions wallet-new/src/Cardano/Wallet/Kernel/CoinSelection/Generic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -590,16 +590,30 @@ nLargestFromListBy f n = \xs ->
dropOne (Just [_]) = Nothing
dropOne (Just (_:as)) = Just as

-- | Proportionally divide the fee over each output
-- | Proportionally divide the fee over each output.
--
-- There's a special 'edge-case' when the given input is a singleton list
-- with one 0 coin. This is artifically created during input selection when
-- the transaction's amount matches exactly the source's balance.
-- In such case, we can't really compute any ratio for fees and simply return
-- the whole fee back with the given change value.
divvyFee :: forall dom a. CoinSelDom dom
=> (a -> Value dom) -> Fee dom -> [a] -> [(Fee dom, a)]
divvyFee _ _ [] = error "divvyFee: empty list"
divvyFee f fee as = map (\a -> (feeForOut a, a)) as
divvyFee _ _ [] = error "divvyFee: empty list"
divvyFee f fee [a] | f a == valueZero = [(fee, a)]
divvyFee f fee as = map (\a -> (feeForOut a, a)) as
where
-- All outputs are selected from well-formed UTxO, so their sum cannot
-- overflow
totalOut :: Value dom
totalOut = unsafeValueSum (map f as)
totalOut =
let
total = unsafeValueSum (map f as)
in
if total == valueZero then
error "divyyFee: invalid set of coins, total is 0"
else
total

-- The ratio will be between 0 and 1 so cannot overflow
feeForOut :: a -> Fee dom
Expand Down

0 comments on commit 78c113e

Please sign in to comment.