Skip to content
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-36? | Add support for Catalyst multi-delegation #200

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions CIP-0036/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
---
CIP: 36
Title: Catalyst/Voltaire Registration Transaction Metadata Format (Updated)
Authors: Sebastien Guillemot <sebastien@emurgo.io>, Rinor Hoxha <rinor.hoxha@iohk.io>, Mikhail Zabaluev <mikhail.zabaluev@iohk.io>, Giacomo Pasini <giacomo.pasini@iohk.io>, Kevin Hammond <kevin.hammond@iohk.io>
Comments-URI: https://forum.cardano.org/t/cip-catalyst-registration-metadata-format/44038
Status: Draft
Type: Standards
Created: 2021-12-06
License: CC-BY-4.0
---

## Abstract

Cardano uses a sidechain for its treasury system. One needs to "register" to participate on this sidechain by submitting a registration transaction on the mainnet chain. This CIP details the registration transaction format.
This is a revised version of the original CIP-15.

## Motivation

Cardano uses a sidechain for its treasury system ("Catalyst") and for other voting purposes. One of the desirable properties of this sidechain is that even if its safety is compromised, it doesn't cause loss of funds on the main Cardano chain. To achieve this, instead of using your wallet's recovery phrase on the sidechain, we need to use a brand new "voting key".

However, since 1 ADA = 1 vote, a user needs to associate their mainnet ADA to their new voting key. This can be achieved through a registration transaction.

In addition, to encourage participation by a broader range of ADA holders, it should be possible to delegate one's rights to vote to (possibly multiple) representatives and/or expert voters. Such delegations will still be able to receive Catalyst rewards.

We therefore need a registration transaction that serves three purposes:

1. Registers a "voting key" to be included in the sidechain and/or delegates to existing "voting key"s
2. Associates mainnet ADA to this voting key(s)
3. Declares an address to receive Catalyst rewards


Note: This schema does not attempt to differentiate delegations from direct registrations, as the two options have exactly the same format. It also does not distinguish between delegations that are made as "private" arrangements (proxy votes)
from those that are made by delegating to representatives who promote themselves publicly.
Distinguishing these possibilities is left to upper layers or future revisions of this standard, if required.
In this document, we will use the term 'delegations' to refer to all these possibilities.

## Specification

### Registration metadata format

A Catalyst registration transaction is a regular Cardano transaction with a specific transaction metadata associated with it.

Notably, there should be five entries inside the metadata map:
- A non-empty array of delegations, as described below;
- A stake address for the network that this transaction is submitted to (to point to the Ada that is being delegated);
- A Shelley address discriminated for the same network this transaction is submitted to to receive rewards.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be a shelley stake address. It can't be a regular address because of minutxo requirements.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that the challenges are not static -- they dynamically change every round. It means you can't "fire and forget" for a specific category and you'd have to explicitly re-delegate your vote every funding round. You could argue whether or not this is a desirable property or not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue it is a desirable property for now; later after DCF emerges and voting on parameters will be enabled we will have to revisit this CIP anyway; so IMO for now it fits the current crucial need to enable Project Catalyst to grow and get us where we need to be this year.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the voting purpose field allows different delegation assignments for specific reasons (and the CIP deliberately doesn't restrict what those reasons might be). So we simply need to define the mappings from voting purpose to challenges etc. and reflect that in the voting weights.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can explicitly make the rewards address a Shelley address. I think that was just carried over from CIP-15

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark, we are definitely looking ahead to non-Catalyst uses for this

- A nonce that identifies that most recent delegation
- A number that indicates the purpose of the vote
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's be more specific here, is the "number" a non-negative integer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the CDDL below, the purpose number is optional. Shouldn't it be mentioned here? Or some discussion of allowed/typical/default values of that?


### Delegation format

A delegation assigns (a portion of) the ADA controlled by one or more UTxOs on mainnet to the voting key in the sidechain as voting power. The UTxOs can be identified via the stake address at some designated point in time.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can only guess what at some designated point in time means here.


