This repository has been archived by the owner on Oct 12, 2022. It is now read-only.
/
AddressDiscovery.hs
71 lines (62 loc) · 2.79 KB
/
AddressDiscovery.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
module Ariadne.Wallet.Cardano.Kernel.AddressDiscovery
( AddressWithPathToUtxoMap
, discoverHDAddressWithUtxo
, discoverHDAddressesWithUtxo
) where
import Control.Lens (at, non, (?~))
import Data.Conduit (runConduitRes, (.|))
import qualified Data.Conduit.List as CL
import qualified Data.List.NonEmpty as NE
import qualified Data.Map as Map
import UnliftIO (MonadUnliftIO)
import Pos.Core (AddrAttributes(..), Address, addrAttributesUnwrapped)
import Pos.Core.Txp (TxOutAux(..), txOutAddress)
import Pos.Crypto.HD (HDAddressPayload, HDPassphrase, unpackHDAddressAttr)
import Pos.DB.Class (MonadDBRead)
import Pos.Txp.DB (utxoSource)
import Pos.Txp.Toil.Types (Utxo)
import Ariadne.Wallet.Cardano.Kernel.Bip32 (DerivationPath(..))
type AddressWithPathToUtxoMap = Map (DerivationPath, Address) Utxo
discoverHDAddressWithUtxo ::
(MonadDBRead m, MonadUnliftIO m)
=> HDPassphrase
-> m AddressWithPathToUtxoMap
discoverHDAddressWithUtxo walletPassphrase =
head <$> discoverHDAddressesWithUtxo (one walletPassphrase)
-- | This is heavily based on @Pos.Crypto.HDDiscovery.discoverHDAddresses@.
discoverHDAddressesWithUtxo
:: (MonadDBRead m, MonadUnliftIO m)
=> NonEmpty HDPassphrase
-> m (NonEmpty AddressWithPathToUtxoMap)
discoverHDAddressesWithUtxo walletPassphrases =
runConduitRes $ utxoSource .| CL.fold step initWallets
where
initWallets = map (const Map.empty) walletPassphrases
outAddr = txOutAddress . toaOut . snd
hdPayload :: Address -> Maybe HDAddressPayload
hdPayload (addrAttributesUnwrapped -> AddrAttributes {..}) =
aaPkDerivationPath
insertMaybe
:: OneItem Utxo
-> (Maybe DerivationPath, AddressWithPathToUtxoMap)
-> AddressWithPathToUtxoMap
insertMaybe _ (Nothing, m) = m
insertMaybe utxoItem@(k, v) (Just derPath, m) =
-- This comes straight from the @Control.Lens@ doc on @non@:
-- https://hackage.haskell.org/package/lens-3.10.1/docs/Control-Lens-Iso.html#v:non
-- This code is equivalent to the following:
-- 1. Check whether @(derPath, address)@ is a key in @m@. If it is not,
-- insert @Map.empty@ at this key.
-- 2. Insert @utxoItem@ into the map at the key @(derPath, address)@.
m & at (derPath, outAddr utxoItem) . non Map.empty . at k ?~ v
step
:: NonEmpty AddressWithPathToUtxoMap
-> OneItem Utxo
-> NonEmpty AddressWithPathToUtxoMap
step res utxoItem =
case hdPayload (outAddr utxoItem) of
Just payload -> do
let unpackResults :: NonEmpty (Maybe DerivationPath)
unpackResults = map (fmap DerivationPath . flip unpackHDAddressAttr payload) walletPassphrases
map (insertMaybe utxoItem) $ NE.zip unpackResults res
_ -> res