@@ -72,27 +72,28 @@ module Account =
72
72
// TODO: measure how long does it take to get the script hash and if it's too long, cache it at app startup?
73
73
BitcoinAddress.Create( publicAddress, GetNetwork currency) |> GetElectrumScriptHashFromAddress
74
74
75
- let internal GetSegwitP2shPublicAddressFromPublicKey currency ( publicKey : PubKey ) =
75
+ let internal GetNestedSegwitPublicAddressFromPublicKey currency ( publicKey : PubKey ): BitcoinAddress =
76
76
publicKey
77
77
.GetScriptPubKey( ScriptPubKeyType.SegwitP2SH)
78
78
.GetDestinationAddress( GetNetwork currency)
79
- .ToString()
80
79
81
- let internal GetNativeSegwitPublicAddressFromPublicKey currency ( publicKey : PubKey ) =
80
+ let internal GetNativeSegwitPublicAddressFromPublicKey currency ( publicKey : PubKey ): BitcoinAddress =
82
81
publicKey
83
82
.GetScriptPubKey( ScriptPubKeyType.Segwit)
84
83
.GetDestinationAddress( GetNetwork currency)
85
- .ToString()
86
84
87
- let internal GetPublicAddressFromPublicKey =
85
+ let private GetUtxoPublicAddressFromPublicKey =
88
86
if Config.UseNativeSegwit then
89
87
GetNativeSegwitPublicAddressFromPublicKey
90
88
else
91
- GetSegwitP2shPublicAddressFromPublicKey
89
+ GetNestedSegwitPublicAddressFromPublicKey
90
+
91
+ let internal GetPublicAddressFromPublicKey currency pubKey =
92
+ ( GetUtxoPublicAddressFromPublicKey currency pubKey) .ToString()
92
93
93
94
let internal GetPublicAddressFromNormalAccountFile ( currency : Currency ) ( accountFile : FileRepresentation ): string =
94
95
let pubKey = PubKey( accountFile.Name)
95
- GetPublicAddressFromPublicKey currency pubKey
96
+ ( GetUtxoPublicAddressFromPublicKey currency pubKey) .ToString ()
96
97
97
98
let internal GetPublicKeyFromNormalAccountFile ( accountFile : FileRepresentation ): PubKey =
98
99
PubKey accountFile.Name
@@ -102,7 +103,7 @@ module Account =
102
103
103
104
let internal GetPublicAddressFromUnencryptedPrivateKey ( currency : Currency ) ( privateKey: string ) =
104
105
let privateKey = Key.Parse( privateKey, GetNetwork currency)
105
- GetPublicAddressFromPublicKey currency privateKey.PubKey
106
+ ( GetUtxoPublicAddressFromPublicKey currency privateKey.PubKey) .ToString ()
106
107
107
108
let internal GetAccountFromFile ( accountFile : FileRepresentation ) ( currency : Currency ) kind : IAccount =
108
109
if not ( currency.IsUtxo()) then
@@ -152,9 +153,9 @@ module Account =
152
153
: Async < BlockchainScriptHashGetBalanceInnerResult > =
153
154
let scriptHashesHex =
154
155
[
155
- GetNativeSegwitPublicAddressFromPublicKey account.Currency account.PublicKey
156
+ ( GetNativeSegwitPublicAddressFromPublicKey account.Currency account.PublicKey) .ToString ()
156
157
|> GetElectrumScriptHashFromPublicAddress account.Currency
157
- GetSegwitP2shPublicAddressFromPublicKey account.Currency account.PublicKey
158
+ ( GetNestedSegwitPublicAddressFromPublicKey account.Currency account.PublicKey) .ToString ()
158
159
|> GetElectrumScriptHashFromPublicAddress account.Currency
159
160
]
160
161
@@ -200,9 +201,9 @@ module Account =
200
201
let sourceAddress = scriptPubKey.GetDestinationAddress( GetNetwork account.Currency) .ToString()
201
202
let coin =
202
203
Coin( txHash, uint32 inputOutpointInfo.OutputIndex, Money( inputOutpointInfo.ValueInSatoshis), scriptPubKey)
203
- if sourceAddress = GetSegwitP2shPublicAddressFromPublicKey account.Currency account.PublicKey then
204
+ if sourceAddress = ( GetNestedSegwitPublicAddressFromPublicKey account.Currency account.PublicKey) .ToString () then
204
205
coin.ToScriptCoin( account.PublicKey.WitHash.ScriptPubKey) :> ICoin
205
- elif sourceAddress = GetNativeSegwitPublicAddressFromPublicKey account.Currency account.PublicKey then
206
+ elif sourceAddress = ( GetNativeSegwitPublicAddressFromPublicKey account.Currency account.PublicKey) .ToString () then
206
207
coin :> ICoin
207
208
else
208
209
//We filter utxos based on scriptPubKey when retrieving from electrum
@@ -325,9 +326,9 @@ module Account =
325
326
326
327
let currency = account.Currency
327
328
328
- let getUtxos ( publicAddress : string ) =
329
+ let getUtxos ( publicAddress : BitcoinAddress ) =
329
330
async {
330
- let job = GetElectrumScriptHashFromPublicAddress currency publicAddress
331
+ let job = GetElectrumScriptHashFromPublicAddress currency ( publicAddress.ToString ())
331
332
|> ElectrumClient.GetUnspentTransactionOutputs
332
333
333
334
return ! Server.Query currency ( QuerySettings.Default ServerSelectionMode.Fast) job None
@@ -340,7 +341,7 @@ module Account =
340
341
|> getUtxos
341
342
342
343
let! legacySegwitUtxos =
343
- GetSegwitP2shPublicAddressFromPublicKey currency account.PublicKey
344
+ GetNestedSegwitPublicAddressFromPublicKey currency account.PublicKey
344
345
|> getUtxos
345
346
346
347
return Seq.concat [ nativeSegwitUtxos; legacySegwitUtxos ]
@@ -707,11 +708,23 @@ module Account =
707
708
failwith " transaction has multiple different inputs"
708
709
origin
709
710
710
- let matchOriginToAccount ( account : ReadOnlyUtxoAccount ): bool =
711
- let accountAddress = ( account :> IAccount) .PublicAddress
712
- let bitcoinAddress = BitcoinAddress.Create( accountAddress, network)
713
- let destination = bitcoinAddress.ScriptPubKey.GetDestination()
714
- ( destination :> IDestination) = origin
711
+ let anyAccountAddressesMatch ( originOrDestination : IDestination ) ( account : IUtxoAccount ) ( throwIfNot : bool ): bool =
712
+ let nativeSegWitAddress =
713
+ GetNativeSegwitPublicAddressFromPublicKey account.Currency account.PublicKey
714
+ :> IDestination
715
+ let nestedSegWitAddress =
716
+ GetNestedSegwitPublicAddressFromPublicKey account.Currency account.PublicKey
717
+ :> IDestination
718
+ let network = GetNetwork account.Currency
719
+ let originOrDestinationAddress = originOrDestination.ScriptPubKey.GetDestinationAddress network :> IDestination
720
+ let anyMatch =
721
+ nativeSegWitAddress = originOrDestinationAddress || nestedSegWitAddress = originOrDestinationAddress
722
+ if not anyMatch then
723
+ if throwIfNot then
724
+ failwith
725
+ <| SPrintF3 " ReadOnly account's addresses (%s and %s ) don't match with the source adress of the signed transaction (%s )"
726
+ ( nativeSegWitAddress.ToString()) ( nestedSegWitAddress.ToString()) ( originOrDestinationAddress.ToString())
727
+ anyMatch
715
728
716
729
let account =
717
730
let accountOpt =
@@ -721,22 +734,20 @@ module Account =
721
734
GetAccountFromFile accountFile currency AccountKind.ReadOnly
722
735
:?> ReadOnlyUtxoAccount
723
736
)
724
- |> Seq.filter matchOriginToAccount
725
737
|> Seq.tryExactlyOne
726
738
match accountOpt with
727
- | Some account -> account
728
- | None -> failwith " unknown origin account"
729
- let originAddress =
730
- let accountAddress = ( account :> IAccount) .PublicAddress
731
- let bitcoinAddress = BitcoinAddress.Create( accountAddress, network)
732
- bitcoinAddress
739
+ | None -> failwith " Cannot broadcast transactions from a wallet instance that doesn't have read-only accounts"
740
+ | Some account ->
741
+ let utxoAccount = account :> IUtxoAccount
742
+ anyAccountAddressesMatch origin utxoAccount true |> ignore< bool>
743
+ account
733
744
734
745
let destinationAddress , value =
735
746
let filterChangeTxOuts ( txOut : TxOut ): Option < BitcoinAddress * Money > =
736
747
let scriptPubKey = txOut.ScriptPubKey
737
748
let destinationAddress = scriptPubKey.GetDestinationAddress network
738
749
let destination = destinationAddress.ScriptPubKey.GetDestination()
739
- if ( destination :> IDestination ) = origin then
750
+ if anyAccountAddressesMatch destination account false then
740
751
None
741
752
else
742
753
Some ( destinationAddress, txOut.Value)
@@ -748,7 +759,7 @@ module Account =
748
759
failwith " expected a single destination address"
749
760
750
761
{
751
- OriginAddress = originAddress.ToString ()
762
+ OriginAddress = ( account :> IAccount ). PublicAddress
752
763
DestinationAddress = destinationAddress.ToString()
753
764
Amount = value.ToDecimal MoneyUnit.BTC
754
765
Currency = currency
0 commit comments