Safe Haskell | None |
---|---|
Language | Haskell2010 |
Module for
DelegationState
.
Synopsis
-
data
DelegationState
k =
DelegationState
{
- rewardAccountKey :: k ' AccountK XPub
- state :: State
- initialDelegationState :: k ' AccountK XPub -> DelegationState k
- presentableKeys :: SoftDerivation k => DelegationState k -> [k ' AddressK XPub ]
- usableKeys :: SoftDerivation k => DelegationState k -> [k ' AddressK XPub ]
- activeKeys :: SoftDerivation k => DelegationState k -> [k ' AddressK XPub ]
- keyAtIx :: SoftDerivation k => DelegationState k -> Index ' Soft ' AddressK -> k ' AddressK XPub
- lastActiveIx :: DelegationState k -> Maybe ( Index ' Soft ' AddressK )
- data PointerUTxO = PointerUTxO { }
-
data
State
- = Zero
- | One
- | More !( Index ' Soft ' AddressK ) PointerUTxO ! Key0Status
-
data
Key0Status
- = ValidKey0
- | MissingKey0
- data Tx = Tx { }
- data Cert
- applyTx :: forall k. ( SoftDerivation k, ToRewardAccount k, MkKeyFingerprint k Address , MkKeyFingerprint k (k ' AddressK XPub )) => Tx -> Hash "Tx" -> DelegationState k -> DelegationState k
- setPortfolioOf :: ( SoftDerivation k, ToRewardAccount k) => DelegationState k -> Coin -> (k ' AddressK XPub -> Address ) -> ( RewardAccount -> Bool ) -> Int -> Maybe Tx
Creation
data DelegationState k Source #
Delegation state
Goals
- Allow a wallet to have an arbitrary number of stake keys
- Ensure those stake keys can be automatically discovered on-chain
- Ensure the wallet is always aware of all stake keys it registers, even in the case of concurrent user actions on multiple wallet instances, and old wallet software.
How
We track a consecutive range of keys that is extended with delegation of the
next unused key, and shrunk with key de-registration. We use a
PointerUTxO
to ensure that transactions changing the state can't be accepted to the
ledger in any other order than intended. We also need some special care
regarding stake key 0, which old wallet software could try to de-register.
Diagram
Diagram of states, where the list denotes active (registered and delegating) keys.
Here we assume the minUTxOValue is 1 ada.
Note that intermediate steps for the
PointerUTxO
should be skipped within a
transaction.
E.g. to transition from [] to [0,1,2] we should deposit 1 ada to key 3,
skipping key 2.
See the implementation of
setPortfolioOf
and
applyTx
for more details.
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌─────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ │ Pointer │ │ │ │ │ │──────────▶│ │ ──────deposit──────▶│ │ ─────────▶ │ │ ─────────▶ │ │ │ │ │ [0,1] │ │ [0,1,2] │ │ [] │ │ [0] │ │1 ada held by key 2 │ │ 1 ada held by key 3 │ │ │ │ │ │ │ │ │ │ │ │ │ Pointer │ │ │ │ │ │◀──────────│ │ ◀─────deposit ──────│ │◀────────── │ │◀────────── │ │ │ │ returned │ │ │ │ └────────────────────┘◀──┐ └────────────────────┘ └────────────────────▲ ▲─────────────────────▲ ▲ └───┐ │ ▲ └─┐ ┌┘ │ ▲ └─┐ ┌┘ Normal states └───┐ │ │ └─┐ ┌─┘ │ │ └─┐ ┌─┘ └───┐ │ │ └─┐ ┌─┘ │ │ └─┐ ┌─┘ ╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳└───┐╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳╳│╳╳╳╳╳╳╳│╳╳╳╳╳╳╳╳╳╳╳│ │╳╳╳╳╳╳╳╳╳╳╳│╳╳╳╳╳╳╳│╳╳╳╳╳╳▶ ├─┤ └───┐ │ │ ┌─┘ └─┐ │ │ ┌─┘ └─┐ States caused by └────┐Pointer ▼ │ ┌─┘ └─┐ ▼ │ ┌─┘ └─┐ old wallet └deposit ┌────────────────────┐─┘ └┬─────────────────────┐─┘ └─ de-registering returned─┐ │ │ │ │ stake-key 0 └────┐ │ │ ─────────▶ │ │ ─────────▶ of multi-stake └────┐ │ │ │ │ key wallet └──── │ [1] │ │ [1,2] │ │1 ada held by key 2 │ │ 1 ada held by key 3 │ │ │ │ │ │ │◀────────── │ │◀────────── │ │ │ │ │ │ │ │ └────────────────────┘ └─────────────────────┘
DelegationState | |
|
Instances
initialDelegationState :: k ' AccountK XPub -> DelegationState k Source #
Construct the initial delegation state.
Operations
presentableKeys :: SoftDerivation k => DelegationState k -> [k ' AddressK XPub ] Source #
All stake keys worth listing to the user.
May include: 1. Active stake keys 2. The next un-active key
NOTE: In theory we might want also present stake keys that are unexpectedly registered, as they could be de-registered to reclaim the deposit, but this should in-practice never happen.
If
sn
denotes the state with
n
registered and delegating keys:
>>> presentableKeys s0
[0]
>>> presentableKeys s1
[0, 1]
>>> presentableKeys s2
[0, 1, 2]
usableKeys :: SoftDerivation k => DelegationState k -> [k ' AddressK XPub ] Source #
activeKeys :: SoftDerivation k => DelegationState k -> [k ' AddressK XPub ] Source #
For testing. Returns all registered and delegating stake keys.
For Testing
keyAtIx :: SoftDerivation k => DelegationState k -> Index ' Soft ' AddressK -> k ' AddressK XPub Source #
lastActiveIx :: DelegationState k -> Maybe ( Index ' Soft ' AddressK ) Source #
data PointerUTxO Source #
Instances
The internal state, without the account key.
TODO: Perhaps we should model this as
S = S1 * S2, where S1 = Bool, S2 = ix * UTxOPointer
- having two
"concurrent" states tracking stake keys, where the first one is identical to
legacy single-stake key wallets.
Maybe that would help simplify
applyTx
and
setPortfolioOf
...
Zero |
No active stake keys. The initial state of a new wallet. |
One |
The first stake-key (index 0) is registered and either delegating or about to be delegating. |
More |
There is more than one active stake keys. Can only be reached using wallets with support for multiple stake keys. |
|
Instances
Eq State Source # | |
Show State Source # | |
Generic State Source # | |
NFData State Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State |
|
type Rep State Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State
type
Rep
State
=
D1
('
MetaData
"State" "Cardano.Wallet.Primitive.Delegation.State" "cardano-wallet-core-2022.7.1-AGKhlyz9liLKN3QqZD1gj" '
False
) (
C1
('
MetaCons
"Zero" '
PrefixI
'
False
) (
U1
::
Type
->
Type
)
:+:
(
C1
('
MetaCons
"One" '
PrefixI
'
False
) (
U1
::
Type
->
Type
)
:+:
C1
('
MetaCons
"More" '
PrefixI
'
False
) (
S1
('
MetaSel
('
Nothing
::
Maybe
Symbol
) '
NoSourceUnpackedness
'
SourceStrict
'
DecidedStrict
) (
Rec0
(
Index
'
Soft
'
AddressK
))
:*:
(
S1
('
MetaSel
('
Nothing
::
Maybe
Symbol
) '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
PointerUTxO
)
:*:
S1
('
MetaSel
('
Nothing
::
Maybe
Symbol
) '
NoSourceUnpackedness
'
SourceStrict
'
DecidedStrict
) (
Rec0
Key0Status
)))))
|
data Key0Status Source #
Is key 0 still registered? For compatibility with single-stake-key wallets, we need to track this.
>>>
activeKeys (More (toEnum 3) p ValidKey0)
[0, 1, 2]
>>>
activeKeys (More (toEnum 3) p MissingKey0)
[1, 2]
(pseudocode; requires a bit more boilerplate to compile)
See the implementation of
applyTx
for how it is used.
Instances
Eq Key0Status Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State (==) :: Key0Status -> Key0Status -> Bool Source # (/=) :: Key0Status -> Key0Status -> Bool Source # |
|
Show Key0Status Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State |
|
Generic Key0Status Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State from :: Key0Status -> Rep Key0Status x Source # to :: Rep Key0Status x -> Key0Status Source # |
|
NFData Key0Status Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State rnf :: Key0Status -> () Source # |
|
type Rep Key0Status Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State
type
Rep
Key0Status
=
D1
('
MetaData
"Key0Status" "Cardano.Wallet.Primitive.Delegation.State" "cardano-wallet-core-2022.7.1-AGKhlyz9liLKN3QqZD1gj" '
False
) (
C1
('
MetaCons
"ValidKey0" '
PrefixI
'
False
) (
U1
::
Type
->
Type
)
:+:
C1
('
MetaCons
"MissingKey0" '
PrefixI
'
False
) (
U1
::
Type
->
Type
))
|
Chain following model
A transaction type specific to
DelegationState
.
Intended to be converted both from and to a more real transaction type.
When constructing a real transaction from
Tx
, these
outputs
should appear before other outputs. In the theoretical event that there's
also a user-specified output with the same payment key as the pointer output,
applyTx
will track the first one as the new pointer.
Instances
Eq Tx Source # | |
Show Tx Source # | |
Generic Tx Source # | |
Semigroup Tx Source # | |
type Rep Tx Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State
type
Rep
Tx
=
D1
('
MetaData
"Tx" "Cardano.Wallet.Primitive.Delegation.State" "cardano-wallet-core-2022.7.1-AGKhlyz9liLKN3QqZD1gj" '
False
) (
C1
('
MetaCons
"Tx" '
PrefixI
'
True
) (
S1
('
MetaSel
('
Just
"certs") '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
[
Cert
])
:*:
(
S1
('
MetaSel
('
Just
"inputs") '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
[(
TxIn
,
Coin
)])
:*:
S1
('
MetaSel
('
Just
"outputs") '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
[
TxOut
]))))
|
RegisterKey RewardAccount | |
Delegate RewardAccount |
Which pool we're delegating to is here (and for now) irrelevant. The main thing is that there exists a witness on-chain for this stake key (registration certs don't require witnesses) TODO: We may also want to add the PoolId here. |
DeRegisterKey RewardAccount |
Instances
Eq Cert Source # | |
Show Cert Source # | |
Generic Cert Source # | |
type Rep Cert Source # | |
Defined in Cardano.Wallet.Primitive.Delegation.State
type
Rep
Cert
=
D1
('
MetaData
"Cert" "Cardano.Wallet.Primitive.Delegation.State" "cardano-wallet-core-2022.7.1-AGKhlyz9liLKN3QqZD1gj" '
False
) (
C1
('
MetaCons
"RegisterKey" '
PrefixI
'
False
) (
S1
('
MetaSel
('
Nothing
::
Maybe
Symbol
) '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
RewardAccount
))
:+:
(
C1
('
MetaCons
"Delegate" '
PrefixI
'
False
) (
S1
('
MetaSel
('
Nothing
::
Maybe
Symbol
) '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
RewardAccount
))
:+:
C1
('
MetaCons
"DeRegisterKey" '
PrefixI
'
False
) (
S1
('
MetaSel
('
Nothing
::
Maybe
Symbol
) '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
RewardAccount
))))
|
applyTx :: forall k. ( SoftDerivation k, ToRewardAccount k, MkKeyFingerprint k Address , MkKeyFingerprint k (k ' AddressK XPub )) => Tx -> Hash "Tx" -> DelegationState k -> DelegationState k Source #
Apply a
Tx
to a
DelegationState
.
Expects the
PointerUTxO
to be correctly managed, and will panic otherwise.
:: ( SoftDerivation k, ToRewardAccount k) | |
=> DelegationState k | |
-> Coin |
minUTxOVal |
-> (k ' AddressK XPub -> Address ) |
A way to construct an Address |
-> ( RewardAccount -> Bool ) |
Whether or not the key is registered. TODO: Need a Set or Map for the real implementation with LSQ. |
-> Int |
Target number of stake keys. |
-> Maybe Tx |
Given a
DelegationState
, produce a
Tx
registering or de-registering
stake-keys, in order to have
n
stake-keys.
E.g.
setPortfolioOf s0 _ _ 2
creates a tx which after application causes
the state to have
activeKeys == [0,1]
Returns
Nothing
if the target
n
is already reached.