Each delegation therefore contains:
- a voting key: simply an ED25519 public key. This is the spending credential in the sidechain that will receive voting power from this delegation. For direct voting it's necessary to have the corresponding private key to cast votes in the sidechain. How this key is created is up to the wallet.
- the weight that is associated with this key: this is an unsigned integer (CBOR major type 0) that represents the relative weight of this delegation over the total weight of all delegations in the same registration transaction.
The weight may range from 0 to 2^32-1. Any greater value is capped to 2^32-1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should specify the maximum number of delegations per transaction. (I wouldn't go above 2^16-1.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no technical need to fix a maximum number of delegations - it will be restricted by the transaction size. The practical limit will be around 200-300


### Associating voting power with a voting key

This method has been used since Fund 2.
For future fund iterations, a new method making use of time-lock scripts may
be introduced as described [below][future-development].

Recall: Cardano uses the UTXO model so to completely associate a wallet's balance with a voting key (i.e. including enterprise addresses), we would need to associate every payment key to a voting key individually. Although there are attempts at this (see [CIP-0008]), the resulting data structure is a little excessive for on-chain metadata (which we want to keep small)

Given the above, we choose to only associate staking keys with voting keys. Since most Cardano wallets only use base addresses for Shelley wallet types, in most cases this should perfectly match the user's wallet.

The voting power that is associated with each delegated voting key is derived from the user's total voting power
as follows.

1. The total weight is calculated as a sum of all the weights;
2. The user's total voting power is calculated as a whole number of ADA (rounded down);
3. The voting power associated with each voting key in the delegation array is calculated as the weighted fraction of the
total voting power (rounded down);
4. Any remaining voting power is assigned to the last voting key in the delegation array.

This ensures that the voter's total voting power is never accidentally reduced through poor choices of weights,
and that all voting powers are exact ADA.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"voting powers are exact ADA" sounds sloppy

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll revise this. It came from the original CIP-15, I believe


### Example

Voting registration example:
```
61284: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

61284 should be explicitly mentioned before it is used in an example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CIP-0036/schema.cddl should also be referenced before the example.

// delegations - CBOR byte array
1: [("0xa6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663", 1), ("0x00588e8e1d18cba576a4d35758069fe94e53f638b6faf7c07b8abd2bc5c5cdee", 3)],
// stake_pub - CBOR byte array
Copy link
Contributor

@SebastienGllmt SebastienGllmt Mar 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason only allow public keys and not script hashes? Only supporting public keys would block multisigs from delegating their vote. It wouldn't add any complexity to the voting app because at the end of the day you're delegating to a (non-script) voting key

Probably the type should be
vkey | native_script since they both can be easily checked, but probably handling of Plutus multisig wallets is not doable in time for fund 9

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No particular reasons besides increased complexity on the backend to validate such scripts. Plutus for sure seems out of scope for now, but I'm worried even native scripts might be a bit of a stretch atm, considering required changes to the format as well.
Do we know how common / requested this feature is? We can add such functionality in the future if needed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zeegomo I think right now there's 100M+ locked in native script multisigs including ADA owned by the Milkomeda DAO

2: "0xad4b948699193634a39dd56f779a2951a24779ad52aa7916f6912b8ec4702cee",
// reward_address - CBOR byte array
3: "0x00588e8e1d18cba576a4d35758069fe94e53f638b6faf7c07b8abd2bc5c5cdee47b60edc7772855324c85033c638364214cbfc6627889f81c4",
// nonce
4: 5479467
// voting_purpose: 0 = Catalyst, 1 = Council Election
5: 0
}
```
The entries under keys 1, 2, 3, 4 and 5 represent the Catalyst delegation array,
the staking key on the Cardano network, the address to receive rewards,
a nonce, and a voting purpose, respectively. A registration with these metadata will be
considered valid if the following conditions hold:

- The nonce is an unsigned integer (of CBOR major type 0) that should be
monotonically rising across all transactions with the same staking key.
The advised way to construct a nonce is to use the current slot number.
This is a simple way to keep the nonce increasing without having to access
the previous transaction data.
- The reward address is a Shelley address discriminated for the same network
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned by @disassembler , it should be a stake address.

this transaction is submitted to.
- The delegation array is not empty
- The weights in the delegation array are not all zero


Delegation to the voting key `0xa6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663` will have relative weight 1 and delegation to the voting key `0x00588e8e1d18cba576a4d35758069fe94e53f638b6faf7c07b8abd2bc5c5cdee` relative weight 3 (for a total weight of 4).
Such a registration will assign 1/4 and 3/4 of the value in ADA to those keys respectively, with any remainder assigned to the second key.

To produce the signature field, the CBOR representation of a map containing
a single entry with key 61284 and the registration metadata map in the
format above is formed, designated here as `sign_data`.
This data is signed with the staking key as follows: first, the
blake2b-256 hash of `sign_data` is obtained. This hash is then signed
using the Ed25519 signature algorithm. The signature metadata entry is
added to the transaction under key 61285 as a CBOR map with a single entry
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"added to the transaction" is imprecise, we are still talking about constructing tx metadata, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, would "The signature metadata is added to the transaction metadata under key 61285" be better?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, definitely.

that consists of the integer key 1 and signature as obtained above as the byte array value.

Signature example:
```
61285: {
// signature - ED25119 signature CBOR byte array
1: "0x8b508822ac89bacb1f9c3a3ef0dc62fd72a0bd3849e2381b17272b68a8f52ea8240dcc855f2264db29a8512bfcd522ab69b982cb011e5f43d0154e72f505f007"
}
```

### Metadata schema

See the [schema file](./schema.cddl)

# Test vector

See [test vector file](./test-vector.md)

### Future development

[future-development]: #future-development

A future change of the Catalyst system may make use of a time-lock script to commit ADA on the mainnet for the duration of a voting period. The voter registration metadata in this method will not need an association
with the staking key. Therefore, the `staking_pub_key` map entry
and the `registration_signature` payload with key 61285 will no longer
be required.

## Changelog

Fund 3 added the `reward_address` inside the `key_registration` field.

Fund 4:
- added the `nonce` field to prevent replay attacks;
- changed the signature algorithm from one that signed `sign_data` directly
to signing the Blake2b hash of `sign_data` to accommodate memory-constrained hardware wallet devices.

It was planned that since Fund 4, `registration_signature` and the `staking_pub_key` entry inside the `key_registration` field will be deprecated.
This has been deferred to a future revision of the protocol.

Fund 8:
- renamed the `voting_key` field to `delegations` and add support for splitting voting power across multiple vote keys.
- added the `voting_purpose` field to limit the scope of the delegations.

## Copyright

This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode)

