@@ -28,12 +28,7 @@ module Bitcoin.Transaction.Builder (
28
28
29
29
-- * Coin Selection
30
30
Coin (.. ),
31
- chooseCoins ,
32
- chooseCoinsSink ,
33
- chooseMSCoins ,
34
- chooseMSCoinsSink ,
35
31
countMulSig ,
36
- greedyAddSink ,
37
32
guessTxFee ,
38
33
guessMSTxFee ,
39
34
guessTxSize ,
@@ -49,14 +44,6 @@ import qualified Data.ByteString as B
49
44
import Data.Bytes.Get
50
45
import Data.Bytes.Put
51
46
import Data.Bytes.Serial
52
- import Data.Conduit (
53
- ConduitT ,
54
- Void ,
55
- await ,
56
- runConduit ,
57
- (.|) ,
58
- )
59
- import Data.Conduit.List (sourceList )
60
47
import Data.Either (fromRight )
61
48
import Data.List (nub )
62
49
import Data.Maybe (catMaybes , fromJust , isJust )
@@ -92,163 +79,6 @@ class Coin c where
92
79
coinValue :: c -> Word64
93
80
94
81
95
- -- | Coin selection algorithm for normal (non-multisig) transactions. This
96
- -- function returns the selected coins together with the amount of change to
97
- -- send back to yourself, taking the fee into account.
98
- chooseCoins ::
99
- Coin c =>
100
- -- | value to send
101
- Word64 ->
102
- -- | fee per byte
103
- Word64 ->
104
- -- | number of outputs (including change)
105
- Int ->
106
- -- | try to find better solutions
107
- Bool ->
108
- -- | list of ordered coins to choose from
109
- [c ] ->
110
- -- | coin selection and change
111
- Either String ([c ], Word64 )
112
- chooseCoins target fee nOut continue coins =
113
- runIdentity . runConduit $
114
- sourceList coins .| chooseCoinsSink target fee nOut continue
115
-
116
-
117
- -- | Coin selection algorithm for normal (non-multisig) transactions. This
118
- -- function returns the selected coins together with the amount of change to
119
- -- send back to yourself, taking the fee into account. This version uses a Sink
120
- -- for conduit-based coin selection.
121
- chooseCoinsSink ::
122
- (Monad m , Coin c ) =>
123
- -- | value to send
124
- Word64 ->
125
- -- | fee per byte
126
- Word64 ->
127
- -- | number of outputs (including change)
128
- Int ->
129
- -- | try to find better solution
130
- Bool ->
131
- -- | coin selection and change
132
- ConduitT c Void m (Either String ([c ], Word64 ))
133
- chooseCoinsSink target fee nOut continue
134
- | target > 0 =
135
- maybeToEither err
136
- <$> greedyAddSink target (guessTxFee fee nOut) continue
137
- | otherwise = return $ Left " chooseCoins: Target must be > 0"
138
- where
139
- err = " chooseCoins: No solution found"
140
-
141
-
142
- -- | Coin selection algorithm for multisig transactions. This function returns
143
- -- the selected coins together with the amount of change to send back to
144
- -- yourself, taking the fee into account. This function assumes all the coins
145
- -- are script hash outputs that send funds to a multisignature address.
146
- chooseMSCoins ::
147
- Coin c =>
148
- -- | value to send
149
- Word64 ->
150
- -- | fee per byte
151
- Word64 ->
152
- -- | m of n multisig
153
- (Int , Int ) ->
154
- -- | number of outputs (including change)
155
- Int ->
156
- -- | try to find better solution
157
- Bool ->
158
- [c ] ->
159
- -- | coin selection change amount
160
- Either String ([c ], Word64 )
161
- chooseMSCoins target fee ms nOut continue coins =
162
- runIdentity . runConduit $
163
- sourceList coins .| chooseMSCoinsSink target fee ms nOut continue
164
-
165
-
166
- -- | Coin selection algorithm for multisig transactions. This function returns
167
- -- the selected coins together with the amount of change to send back to
168
- -- yourself, taking the fee into account. This function assumes all the coins
169
- -- are script hash outputs that send funds to a multisignature address. This
170
- -- version uses a Sink if you need conduit-based coin selection.
171
- chooseMSCoinsSink ::
172
- (Monad m , Coin c ) =>
173
- -- | value to send
174
- Word64 ->
175
- -- | fee per byte
176
- Word64 ->
177
- -- | m of n multisig
178
- (Int , Int ) ->
179
- -- | number of outputs (including change)
180
- Int ->
181
- -- | try to find better solution
182
- Bool ->
183
- -- | coin selection and change
184
- ConduitT c Void m (Either String ([c ], Word64 ))
185
- chooseMSCoinsSink target fee ms nOut continue
186
- | target > 0 =
187
- maybeToEither err
188
- <$> greedyAddSink target (guessMSTxFee fee ms nOut) continue
189
- | otherwise = return $ Left " chooseMSCoins: Target must be > 0"
190
- where
191
- err = " chooseMSCoins: No solution found"
192
-
193
-
194
- -- | Select coins greedily by starting from an empty solution. If the 'continue'
195
- -- flag is set, the algorithm will try to find a better solution in the stream
196
- -- after a solution is found. If the next solution found is not strictly better
197
- -- than the previously found solution, the algorithm stops and returns the
198
- -- previous solution. If the continue flag is not set, the algorithm will return
199
- -- the first solution it finds in the stream.
200
- greedyAddSink ::
201
- (Monad m , Coin c ) =>
202
- -- | value to send
203
- Word64 ->
204
- -- | coin count to fee function
205
- (Int -> Word64 ) ->
206
- -- | try to find better solutions
207
- Bool ->
208
- -- | coin selection and change
209
- ConduitT c Void m (Maybe ([c ], Word64 ))
210
- greedyAddSink target guessFee continue =
211
- go [] 0 [] 0
212
- where
213
- -- The goal is the value we must reach (including the fee) for a certain
214
- -- amount of selected coins.
215
- goal c = target + guessFee c
216
- go acc aTot ps pTot =
217
- await >>= \ case
218
- -- A coin is available in the stream
219
- Just coin -> do
220
- let val = coinValue coin
221
- -- We have reached the goal using this coin
222
- if val + aTot >= goal (length acc + 1 )
223
- then -- If we want to continue searching for better solutions
224
-
225
- if continue
226
- then -- This solution is the first one or
227
- -- This solution is better than the previous one
228
-
229
- if pTot == 0 || val + aTot < pTot
230
- then -- Continue searching for better solutions in the stream
231
- go [] 0 (coin : acc) (val + aTot)
232
- else -- Otherwise, we stop here and return the previous
233
- -- solution
234
- return $ Just (ps, pTot - goal (length ps))
235
- else -- Otherwise, return this solution
236
-
237
- return $
238
- Just (coin : acc, val + aTot - goal (length acc + 1 ))
239
- else -- We have not yet reached the goal. Add the coin to the
240
- -- accumulator
241
- go (coin : acc) (val + aTot) ps pTot
242
- -- We reached the end of the stream
243
- Nothing ->
244
- return $
245
- if null ps
246
- then -- If no solution was found, return Nothing
247
- Nothing
248
- else -- If we have a solution, return it
249
- Just (ps, pTot - goal (length ps))
250
-
251
-
252
82
-- | Estimate tranasction fee to pay based on transaction size estimation.
253
83
guessTxFee :: Word64 -> Int -> Int -> Word64
254
84
guessTxFee byteFee nOut nIn =
0 commit comments