Skip to content

Commit 55d7368

Browse files
committed
Backend: print shared outputs
When called with --print-transactions and number of transactions is specified, if there are outputs shared between all transactions, print amount and percentage for each such output in each transaction.
1 parent 8071cac commit 55d7368

File tree

2 files changed

+88
-6
lines changed

2 files changed

+88
-6
lines changed

src/GWallet.Backend/UtxoCoin/BtcTransactionPrinting.fs

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ open GWallet.Backend.FSharpUtil.UwpHacks
99

1010

1111
module BtcTransactionPrinting =
12+
type private ProcessedHistoryEntry =
13+
{
14+
Date: DateTime
15+
Outputs: NBitcoin.TxOutList
16+
}
17+
18+
type private EntryWithSharedAddress =
19+
{
20+
Date: DateTime
21+
SharedOutputs: seq<NBitcoin.TxOut>
22+
}
23+
1224
let GetBitcoinPriceForDate (date: DateTime) : Async<Result<decimal, Exception>> =
1325
async {
1426
try
@@ -26,7 +38,8 @@ module BtcTransactionPrinting =
2638
return Error ex
2739
}
2840

29-
let PrintTransactions (maxTransactionsCount: uint32) (btcAddress: string) =
41+
let PrintTransactions (maxTransactionsCountOption: uint32 option) (btcAddress: string) =
42+
let maxTransactionsCount = defaultArg maxTransactionsCountOption UInt32.MaxValue
3043
let address = NBitcoin.BitcoinAddress.Create(btcAddress, NBitcoin.Network.Main)
3144
async {
3245
let scriptHash = Account.GetElectrumScriptHashFromPublicAddress Currency.BTC btcAddress
@@ -70,13 +83,82 @@ module BtcTransactionPrinting =
7083
Console.WriteLine("Could not get bitcoin price for the date. An error has occured:\n" + exn.ToString())
7184
Console.WriteLine(SPrintF1 "date: %A UTC" dateTime)
7285
Console.WriteLine()
73-
return! processHistory rest (maxTransactionsToPrint - 1u)
86+
let! otherEntries = processHistory rest (maxTransactionsToPrint - 1u)
87+
return { Date = dateTime; Outputs = transactionInfo.Outputs } :: otherEntries
7488
else
7589
return! processHistory rest maxTransactionsToPrint
7690
}
77-
| _ -> async { return () }
91+
| _ -> async { return [] }
7892

79-
do! processHistory sortedHistory maxTransactionsCount
93+
let! processedEntries = processHistory sortedHistory maxTransactionsCount
94+
95+
if maxTransactionsCountOption.IsSome then
96+
let getAddress (output: NBitcoin.TxOut) =
97+
output.ScriptPubKey.GetDestinationAddress NBitcoin.Network.Main
98+
99+
let allAddressesExceptOurs =
100+
processedEntries
101+
|> Seq.collect(
102+
fun entry ->
103+
entry.Outputs
104+
|> Seq.map getAddress)
105+
|> Seq.filter (fun each -> each <> address)
106+
|> Seq.distinct
107+
|> Seq.cache
108+
109+
let sharedAddresses =
110+
allAddressesExceptOurs
111+
|> Seq.filter (
112+
fun addr ->
113+
processedEntries
114+
|> Seq.forall(
115+
fun entry ->
116+
entry.Outputs
117+
|> Seq.exists (fun output -> output.IsTo addr) ) )
118+
|> Seq.cache
119+
120+
let entriesWithSharedAddresses =
121+
processedEntries
122+
|> Seq.choose (
123+
fun entry ->
124+
let sharedOutputs =
125+
entry.Outputs
126+
|> Seq.filter (
127+
fun output ->
128+
sharedAddresses |> Seq.exists (fun addr -> output.IsTo addr))
129+
if sharedOutputs |> Seq.isEmpty then
130+
None
131+
else
132+
let outputsToOurAddress = entry.Outputs |> Seq.filter (fun output -> output.IsTo address)
133+
Some {
134+
SharedOutputs = sharedOutputs |> Seq.append outputsToOurAddress
135+
Date = entry.Date
136+
} )
137+
|> Seq.cache
138+
139+
if (entriesWithSharedAddresses |> Seq.length) >= 2 then
140+
Console.WriteLine(SPrintF1 "Transactions with outputs shared with %A:\n" address)
141+
for entry in entriesWithSharedAddresses do
142+
let totalAmount =
143+
entry.SharedOutputs
144+
|> Seq.sumBy (fun txOut -> txOut.Value)
145+
let sharedOutputs =
146+
entry.SharedOutputs
147+
|> Seq.groupBy getAddress
148+
let currentSharedAddresses =
149+
sharedOutputs
150+
|> Seq.map fst
151+
152+
Console.WriteLine(SPrintF1 "Transaction with outputs to %s" (String.Join(", ", currentSharedAddresses)))
153+
Console.WriteLine(SPrintF1 "Date: %A UTC" entry.Date)
154+
Console.WriteLine(SPrintF1 "Total BTC: %A" totalAmount)
155+
for addr, outputs in sharedOutputs do
156+
let amount = outputs |> Seq.sumBy (fun txOut -> txOut.Value)
157+
let percentage =
158+
amount.ToDecimal(NBitcoin.MoneyUnit.BTC) / totalAmount.ToDecimal(NBitcoin.MoneyUnit.BTC) * 100.0m
159+
Console.WriteLine(SPrintF3 "Sent %A BTC to %A (%s%%)" amount addr (percentage.ToString("F2")))
160+
Console.WriteLine()
161+
80162
Console.WriteLine("End of results")
81163
Console.ReadKey() |> ignore
82164
return 0

src/GWallet.Frontend.Console/Program.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,8 @@ module Program =
538538
| 2 | 3 when argv.[0] = "--print-transactions" ->
539539
// --print-transactions <btcAddress> [maxTransactionsCount]
540540
if argv.Length = 2 then
541-
UtxoCoin.BtcTransactionPrinting.PrintTransactions UInt32.MaxValue argv.[1]
541+
UtxoCoin.BtcTransactionPrinting.PrintTransactions None argv.[1]
542542
else
543-
UtxoCoin.BtcTransactionPrinting.PrintTransactions (uint32 argv.[2]) argv.[1]
543+
UtxoCoin.BtcTransactionPrinting.PrintTransactions (Some <| uint32 argv.[2]) argv.[1]
544544
| _ ->
545545
failwith "Arguments not recognized"

0 commit comments

Comments
 (0)