[CIP-0008]: https://github.com/cardano-foundation/CIPs/tree/master/CIP-0008
27 changes: 27 additions & 0 deletions CIP-0036/schema.cddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
registration_cbor = {
61284: key_registration,
61285: registration_signature
}

$voting_pub_key /= bytes .size 32
$staking_pub_key /= bytes .size 32
$ed25519_signature /= bytes .size 64
$reward_address /= bytes
$nonce /= uint
$proportion /= uint
$voting_purpose /= uint
legacy_key_registration = $voting_pub_key
delegation = ($voting_pub_key, $proportion)

key_registration = {
1 : [+delegation] / legacy_key_registration,
2 : $staking_pub_key,
3 : $reward_address,
4 : $nonce,
? 5 : $voting_purpose .default 0
}


registration_signature = {
1 : $ed25519_signature
}
112 changes: 112 additions & 0 deletions CIP-0036/test-vector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Test vector for CIP15

### Inputs

Payment **public** key hex
```
3273a5316e4de228863bd7cf8dac90d57149e1a595f3dd131073b84e35546676
```

Staking **private** key hex
```
f5beaeff7932a4164d270afde7716067582412e8977e67986cd9b456fc082e3a
```

Catalyst **private** key hex
```
4820f7ce221e177c8eae2b2ee5c1f1581a0d88ca5c14329d8f2389e77a465655c27662621bfb99cb9445bf8114cc2a630afd2dd53bc88c08c5f2aed8e9c7cb89
```

### Intermediate steps

Reward address generated from staking key
```
bech32
stake_test1uzhr5zn6akj2affzua8ylcm8t872spuf5cf6tzjrvnmwemcehgcjm

hex-encoded
e0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef
```

Data to sign (human readable format)

Legacy version (full delegation to one key only):
```javascript
'61284': {
'1': '0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0',
'2': '0x86870efc99c453a873a16492ce87738ec79a0ebd064379a62e2c9cf4e119219e',
'3': '0xe0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef',
'4': 1234,
'5': 0
},
```

New version:
```javascript
'61284': {
'1': [['0xa6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663', 1], ['0x00588e8e1d18cba576a4d35758069fe94e53f638b6faf7c07b8abd2bc5c5cdee', 3]],
'2': '0x86870efc99c453a873a16492ce87738ec79a0ebd064379a62e2c9cf4e119219e',
'3': '0xe0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef',
'4': 1234,
'5': 0
},
```


Metadata (CBOR encoding)

Legacy:
```
a119ef64a50158200036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a002582086870efc99c453a873a16492ce87738ec79a0ebd064379a62e2c9cf4e119219e03581de0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef041904d2
```

New:
```
a119ef64a50182825820a6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d16630182582000588e8e1d18cba576a4d35758069fe94e53f638b6faf7c07b8abd2bc5c5cdee0302582086870efc99c453a873a16492ce87738ec79a0ebd064379a62e2c9cf4e119219e03581de0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef041904d20500
```

Blake2b-256 hash of metadata

Legacy:
```
fbab7239fc029ab0ec2f315dba767a6730a60a53c384507bd50c10b7ce26b737
```

New:
```
5bc0681f173efd76e1989037a3694b8a7abea22053f5940cbb5cfcdf721007d7
```

### Output

Legacy:
```javascript
{
'61284': {
'1': '0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0',
'2': '0x1c5d88aa573da97e5a4667e0f7c4a9c6a3d848934c3b0a5b9296b401540f2aef',
'3': '0xe0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef',
'4': 1234,
'5': 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure one can call this "legacy" --- it does not comply with CIP-15 which does not contain key 5.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct, this (and the related occurrence above) should be changed

},
'61285': {
'1': '0x783da057e5dadb75c6d6f1ae121df29106a5c4ed8d7c87927c89b5743e05659e2740172aa6c838304c2627a84536844973b34611e374e70e9183b96c85169a04'
}
}
```

New:
```javascript
{
'61284': {
'1': [['0xa6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663', 1], ['0x00588e8e1d18cba576a4d35758069fe94e53f638b6faf7c07b8abd2bc5c5cdee', 3]],
'2': '0x1c5d88aa573da97e5a4667e0f7c4a9c6a3d848934c3b0a5b9296b401540f2aef',
'3': '0xe0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef',
'4': 1234,
'5': 0
},
'61285': {
'1': '0x3aaa2e6b43c0a96e880a7d70df84dffb2a1a17b19d7a99a6ed27b91d499b32027c43acfbf6dff097af7634b2ee38c8039af259b0b6a64316f02b4ffee28a0608'
}
}
```