-
Notifications
You must be signed in to change notification settings - Fork 334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CIP-0018: Multi Stake Keys Wallets #83
Conversation
I'd suggest a more neutral phrasing such as: Delegating to more pools can reduce the impact of pool failure (for one or more epochs) or unattended changes in pool fees. It may as well be a matter of choice if users do want to delegate to several independent entities for various other reasons. |
CIP-0018/CIP-0018.md
Outdated
- **2.A)** It must exist an active<sup><a href="#1-active-stake-key">1</a></sup> stake key registration certificate on chain of the immediately previous stake key, located in the stable area<sup><a href="#2-stable-area">2</a></sup> of the chain. | ||
- **2.B)** It must exist another stake key registration certificate of the immediately previous stake key in the same transaction which satisfies 2.A or 2.B. | ||
|
||
Said differently, one can only register a new stake key if previous keys have already been registered and are immutable. We also allow registering keys in batch to alleviate the user experience for users wanting to register many stake keys. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it mean one will be able to make multi-delegation only at least every 36h?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes and no. It means that you'll be to register new stake keys after at least 36h from the last registration. Yet, you can register many keys at once. So, if you have a portfolio of let's say 10 pools, you can multi-delegate in one go. But then, once done if you want to add a 11th pool, you'll have to wait 36h. However, you can change the delegation settings of any of these pools anytime you want. What's really constrained is the registration (and conversely, de-registration) of stake keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, thanks. Good, that's how I understood it.
CIP-0018/CIP-0018.md
Outdated
|
||
Similarly, keys can only be de-registered in sequence, from the latest and downwards. Transaction de-registering stake keys must satisfy one of the following conditions to be valid: | ||
|
||
- **3.A)** The index of the de-registered key must be equal to the index of the last active<sup><a href="#1-active-stake-key">1</a></sup> stake key on chain. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should also note this can cause backwards compatibility issues since Yoroi supports de-registering your stake key (so if it doesn't support this spec, it will de-register only the 0-index key, leaving the other active keys untouched breaking this rule)
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aa987ef
to
44da520
Compare
@SebastienGllmt we've made quite a large iteration on this design after running into various implementation and conceptual challenges, I've updated the proposal to the latest version which deviates quite a lot from the original idea. If you want to have look 👍 |
|
||
1. Stake keys must be derived sequentially, from 0 and onwards. | ||
1. Every stake key registration must be accompanied by a matching delegation certificate. | ||
1. Every registration transaction must create a special output of exactly `minUTxOValue`<a href="#glossary"><sup>[1]</sup></a> Ada such that its address is an enterprise address with a single **payment part** using the stake key hash of the next available stake key of the wallet to be registered after processing the registration transaction. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is an enterprise address
There should be no reason for requiring the pointer address to be an enterprise one, so it would be simpler just not to mention it? Arguably, one might as well have a stake key on the pointer utxo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. This is needlessly restrictive 🤔
Since the pointer would be a misused UTxO, would't any wallet not implementing this CIP be consuming that UTxO at some point? |
If a stake address was part of a base address that received funds (registered or not) wallets have to sync this stake key anyway (check regs/deregs/delegation/rewards/withdrawals). So why bother with implementing a pointer for registrations? Filling gaps makes sense, sure. But a wallet knows about the status of a stake key index and thus can re-register a stake key, if it previously was registered and had since been deregistered. I try to understand what's the motivation from a wallet standpoint as I want to start implementing multi delegation in our wallet. Portfolios: If a portfolio changes and eg. removes a pool that was delegated to using let's say stake key index 3 of 5, with this CIP index 5 would need to be deregistered, index 3 re-delegated. But wallets need to sync that stake key index anyway, a wallet knows the status of that index 3 as deregistered and that index can be reused (re-registering + delegating) if need be. |
There's actually little risk (unless the wallet it doing something abnormal, or not following CIP-1852) because the UTxO lives on a completely different derivation chain than others. The pointer UTxO is specifically chosen at a path that does not conflict with existing derivation paths.
Actually, no. The wallet does not know the status of registrations. Or more exactly, it only knows it after a certain time (36h on mainnet and testnet). And this is because of two reasons:
Thus, you can't really expect that you'll be able to recover the state of your wallet from the chain unless you construct it in such a way that makes it possible. Let's say that you do not use a pointer like in this proposal but simply rely on observing the next certificate on chain. Then comes Alice, who first registers a key K1. A bit later, she registers K2, but out of luck, the transaction regarding K1 is rolled back and never ends up on chain. Now if she tries restoring her wallet on another machine, she may be surprised when her wallet fails to discover K2 because the wallet is only watching the chain for K1. Like for sequential wallets, you could use a gap and not be too short sighted, but it only moves the problem by some offset. We've got some users who wants to register hundreds of stake keys, and while having a gap of 100 is possible, it would impact performances quite a bit and, will only be okay until someone comes with 200 keys to register. Our first proposal to this was to simply forbid the creation of new stake keys before the immutability of the previous ones, which was unsatisfactory as it makes the UX worse.. This, another solution (this proposal) leverages the UTxO mechanism by artificially chaining all registrations and deregistrations together. By forcing a specific UTxO to be spent for every (de) registration, we avoid any concurrency issue regarding rollback or multi wallets. If a transaction is invalidated, then, any transaction coming after is also invalidated (since they depend on UTxOs which are only created by previous transactions!). In brief, the pointer ain't much about tracking the state of the wallet, as you said, this can be figured out easily from certificates on chain. Rather, the pointer is a protection to ensure the wallet can not end up in a state where it is not fully recoverable from the chain. And it does so without limitations of numbers of keys or, time delays. |
Thank you for the explaination. What derivation path is planned for this proposal? |
It is said in the proposal, I reckon I could make that clearer then. We use the same path as the next stake key to be registered, but, use it to construct a payment address (so it's a bit like associating a UTxO to the reward account corresponding to the key). |
Ok, got it (I think). Discover UTxOs on enterprise addr created by deriving m/1852'/1815'/x'/2/1 to n. If a UTxO is present at m/1852'/1815'/x'/2/y, thus pointer available:
If no UTxO was discovered:
Questions: Single stake key delegation: Do not create a pointer UTxO on /1, if the account did not perform multi-delegation before? Remove pointer UTxO only if also /0 was deregistered? |
The following diagram might be helpful, and maybe we should add something like it to the proposal: https://github.com/input-output-hk/cardano-wallet/blob/690e5a2bee1bd4cfbd760c65e8a7f20b71cbfad0/lib/core/src/Cardano/Wallet/Primitive/Delegation/State.hs#L109-L136
No, for consistency with existing single-delegation the pointer is never created for /1 when delegating with key /0.
It ends up being only when /1 is deregisteried (see diagram). |
6/29 Editors meeting (25) discussed this PR - see notes. (conversation might be ahead of meeting notes at this point, this is a reference) => PR is now in 'Last Check': it will get another look at next week's public meeting (26) and should be merged in after that - consider attending the meeting if relevant to you. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, for draft CIP status.
|
||
1. Stake keys must be derived sequentially, from 0 and onwards. | ||
1. Every stake key registration must be accompanied by a matching delegation certificate. | ||
1. Every registration transaction must create a special output of exactly `minUTxOValue`<a href="#glossary"><sup>[1]</sup></a> Ada such that its address is an enterprise address with a single **payment part** using the stake key hash of the next available stake key of the wallet to be registered after processing the registration transaction. |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Multi-Stake-Keys Wallets
Abstract
This document describes how to evolve sequential wallets from Cardano to support multiple stake keys. This proposal is an extension of CIP-1852 and CIP-0011.
Motivation / Use-cases
Cardano wallets originally approached stake delegation by considering a single stake key per wallet. While this was beneficial in terms of ease of implementation and simplicity of reasoning, this is unsuitable for many users with large stakes. Indeed, the inability to split out the stake into multiple pools often leads to over-saturation of existing pools in case of delegation. The only workaround so far requires users to split their funds into multiple accounts and manage them independently. This can be quite cumbersome for a sufficiently large number of accounts.
Even for smaller actors, it can be interesting to delegate to multiple pools to limit risks. Pools may underperform or simply change their parameters from a day to another (for which wallets still do not warn users about). Delegating to more pools can reduce the impact of pool failure (for one or more epochs) or unattended changes in pool fees. It may as well be a matter of choice if users do want to delegate to several independent entities for various other reasons.
Another concern regards privacy leaks coming with the existing wallet scheme. Since the same stake key is associated with every single address of the wallet, it creates a kind of watermark that allows for tracing all funds belonging to the same wallet very easily (it suffices to look at the stake part of addresses). By allowing the wallet to hold multiple stake keys, rotating through them when creating changes does make the traceability a bit harder. One could imagine using a hundred stake keys delegated to the same pool.
Specification
Overview
The restriction from CIP-0011 regarding the derivation index reserved for stake key is rendered obsolete by this specification. That is, one is allowed to derive indexes beyond the first one (index = 0) to effectively administrate multi-stake keys accounts. The creation of new stake keys is however tightly coupled to the registration of associated stake keys to allow wallet software to automatically discover stake keys on-chain. In this design, stake key indexes form at all time a contiguous sequence with no gap.
Key registration
We introduce the concept of UTxO stake key pointer to reliably keep track of stake keys on the blockchain. The gist is to require that every key registration and/or deregistration consume and create a special UTxO which in itself is pointing to the next available stake key of the wallet. Such pointer allows piggybacking on the existing UTxO structure to cope with concurrency issues and rollbacks that are inherent to a distributed system such as Cardano. Plus, this mechanism only demands a low overhead for wallet software and may be recognized as a special spending pattern by hardware devices.
In more details, we require that beyond the first stake key (index = 0), all registrations must satisfy the following rules:
minUTxOValue
[1] Ada such that its address is an enterprise address with a single payment part using the stake key hash of the next available stake key of the wallet to be registered after processing the registration transaction.Example
For example, a wallet that has already registered stake keys 0, 1 and 2 have a UTxO for which the payment part is a hash of the stake key at index=3. If the wallet wants to register two new stake keys at index 3 and 4, it'll do so in a single transaction, by consuming the pointer UTxO and by creating a new one for which the payment part would be a hash of the stake key at index=5.
Note that this only requires two signatures from stake keys at indexes 3 and 4.
Key de-registration
Key de-registrations work symmetrically and require that:
minUtxOValue
Ada such that its address is an enterprise address with a single payment part using the stake key hash of the next stake key of the wallet after processing the de-registration transaction.Rationale
Carrying an extra UTxO pointer makes it possible to not worry (too much) about concurrency issues and problems coming with either, multiple instances of the wallet (like many users do between a mobile and desktop wallet) or the usual rollbacks which may otherwise create gaps in the indexes. By forcing all registration (resp. deregistration) transactions to be chained together, we also enforce that any rollbacks do maintain consistency of the index state: if any intermediate transaction is rolled back, then transactions they depend on are also rolled back.
The first registration induces an extra cost for the end-user for the wallet needs to create a new UTxO with a minimum value. That UTxO is however passed from registration to registration afterwards without any extra cost. It can also be fully refunded upon de-registering the last stake key. So in practice, it works very much like a key deposit.
We do not allow mixing up key registration and key deregistration as part of the same transaction for it makes the calculation of the pointer trickier for wallet processing transactions. A single transaction either move the pointer up or down.
There's in principle nothing preventing someone from sending money to the special key-registration tracking address. Wallets should however only keep track of UTxOs created as part of transactions that register stake keys (and have therefore been authorized by the wallet itself). Applications are however encouraged to collect any funds sent to them in an ad-hoc manner on such keys.
Backwards Compatibility
As stated in the introduction, this proposal is built on top of CIP-0011 such that backward compatibility is preserved when a single key is used. In fact, The management of the first stake key at index 0 remains unchanged and does not require any pointer. This preserves backward compatibility with the existing design for a single stake key wallet and offers a design that can be implemented on top, retro-actively.
Nevertheless, we do assume that existing wallets following CIP-0011 are already fully capable of discovering addresses using stake keys not belonging to the wallet. Some may even report them as mangled[2]. As a result, this extension would not incapacitate existing wallets since the payment ownership is left untouched. However, wallets not supporting the extension may display addresses delegated to keys beyond the first one as mangled and may also fail to report rewards correctly across multiple keys.
We deem this to be an acceptable and fairly minor consequence but encourage existing software to raise awareness about this behaviour.
Reference Implementation
Coming soon.
Glossary
[1] Minimum Utxo Value
The
minUTxOValue
is fixed by the protocol. It is defined as part of the Shelley genesis and can be updated via on-chain protocol updates. At the moment, this equals 1 Ada on the mainnet.[2] Mangled Addresses
An address is said mangled when it has a stake part, and the stake part isn't recognized as belonging to its associated wallet. That is, the payment part and the stake part appear to come from two different sources. This could be the case if the address has been purposely constructed in such a way (because the stake rights and funds are managed by separate entities), or because the stake part refers to a key hash which is no longer known of the wallet (because the associated key registration was rolled back).
Copyright
CC-BY-4.0