Copyright | © 2018-2020 IOHK |
---|---|
License | Apache-2.0 |
Safe Haskell | None |
Language | Haskell2010 |
An implementation of address discovery for the sequential address derivation scheme specified in BIP-0044.
The management of _accounts_ is left-out for this implementation focuses on a single account. In practice, one wants to manage a set of pools, one per account.
Synopsis
- data AddressPoolGap
- newtype MkAddressPoolGapError = ErrGapOutOfRange Integer
- defaultAddressPoolGap :: AddressPoolGap
- getAddressPoolGap :: AddressPoolGap -> Word32
- mkAddressPoolGap :: Integer -> Either MkAddressPoolGapError AddressPoolGap
- mkUnboundedAddressPoolGap :: Word32 -> AddressPoolGap
- newtype SeqAddressPool (c :: Role ) (key :: Depth -> Type -> Type ) = SeqAddressPool { }
- getGap :: SeqAddressPool c k -> AddressPoolGap
- newSeqAddressPool :: forall (n :: NetworkDiscriminant ) c key. (SupportsDiscovery n key, Typeable c) => key ' AccountK XPub -> AddressPoolGap -> SeqAddressPool c key
- unsafePaymentKeyFingerprint :: forall k from. ( HasCallStack , MkKeyFingerprint k from) => from -> KeyFingerprint "payment" k
-
data
SeqState
(n ::
NetworkDiscriminant
) k =
SeqState
{
- internalPool :: !( SeqAddressPool ' UtxoInternal k)
- externalPool :: !( SeqAddressPool ' UtxoExternal k)
- pendingChangeIxs :: !( PendingIxs ' AddressK )
- accountXPub :: k ' AccountK XPub
- policyXPub :: Maybe (k ' PolicyK XPub )
- rewardAccountKey :: k ' AddressK XPub
- derivationPrefix :: DerivationPrefix
- newtype DerivationPrefix = DerivationPrefix ( Index ' Hardened ' PurposeK , Index ' Hardened ' CoinTypeK , Index ' Hardened ' AccountK )
- purposeBIP44 :: Index ' Hardened ' PurposeK
- purposeCIP1852 :: Index ' Hardened ' PurposeK
- coinTypeAda :: Index ' Hardened ' CoinTypeK
- mkSeqStateFromRootXPrv :: forall n k. ( WalletKey k, SupportsDiscovery n k, (k == SharedKey ) ~ ' False ) => (k ' RootK XPrv , Passphrase "encryption") -> Index ' Hardened ' PurposeK -> AddressPoolGap -> SeqState n k
- mkSeqStateFromAccountXPub :: forall (n :: NetworkDiscriminant ) k. (SupportsDiscovery n k, (k == SharedKey ) ~ ' False ) => k ' AccountK XPub -> Maybe (k ' PolicyK XPub ) -> Index ' Hardened ' PurposeK -> AddressPoolGap -> SeqState n k
- discoverSeq :: forall n k m. ( PaymentAddress n k, Monad m) => ( Either Address RewardAccount -> m ChainEvents ) -> SeqState n k -> m ( ChainEvents , SeqState n k)
- discoverSeqWithRewards :: forall n k m. ( DelegationAddress n k, ToRewardAccount k, Monad m) => ( Either Address RewardAccount -> m ChainEvents ) -> SeqState n k -> m ( ChainEvents , SeqState n k)
-
newtype
SeqAnyState
(network ::
NetworkDiscriminant
) key (p ::
Nat
) =
SeqAnyState
{
- innerState :: SeqState network key
- mkSeqAnyState :: forall (p :: Nat ) n k. (SupportsDiscovery n k, WalletKey k, (k == SharedKey ) ~ ' False ) => (k ' RootK XPrv , Passphrase "encryption") -> Index ' Hardened ' PurposeK -> AddressPoolGap -> SeqAnyState n k p
Sequential Derivation
Address Pool Gap
data AddressPoolGap Source #
Maximum number of consecutive undiscovered addresses allowed
Instances
newtype MkAddressPoolGapError Source #
Possible errors when casting to an
AddressPoolGap
Instances
defaultAddressPoolGap :: AddressPoolGap Source #
A default
AddressPoolGap
, as suggested in BIP-0044
mkAddressPoolGap :: Integer -> Either MkAddressPoolGapError AddressPoolGap Source #
Smart constructor for
AddressPoolGap
mkUnboundedAddressPoolGap :: Word32 -> AddressPoolGap Source #
Constructor which allows by-passing the address pool gap boundary limitations. A practical use-case for this are sequential wallets for which we don't have access to the whole history which therefore require using arbitrary big gaps in order to discover addresses with indexes separated by possible huge gaps.
This defies a bit the purpose of this type though.
Address Pool
newtype SeqAddressPool (c :: Role ) (key :: Depth -> Type -> Type ) Source #
An address pool which keeps track of sequential addresses.
To create a new pool, see
newSeqAddressPool
.
Instances
getGap :: SeqAddressPool c k -> AddressPoolGap Source #
newSeqAddressPool :: forall (n :: NetworkDiscriminant ) c key. (SupportsDiscovery n key, Typeable c) => key ' AccountK XPub -> AddressPoolGap -> SeqAddressPool c key Source #
Create a new Address pool from a list of addresses. Note that, the list is expected to be ordered in sequence (first indexes, first in the list).
unsafePaymentKeyFingerprint :: forall k from. ( HasCallStack , MkKeyFingerprint k from) => from -> KeyFingerprint "payment" k Source #
State
data SeqState (n :: NetworkDiscriminant ) k Source #
A state to keep track of sequential addresses as described in BIP-44
Internally, the state keeps track of a few things for us and is it is
parameterized by a type
n
which captures a particular network discrimination.
This enables the state to be agnostic to the underlying address format.
SeqState | |
|
Instances
newtype DerivationPrefix Source #
Each
SeqState
is like a bucket of addresses associated with an
account
.
An
account
corresponds to a subset of an HD tree as defined in BIP-0039.
cardano-wallet implements two similar HD schemes on top of BIP-0039 that are:
- BIP-0044 (for so-called Icarus wallets)
- CIP-1815 (for so-called Shelley and Jormungandr wallets)
Both scheme works by considering 5 levels of derivation from an initial root
key (see also
Depth
from Cardano.Wallet.Primitive.AddressDerivation). A
SeqState keeps track of indexes from the two last levels of a derivation
branch. The
DerivationPrefix
defines the first three indexes chosen for
this particular
SeqState
.
DerivationPrefix ( Index ' Hardened ' PurposeK , Index ' Hardened ' CoinTypeK , Index ' Hardened ' AccountK ) |
Instances
purposeBIP44 :: Index ' Hardened ' PurposeK Source #
Purpose is a constant set to 44' (or 0x8000002C) following the original BIP-44 specification.
It indicates that the subtree of this node is used according to this specification.
Hardened derivation is used at this level.
purposeCIP1852 :: Index ' Hardened ' PurposeK Source #
Purpose is a constant set to 1852' (or 0x8000073c) following the BIP-44 extension for Cardano:
It indicates that the subtree of this node is used according to this specification.
Hardened derivation is used at this level.
coinTypeAda :: Index ' Hardened ' CoinTypeK Source #
One master node (seed) can be used for unlimited number of independent cryptocoins such as Bitcoin, Litecoin or Namecoin. However, sharing the same space for various cryptocoins has some disadvantages.
This level creates a separate subtree for every cryptocoin, avoiding reusing addresses across cryptocoins and improving privacy issues.
Coin type is a constant, set for each cryptocoin. For Cardano this constant is set to 1815' (or 0x80000717). 1815 is the birthyear of our beloved Ada Lovelace.
Hardened derivation is used at this level.
mkSeqStateFromRootXPrv :: forall n k. ( WalletKey k, SupportsDiscovery n k, (k == SharedKey ) ~ ' False ) => (k ' RootK XPrv , Passphrase "encryption") -> Index ' Hardened ' PurposeK -> AddressPoolGap -> SeqState n k Source #
Construct a Sequential state for a wallet from root private key and password.
mkSeqStateFromAccountXPub :: forall (n :: NetworkDiscriminant ) k. (SupportsDiscovery n k, (k == SharedKey ) ~ ' False ) => k ' AccountK XPub -> Maybe (k ' PolicyK XPub ) -> Index ' Hardened ' PurposeK -> AddressPoolGap -> SeqState n k Source #
Construct a Sequential state for a wallet from public account key.
discoverSeq :: forall n k m. ( PaymentAddress n k, Monad m) => ( Either Address RewardAccount -> m ChainEvents ) -> SeqState n k -> m ( ChainEvents , SeqState n k) Source #
Discover addresses and transactions using an
efficient query
addr -> m txs
.
Does
not
take
RewardAccount
into account.
discoverSeqWithRewards :: forall n k m. ( DelegationAddress n k, ToRewardAccount k, Monad m) => ( Either Address RewardAccount -> m ChainEvents ) -> SeqState n k -> m ( ChainEvents , SeqState n k) Source #
Discover addresses and transactions using an
efficient query
addr -> m txs
.
Does take
RewardAccount
into account.
Benchmarking
newtype SeqAnyState (network :: NetworkDiscriminant ) key (p :: Nat ) Source #
An "unsound" alternative that can be used for benchmarking and stress
testing. It re-uses the same underlying structure as the
SeqState
but
it discovers addresses based on an arbitrary ratio instead of respecting
BIP-44 discovery.
The proportion is stored as a type-level parameter so that we don't have to alter the database schema to store it. It simply exists and depends on the caller creating the wallet to define it.
SeqAnyState | |
|
Instances
mkSeqAnyState :: forall (p :: Nat ) n k. (SupportsDiscovery n k, WalletKey k, (k == SharedKey ) ~ ' False ) => (k ' RootK XPrv , Passphrase "encryption") -> Index ' Hardened ' PurposeK -> AddressPoolGap -> SeqAnyState n k p Source #
Initialize the HD random address discovery state from a root key and RNG seed.
The type parameter is expected to be a ratio of addresses we ought to simply recognize as ours. It is expressed in per-myriad, so "1" means 0.01%, "100" means 1% and 10000 means 100%.
Orphan instances
Buildable ScriptTemplate Source # | |
build :: ScriptTemplate -> Builder Source # |
|
Buildable ( ScriptTemplate , Maybe ScriptTemplate ) Source # | |
build :: ( ScriptTemplate , Maybe ScriptTemplate ) -> Builder Source # |
|
PersistPublicKey (key ' PolicyK ) => Buildable (key ' PolicyK XPub ) Source # | |
PersistPublicKey (key ' AccountK ) => Buildable (key ' AccountK XPub ) Source # | |