From 81c7596ba59c68e35d13856e7384ab330f175e46 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Thu, 14 Jul 2022 09:43:02 +0100 Subject: [PATCH 01/30] Jurmungandr api submitVote, connect to Node --- CIP-0062/README.md | 229 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 CIP-0062/README.md diff --git a/CIP-0062/README.md b/CIP-0062/README.md new file mode 100644 index 0000000000..352fae4007 --- /dev/null +++ b/CIP-0062/README.md @@ -0,0 +1,229 @@ +--- +CIP: 62 +Title: Cardano dApp-Connector Governance extension +Authors: Bruno Martins +Status: Draft +Type: Standards +Created: 2021-06-11 +License: CC-BY-4.0 +--- + +# **Abstract** + +This document describe the interface between webpage / web-based stack and cardano wallets. This specificies that API of the javascript object that need to be injected into the web applications in order to support all the Governance features. + +These definitions extend [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/) to provide specific support for vote delegation. + +# **Motivation** +The goal for this CIP is to extend the dApp-Wallet web bridge to enable the construction of transactions containing metadata that conforms to +[CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://cips.cardano.org/cips/cip36/), +enabling new functionality including vote delegation to either private or public representatives (dReps), +splitting or combining of private votes, +the use of different voting keys or delegations +for different purposes (Catalyst etc). + +# **Specification** + +## `Types` + +### **GovernanceKey** + +``` +type GovernanceKey = { + votingKey: string, + weight: number +} + +``` + +`votingKey`: Ed25519 pubkey 32 bytes HEX string + +`weight`: Used to calculate the actual voting power using the rules described +in +[CIP-36](https://cips.cardano.org/cips/cip36/). + + +### **Purpose** + +``` +type enum Purpose = { + CATALYST = 0, + OTHER = 1 +} + +``` + +`Purpose`: Defines the purpose of the delegations. This is used to limit the scope of the delegations. For example, a purpose might be a subset of Catalyst proposals, a council election, or even some private purpose (agreed by convention). + +### **KeyPath** +``` +interface KeyPath = { + address_index: number + account: number + role: number +} +``` + + + +## **Namespace** + +### **cardano.{walletName}.governance.enable(): Promise\** +The `cardano.{walletName}.governance.enable()` method is used to enable the governance API. It should request permission from the wallet to enable the API. If permission is granted, the rest of the API will be available. The walelt may choose to maintain a whitelist of allowed clients to avoid asking for permission every time. + +This api being an extension of [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/), expects that `cardano.{walletName}.enable()` to be enabled implicitly. + +# **`Jormungandr API`** + +## **api.connectToNode**(url: string): Promise\ + +The `api.connectToNode` method is used to connect to a Jormungandr node. + +## **api.submitVote**(keyPath: KeyPath, proposal: Proposal, choice: Choice, validUntil: BlockDate, spendingCounter: number): Promise\ + +`keyPath`: The derivation path values to the voting key for which transaction should be signed with. The derivation path should follow the already establish in [CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://cips.cardano.org/cips/cip36/). +_`m / 1694' / 1815' / account' / role' / address_index'`_ + + +`proposal` : proposal information. Include the range of options we can use to vote. This defines the allowed values in `choice`. + +``` +interface Proposal { + votePlanId: number + index: number + voteOptions: number[] +} +``` + +`choice`: The choice we want to vote for. An `UnkownChoiceError` should be thrown is the value is not within the `proposal` option set. + +`validUntil`: chain epoch \& slot for when the vote will expire. + +``` +interface BlockDate { + epoch: number + slot: number +} +``` + +### Returns + +`hash32` - This is the hash of the transaction that will be submitted to the node. + +#### Errors +`InvalidArgumentError` - Generic error for errors in the formatting of the arguments. + +`UnknownChoiceError` - If the `choice` is not within the `proposal` option set. + +`InvalidBlockDateError` - If the `validUntil` is not a valid block date. + +`InvalidVotingKeyError` - If the `keyPath` is not a valid voting key. + +`InvalidVotePlanError` - If the `votePlanId` is not a valid vote plan. + +`InvalidVoteOptionError` - If the `index` is not a valid vote option. + +# **`Delegation API`** + +## **api.getVotingKey**(path: KeyPath): Promise\ + +Should derive and return the wallets voting public key + +### **Returns** +`cbor\` - cbor serialized 64 bytes (x, y) Ed25519 public key + +There should be only a single single voting key per wallet / mnemonic. + +The **`votingKey`** should be derived from the following path. + +``` +m / 1694' / 1815' / account' / role' / address_index' +``` + +`1694` (year Voltaire was born) Sets a dedicated `purpose` in the derivation path for the voting profile. + +`address_index` - index of the key to use. + + +## **api.buildDelegation**(keys: GovernanceKey[], purpose: Purpose, networkId: number, stakeAccountPath: number = 0, stakeRolePath: number = 0, stakeIndex: number = 0): Promise\<**`Delegation`**> + +Should create the metadata object to be submitted by a metadata transaction to register the delegations on-chain. + +### **Params** + +`account`: In case the wallet supports multiple accounts. defaults to 0 + +`chain`: Part of the derivation path. defaults to 0 + +`role`: + +### **Returns** + +#### **`Delegation`** + +``` +export interface Delegation { + voting_delegation: GovernanceKey[], + staking_key: string, + reward_address: string, + nonce: number, + purpose: Purpose +} +``` + +Defines the structure to be crafted and signed for delegation of voting & their respectively voting power. Embeds the stake key and reward address from the wallet, and constructs a suitable nonce. + +***`voting_delegation`***: List of keys and their voting weight to delegate voting power to. + +The ***`staking_key`*** is Ed25519 public key 32bytes (x only) associated with the stake address. Defined in [CIP-11]((https://cips.cardano.org/cips/cip11), which specifies the derivation path for the staking key: + +``` +m / 1852' / 1815' / account' / chain / 0 +``` + +The ***`reward_address`*** as specified in [CIP-8](https://cips.cardano.org/cips/cip8/#addressformats) + + +The ***`nonce`*** is an unsigned integer (of CBOR major type 0) that should be monotonically increasing across all transactions with the same staking key. The wallet manages this and guarantees that nonces are always unique and greater than the previous ones. A suitable nonce value is the `linux epoch timestamp`. + + +## **api.signDelegation**(delegation: DelegationMetadata, account: number = 0, role: number = 0, index: number = 0): Promise\<**`SignedDelegationMetadata`**> + +Since [CIP-18](https://cips.cardano.org/cips/cip18), multi-staking keys should be considered. However, a single voting profile should exist per wallet. A single staking key should be used to perform EDDSA over the voting profile blake2b-256 hash. The staking key used should still be the one defined in [CIP-11]((https://cips.cardano.org/cips/cip11). + +### **Returns** + +#### **`SignedDelegationMetadata`** + +``` +export interface SignedDelegationMetadata { + '61284': DelegationMetadata, + '61285': string +} +``` + +Defines the result of signing the DelegationMetadata. + +- `61284`: Key that defines the registration metadata map + +- `61285`: Signature of the blake2b hash of the `DelegationMetadata` + +## **api.submitDelegation(delegation: SignedDelegationMetadataw): Promise\** + +This should be a call that implicitly cbor encodes the `delegation` object and uses the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.submitTx` to submit the transaction. The resulting transaction hash should be returned. + +This should be trigger a request to the wallet to approve the transaction. + +Errors: `APIError`, `TxSendError` + +### Delegation Cert process + +1. **`Get Voting Key`** - use the method **api.getVotingKey** to return a ed25519 32 bytes public key (x value of the point on the curve). + +2. **`Collect Voting Keys`** - Collect the keys to delegate voting power to. + +3. **`Craft delegation cert`** - Use **api.buildDelegation** to construct the object containing the key array set to delegate voting power to. Each value will express the `weight` of the voting powers given. + +4. **`Sign the delegation cert`** - Use **api.signDelegation** to sign the blake2b hash of the delegation cert and append it to the cert + +5. **`Submit delegation`** - Submit the metadata transaction to the chain using **api.submitDelegation** which implicitly can use the already existing **api.submitTx**, available from [CIP-30](https://cips.cardano.org/cips/cip30/) From e360eb5a67c2ee2ca51c638d3a2633aa35b9548b Mon Sep 17 00:00:00 2001 From: ehanoc Date: Thu, 14 Jul 2022 11:33:30 +0100 Subject: [PATCH 02/30] Jurmungandr unnecessary connectToNode --- CIP-0062/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 352fae4007..aae354f326 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -75,10 +75,6 @@ This api being an extension of [CIP-30 (Cardano dApp-Wallet Web Bridge)](https:/ # **`Jormungandr API`** -## **api.connectToNode**(url: string): Promise\ - -The `api.connectToNode` method is used to connect to a Jormungandr node. - ## **api.submitVote**(keyPath: KeyPath, proposal: Proposal, choice: Choice, validUntil: BlockDate, spendingCounter: number): Promise\ `keyPath`: The derivation path values to the voting key for which transaction should be signed with. The derivation path should follow the already establish in [CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://cips.cardano.org/cips/cip36/). From ad82668aa2031432b2f0e7909cccfc852bffabc3 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Thu, 14 Jul 2022 11:52:33 +0100 Subject: [PATCH 03/30] Removing requirement for single voting key for mnemonic. Rewording description enable() --- CIP-0062/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index aae354f326..56f268786f 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -69,9 +69,11 @@ interface KeyPath = { ## **Namespace** ### **cardano.{walletName}.governance.enable(): Promise\** -The `cardano.{walletName}.governance.enable()` method is used to enable the governance API. It should request permission from the wallet to enable the API. If permission is granted, the rest of the API will be available. The walelt may choose to maintain a whitelist of allowed clients to avoid asking for permission every time. +The `cardano.{walletName}.governance.enable()` method is used to enable the governance API. It should request permission from the wallet to enable the API. If permission is granted, the rest of the API will be available. The wallet should maintain a specific whitelist of allowed clients for this API. This whitelist can be used to avoid asking for permission every time. -This api being an extension of [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/), expects that `cardano.{walletName}.enable()` to be enabled implicitly. +This api being an extension of [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/), expects that `cardano.{walletName}.enable()` to be enabled and added to CIP-30 whitelist implicitly. + +When both this API and **CIP-30** is being enabled, is up to the wallet to decide the number of prompts requesting permissions to be displayed to the user. # **`Jormungandr API`** @@ -128,8 +130,6 @@ Should derive and return the wallets voting public key ### **Returns** `cbor\` - cbor serialized 64 bytes (x, y) Ed25519 public key -There should be only a single single voting key per wallet / mnemonic. - The **`votingKey`** should be derived from the following path. ``` From 5cfa05182f2940e06e8eda491b4c52155ff31bf9 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Mon, 25 Jul 2022 14:03:42 +0100 Subject: [PATCH 04/30] Support batching of votes in api.submitVotes. Refactor multiple steps to sign and submit delegation cert into one step api.submitDelegation --- CIP-0062/README.md | 87 +++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 56f268786f..565215ad3f 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -77,25 +77,25 @@ When both this API and **CIP-30** is being enabled, is up to the wallet to decid # **`Jormungandr API`** -## **api.submitVote**(keyPath: KeyPath, proposal: Proposal, choice: Choice, validUntil: BlockDate, spendingCounter: number): Promise\ +## **api.submitVotes**(keyPath: KeyPath, votes: Vote[], spendingCounter: number): Promise\ `keyPath`: The derivation path values to the voting key for which transaction should be signed with. The derivation path should follow the already establish in [CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://cips.cardano.org/cips/cip36/). _`m / 1694' / 1815' / account' / role' / address_index'`_ +### `spendingCounter`: +The spending counter is used to prevent double voting. The current spending counter for the account should be provided and the implementation should increment it for each vote before submission and attach it to the vote according to [Jormungandr Voting] (https://input-output-hk.github.io/jormungandr/jcli/vote.html#voting). This needs to be in sequential order. -`proposal` : proposal information. Include the range of options we can use to vote. This defines the allowed values in `choice`. +### **`votes`**: ``` -interface Proposal { - votePlanId: number - index: number - voteOptions: number[] +interface Vote { + proposal: Proposal, + choice: number, + expiration: BlockDate } ``` - -`choice`: The choice we want to vote for. An `UnkownChoiceError` should be thrown is the value is not within the `proposal` option set. - -`validUntil`: chain epoch \& slot for when the vote will expire. +#### `expiration`: +chain epoch \& slot for when the vote will expire. The type used is: ``` interface BlockDate { @@ -104,11 +104,30 @@ interface BlockDate { } ``` -### Returns +#### `choice`: +The choice **index** we want to vote for. An `UnkownChoiceError` should be thrown is the value is not within the `proposal` option set. + +#### **`proposal`** : +proposal information. Include the range of options we can use to vote. This defines the allowed values in `choice`. + +``` +interface Proposal { + votePlanId: number + voteOptions: number[] +} +``` + +##### `votePlanId`: +the vote plan id. This is used to identify the vote plan. This should be the same as anchored on chain. + +##### `voteOptions`: +The vote options. This is the set of options we can vote for. + +### **Returns** `hash32` - This is the hash of the transaction that will be submitted to the node. -#### Errors +#### **Errors** `InvalidArgumentError` - Generic error for errors in the formatting of the arguments. `UnknownChoiceError` - If the `choice` is not within the `proposal` option set. @@ -140,22 +159,17 @@ m / 1694' / 1815' / account' / role' / address_index' `address_index` - index of the key to use. +## **api.submitDelegation(delegation: Delegation): Promise\** -## **api.buildDelegation**(keys: GovernanceKey[], purpose: Purpose, networkId: number, stakeAccountPath: number = 0, stakeRolePath: number = 0, stakeIndex: number = 0): Promise\<**`Delegation`**> - -Should create the metadata object to be submitted by a metadata transaction to register the delegations on-chain. - -### **Params** - -`account`: In case the wallet supports multiple accounts. defaults to 0 +This endpoint should construct the cbor encoded delegation certificate according to the specs in [CIP-36 Example](https://github.com/Zeegomo/CIPs/blob/472181b9c69feeedae0b5b2db8b42d0cf4eb1a11/CIP-0036/README.md#example). -`chain`: Part of the derivation path. defaults to 0 +It should then sign the certificate with the staking key as described in the same example as above. -`role`: +The implementation of this endpoint can make use of the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.signData` and `api.submitTx` to perform the broadcasting of the transaction containing the metadata. -### **Returns** +Upon submission of the transaction containing the delegation cert as part of metadata, the wallet should store the delegation in its local storage and return an object that contains the delegation cert, the signature and the txhash of the transaction that the certificate was submitted with. -#### **`Delegation`** +## **`Delegation`** ``` export interface Delegation { @@ -183,36 +197,23 @@ The ***`reward_address`*** as specified in [CIP-8](https://cips.cardano.org/cips The ***`nonce`*** is an unsigned integer (of CBOR major type 0) that should be monotonically increasing across all transactions with the same staking key. The wallet manages this and guarantees that nonces are always unique and greater than the previous ones. A suitable nonce value is the `linux epoch timestamp`. -## **api.signDelegation**(delegation: DelegationMetadata, account: number = 0, role: number = 0, index: number = 0): Promise\<**`SignedDelegationMetadata`**> +This should be a call that implicitly cbor encodes the `delegation` object and uses the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.submitTx` to submit the transaction. The resulting transaction hash should be returned. -Since [CIP-18](https://cips.cardano.org/cips/cip18), multi-staking keys should be considered. However, a single voting profile should exist per wallet. A single staking key should be used to perform EDDSA over the voting profile blake2b-256 hash. The staking key used should still be the one defined in [CIP-11]((https://cips.cardano.org/cips/cip11). +This should be trigger a request to the wallet to approve the transaction. ### **Returns** -#### **`SignedDelegationMetadata`** - ``` -export interface SignedDelegationMetadata { - '61284': DelegationMetadata, - '61285': string +interface SignedDelegationMetadata { + delegation: Delegation, + signature: string, + txHash: string // of the transaction that submitted the delegation } ``` -Defines the result of signing the DelegationMetadata. - -- `61284`: Key that defines the registration metadata map - -- `61285`: Signature of the blake2b hash of the `DelegationMetadata` - -## **api.submitDelegation(delegation: SignedDelegationMetadataw): Promise\** - -This should be a call that implicitly cbor encodes the `delegation` object and uses the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.submitTx` to submit the transaction. The resulting transaction hash should be returned. - -This should be trigger a request to the wallet to approve the transaction. - Errors: `APIError`, `TxSendError` -### Delegation Cert process +## **Delegation Cert process** 1. **`Get Voting Key`** - use the method **api.getVotingKey** to return a ed25519 32 bytes public key (x value of the point on the curve). From 25fff8541e9e3029f22cea2e221f7d21d2be2482 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Tue, 26 Jul 2022 13:03:36 +0100 Subject: [PATCH 05/30] Typo, 32 bytes not 64 for ed25519 pub key --- CIP-0062/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 565215ad3f..f27aa7bb6a 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -147,7 +147,7 @@ The vote options. This is the set of options we can vote for. Should derive and return the wallets voting public key ### **Returns** -`cbor\` - cbor serialized 64 bytes (x, y) Ed25519 public key +`cbor\` - cbor serialized 32 bytes (x, y) Ed25519 public key The **`votingKey`** should be derived from the following path. From da74c101290704bb82d9dc6b359ecd60db6d1da8 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Thu, 28 Jul 2022 15:30:06 +0100 Subject: [PATCH 06/30] remove reward address, nonce and staking key from delegation object. wallet should manage these internally --- CIP-0062/README.md | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index f27aa7bb6a..f8b293d7da 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -174,9 +174,6 @@ Upon submission of the transaction containing the delegation cert as part of met ``` export interface Delegation { voting_delegation: GovernanceKey[], - staking_key: string, - reward_address: string, - nonce: number, purpose: Purpose } ``` @@ -185,18 +182,6 @@ Defines the structure to be crafted and signed for delegation of voting & their ***`voting_delegation`***: List of keys and their voting weight to delegate voting power to. -The ***`staking_key`*** is Ed25519 public key 32bytes (x only) associated with the stake address. Defined in [CIP-11]((https://cips.cardano.org/cips/cip11), which specifies the derivation path for the staking key: - -``` -m / 1852' / 1815' / account' / chain / 0 -``` - -The ***`reward_address`*** as specified in [CIP-8](https://cips.cardano.org/cips/cip8/#addressformats) - - -The ***`nonce`*** is an unsigned integer (of CBOR major type 0) that should be monotonically increasing across all transactions with the same staking key. The wallet manages this and guarantees that nonces are always unique and greater than the previous ones. A suitable nonce value is the `linux epoch timestamp`. - - This should be a call that implicitly cbor encodes the `delegation` object and uses the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.submitTx` to submit the transaction. The resulting transaction hash should be returned. This should be trigger a request to the wallet to approve the transaction. @@ -205,9 +190,20 @@ This should be trigger a request to the wallet to approve the transaction. ``` interface SignedDelegationMetadata { - delegation: Delegation, - signature: string, - txHash: string // of the transaction that submitted the delegation + certificate: DelegatedCertificate, + signature: string, // signature on the CIP-36 delegation certificate + txHash: string // of the transaction that submitted the delegation +} +``` + +#### **DelegatedCertificate** +``` +interface DelegatedCertificate { + delegations: GovernanceKey[] // key delegations, + stakingPub: string // staking public key + rewardAddress: string // reward address + nonce: number //nonce used in the transaction + purpose: Purpose } ``` @@ -221,6 +217,4 @@ Errors: `APIError`, `TxSendError` 3. **`Craft delegation cert`** - Use **api.buildDelegation** to construct the object containing the key array set to delegate voting power to. Each value will express the `weight` of the voting powers given. -4. **`Sign the delegation cert`** - Use **api.signDelegation** to sign the blake2b hash of the delegation cert and append it to the cert - -5. **`Submit delegation`** - Submit the metadata transaction to the chain using **api.submitDelegation** which implicitly can use the already existing **api.submitTx**, available from [CIP-30](https://cips.cardano.org/cips/cip30/) +4. **`Submit delegation`** - Submit the metadata transaction to the chain using **api.submitDelegation** which implicitly sign and/or can use the already existing **api.submitTx**, available from [CIP-30](https://cips.cardano.org/cips/cip30/) From 3c7db95c8babe40612a2ea46deb706ee0030808e Mon Sep 17 00:00:00 2001 From: ehanoc Date: Mon, 8 Aug 2022 11:29:10 +0100 Subject: [PATCH 07/30] Add getVotingKeys, rotateVotingKey, getCurrentVotingKey api methods to the API --- CIP-0062/README.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index f8b293d7da..67fec501c6 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -142,14 +142,16 @@ The vote options. This is the set of options we can vote for. # **`Delegation API`** -## **api.getVotingKey**(path: KeyPath): Promise\ - -Should derive and return the wallets voting public key +## **api.getVotingKeys**(): Promise[]> +Should return a list of all the voting keys for the current wallet. ### **Returns** -`cbor\` - cbor serialized 32 bytes (x, y) Ed25519 public key +An array with the cbor hex encoded public keys. + +## **api.rotateVotingKey**(): Promise> +This call should explicitly rotate the current in-use voting key. Given the current `address_index` in the derivation path defined in [CIP-36](https://cips.cardano.org/cips/cip36/), it should be incremented by 1. -The **`votingKey`** should be derived from the following path. +The key should be derived from the following path. ``` m / 1694' / 1815' / account' / role' / address_index' @@ -159,6 +161,17 @@ m / 1694' / 1815' / account' / role' / address_index' `address_index` - index of the key to use. +### **Returns** +cbor hex encoded representation of the public key + + +## **api.getCurrentVotingKey**(): Promise\> + +Should return the current in-use voting public-key. The wallet should maintain a reference to the current `adress_index` counter and return the public key for that index. + +### **Returns** +cbor hex encoded representation of the public key. + ## **api.submitDelegation(delegation: Delegation): Promise\** This endpoint should construct the cbor encoded delegation certificate according to the specs in [CIP-36 Example](https://github.com/Zeegomo/CIPs/blob/472181b9c69feeedae0b5b2db8b42d0cf4eb1a11/CIP-0036/README.md#example). From 8e9d58f0036b896386976f901c356a58c0786cc0 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Mon, 8 Aug 2022 16:54:45 +0100 Subject: [PATCH 08/30] Removing unnecessary keypath type --- CIP-0062/README.md | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 67fec501c6..e1e10b85f3 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -55,17 +55,6 @@ type enum Purpose = { `Purpose`: Defines the purpose of the delegations. This is used to limit the scope of the delegations. For example, a purpose might be a subset of Catalyst proposals, a council election, or even some private purpose (agreed by convention). -### **KeyPath** -``` -interface KeyPath = { - address_index: number - account: number - role: number -} -``` - - - ## **Namespace** ### **cardano.{walletName}.governance.enable(): Promise\** @@ -77,10 +66,7 @@ When both this API and **CIP-30** is being enabled, is up to the wallet to decid # **`Jormungandr API`** -## **api.submitVotes**(keyPath: KeyPath, votes: Vote[], spendingCounter: number): Promise\ - -`keyPath`: The derivation path values to the voting key for which transaction should be signed with. The derivation path should follow the already establish in [CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://cips.cardano.org/cips/cip36/). -_`m / 1694' / 1815' / account' / role' / address_index'`_ +## **api.submitVotes**(votes: Vote[], spendingCounter: number): Promise\ ### `spendingCounter`: The spending counter is used to prevent double voting. The current spending counter for the account should be provided and the implementation should increment it for each vote before submission and attach it to the vote according to [Jormungandr Voting] (https://input-output-hk.github.io/jormungandr/jcli/vote.html#voting). This needs to be in sequential order. @@ -134,8 +120,6 @@ The vote options. This is the set of options we can vote for. `InvalidBlockDateError` - If the `validUntil` is not a valid block date. -`InvalidVotingKeyError` - If the `keyPath` is not a valid voting key. - `InvalidVotePlanError` - If the `votePlanId` is not a valid vote plan. `InvalidVoteOptionError` - If the `index` is not a valid vote option. From 20feaf3b13adba32248a32a61e9ac34884f89f12 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Wed, 10 Aug 2022 09:03:23 +0100 Subject: [PATCH 09/30] Align naming of variables and update setup-by-step guide --- CIP-0062/README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index e1e10b85f3..ce8ec6d755 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -170,14 +170,14 @@ Upon submission of the transaction containing the delegation cert as part of met ``` export interface Delegation { - voting_delegation: GovernanceKey[], + delegations: GovernanceKey[], purpose: Purpose } ``` Defines the structure to be crafted and signed for delegation of voting & their respectively voting power. Embeds the stake key and reward address from the wallet, and constructs a suitable nonce. -***`voting_delegation`***: List of keys and their voting weight to delegate voting power to. +***`delegations`***: List of keys and their voting weight to delegate voting power to. This should be a call that implicitly cbor encodes the `delegation` object and uses the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.submitTx` to submit the transaction. The resulting transaction hash should be returned. @@ -212,6 +212,4 @@ Errors: `APIError`, `TxSendError` 2. **`Collect Voting Keys`** - Collect the keys to delegate voting power to. -3. **`Craft delegation cert`** - Use **api.buildDelegation** to construct the object containing the key array set to delegate voting power to. Each value will express the `weight` of the voting powers given. - -4. **`Submit delegation`** - Submit the metadata transaction to the chain using **api.submitDelegation** which implicitly sign and/or can use the already existing **api.submitTx**, available from [CIP-30](https://cips.cardano.org/cips/cip30/) +3. **`Submit delegation`** - Submit the metadata transaction to the chain using **api.submitDelegation** which implicitly sign and/or can use the already existing **api.submitTx**, available from [CIP-30](https://cips.cardano.org/cips/cip30/) From 66d8cf163d174df9c43be682c3d09a2884ce6bee Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Mon, 12 Sep 2022 16:02:50 +0700 Subject: [PATCH 10/30] clean changes ready for merge --- CIP-0062/README.md | 379 ++++++++++++++++++++++++++++++++------------- 1 file changed, 270 insertions(+), 109 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index ce8ec6d755..c2c68f5a34 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -1,20 +1,21 @@ --- CIP: 62 Title: Cardano dApp-Connector Governance extension -Authors: Bruno Martins +Authors: Bruno Martins , Steven Johnson Status: Draft Type: Standards Created: 2021-06-11 License: CC-BY-4.0 --- -# **Abstract** +# Abstract -This document describe the interface between webpage / web-based stack and cardano wallets. This specificies that API of the javascript object that need to be injected into the web applications in order to support all the Governance features. +This document describe the interface between webpage / web-based stack and cardano wallets. This specifies that API of the javascript object that need to be injected into the web applications in order to support all the Governance features. These definitions extend [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/) to provide specific support for vote delegation. -# **Motivation** +# Motivation + The goal for this CIP is to extend the dApp-Wallet web bridge to enable the construction of transactions containing metadata that conforms to [CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://cips.cardano.org/cips/cip36/), enabling new functionality including vote delegation to either private or public representatives (dReps), @@ -22,194 +23,354 @@ splitting or combining of private votes, the use of different voting keys or delegations for different purposes (Catalyst etc). -# **Specification** +# Specification -## `Types` +## Version -### **GovernanceKey** +The API Extension specified in this document will count as version 0.2.0 for version-checking purposes below. -``` +## Data Types + +### PublicKey + +TODO: Define this. + +### GovernanceKey + +```js type GovernanceKey = { votingKey: string, weight: number } - ``` -`votingKey`: Ed25519 pubkey 32 bytes HEX string - -`weight`: Used to calculate the actual voting power using the rules described -in -[CIP-36](https://cips.cardano.org/cips/cip36/). - +* `votingKey` - Ed25519 pubkey 32 bytes HEX string +* `weight` - Used to calculate the actual voting power using the rules described + in [CIP-36](https://cips.cardano.org/cips/cip36/). -### **Purpose** +### Voting Purpose -``` -type enum Purpose = { - CATALYST = 0, - OTHER = 1 +```js +type enum VotingPurpose = { + CATALYST = 0 } - ``` -`Purpose`: Defines the purpose of the delegations. This is used to limit the scope of the delegations. For example, a purpose might be a subset of Catalyst proposals, a council election, or even some private purpose (agreed by convention). +`VotingPurpose`: Defines the voting purpose of the governance functions. This is used +to limit the scope of the governance functions. For example, a voting purpose +might be a subset of Catalyst proposals, a council election, or even some +private purpose (agreed by convention). Currently, only voting purpose 0 (Zero) +is defined, and it is for Catalyst events. -## **Namespace** +**IMPORTANT**: The List of purposes in this CIP should be considered the +authoritative list of known purposes, subject to future amendment. Other voting +purposes will be defined as required, by either an update to this CIP or a +future CIP listing currently allocated Voting Purposes. -### **cardano.{walletName}.governance.enable(): Promise\** -The `cardano.{walletName}.governance.enable()` method is used to enable the governance API. It should request permission from the wallet to enable the API. If permission is granted, the rest of the API will be available. The wallet should maintain a specific whitelist of allowed clients for this API. This whitelist can be used to avoid asking for permission every time. +### BlockDate -This api being an extension of [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/), expects that `cardano.{walletName}.enable()` to be enabled and added to CIP-30 whitelist implicitly. +```js +interface BlockDate { + epoch: number + slot: number +} +``` -When both this API and **CIP-30** is being enabled, is up to the wallet to decide the number of prompts requesting permissions to be displayed to the user. +* epoch - an epoch value on the voting block chain. +* slot - a block slot number on the voting block chain. -# **`Jormungandr API`** +#### Proposal -## **api.submitVotes**(votes: Vote[], spendingCounter: number): Promise\ +```js +interface Proposal { + votePlanId: number + voteOptions: number[] +} +``` -### `spendingCounter`: -The spending counter is used to prevent double voting. The current spending counter for the account should be provided and the implementation should increment it for each vote before submission and attach it to the vote according to [Jormungandr Voting] (https://input-output-hk.github.io/jormungandr/jcli/vote.html#voting). This needs to be in sequential order. +Proposal information. -### **`votes`**: +* votePlanId - The unique ID of this proposal in the vote plan. This will be the same as anchored on voting chain, and is managed by the dApp. +* voteOptions - List of possible "choices" which can be made for this proposal. -``` +### Vote + +```js interface Vote { proposal: Proposal, choice: number, expiration: BlockDate + purpose: VotingPurpose, + spendingCounter: number } ``` -#### `expiration`: -chain epoch \& slot for when the vote will expire. The type used is: +An individual raw Unsigned Vote record. + +* proposal - The [proposal](#proposal) being voted on. +* choice - This value MUST match one of the available `voteOptions` in the `proposal` element. An `UnknownChoiceError` should be thrown if the value is not one of the valid `voteOptions` of the `proposal`. +* expiration - Voting Chain epoch \& slot for when the vote will expire. This value is supplied and maintained by the dApp, and forms a necessary component of a [Vote](#vote) +* purpose - The [voting purpose](#voting-purpose) being voted on. (Currently always 0). +* spendingCounter - The spending counter is used to prevent double voting. The spending counter for the vote transaction will be supplied and maintained by the dApp. The dApp will manage supplying this in the correct order, and this should not be enforced by the Wallet. + +It is required to attach it to the vote according to [Jormungandr Voting] (). + +## Delegation + +```js +interface Delegation { + delegations: GovernanceKey[], + purpose: VotingPurpose +} ``` -interface BlockDate { - epoch: number - slot: number + +The record of a voters delegation. + +* delegations - List of [Governance Keys](#governancekey) and their voting weight to delegate voting power to. +* purpose - The [Voting Purpose](#voting-purpose) being delegated. A voter may have multiple active delegations for different purposes, but only 1 active delegation per unique Voting Purpose. + +## DelegatedCertificate + +```js +interface DelegatedCertificate { + delegations: GovernanceKey[], + stakingPub: string, + rewardAddress: string, + nonce: number, + purpose: VotingPurpose } ``` -#### `choice`: -The choice **index** we want to vote for. An `UnkownChoiceError` should be thrown is the value is not within the `proposal` option set. +See [CIP-36](https://cips.cardano.org/cips/cip36/) for an explanation of these fields. Note: this object is not in exactly the same format as CIP-36, but the information it contains is the same. -#### **`proposal`** : -proposal information. Include the range of options we can use to vote. This defines the allowed values in `choice`. +## SignedDelegationMetadata +```js +interface SignedDelegationMetadata { + certificate: DelegatedCertificate, + signature: string, + txHash: string +} ``` -interface Proposal { - votePlanId: number - voteOptions: number[] + +* certificate: The [Delegation Certificate](#delegatedcertificate) that is signed. +* signature: signature on the CIP-36 delegation certificate. +* txHash: of the transaction that submitted the delegation. + +## Error Types + +### Extended APIError + +```js +APIErrorCode { + UnsupportedVotingPurpose: -100, + InvalidArgumentError: -101 + UnknownChoiceError: -102 + InvalidBlockDateError: -103 + InvalidVotePlanError: -104 + InvalidVoteOptionError: -105 +} + +APIError { + code: APIErrorCode, + info: string + votingPurpose: Purpose[] } ``` -##### `votePlanId`: -the vote plan id. This is used to identify the vote plan. This should be the same as anchored on chain. +These are the extended API Error Codes used by this specification. See +[CIP-30 Errors](https://cips.cardano.org/cips/cip30/#apierror) for the standard +API Error Codes, which are continue to be valid for this API Extension. + +* UnsupportedVotingPurpose - The wallet does not support one of the requested + voting purposes. The `votingPurpose` element will be present in the `APIError` object and will list all the voting purposes requested, which are unsupported bgy the wallet. Eg: + + If Voting purposes 0,5 and 9 were requested, and only 0 was supported by the + wallet. Then the errors will be: + + ```js + { + code: -100, + info: "Unsupported Voting Purpose 5 & 9", + votingPurpose: [5,9] + } + ``` + +* InvalidArgumentError - Generic error for errors in the formatting of the arguments. +* UnknownChoiceError - If a `choice` is not within the + [`proposal`](#proposal) option set. +* InvalidBlockDateError - If a [block date](#blockdate) is invalid. +* InvalidVotePlanError - If the `votePlanId` is not a valid vote plan. +* InvalidVoteOptionError - If the `index` is not a valid vote option. + +#### APIError elements + +* code - The `APIErrorCode` which is being reported. +* info - A Human readable description of the error. +* votingPurpose - (*OPTIONAL*) - Only present if the error relates to a voting purpose, and will list all the voting purposes which are involved in the error. See the individual error code descriptions for more information. +* rejectedVotes - (*OPTIONAL*) - In a voting transaction, there may be multiple votes being signed simultaneously. + +### Extended TxSignError + +```js +TxSignErrorCode { + ProofGeneration: 1, + UserDeclined: 2, + VoteRejected: 3, +} +``` + +```js +type TxSignError = { + code: TxSignErrorCode, + info: String, + rejectedVotes: number[] +} +``` + +All TxSignErrors defined in [CIP-30](https://cips.cardano.org/cips/cip30/#txsignerror) are unchanged. + +* UserDeclined - Raised when the user declined to sign the entire transaction, in the case of a vote submission, this would be returned if the user declined to sign ALL of the votes. +* VoteRejected - On a vote transaction, where there may be multiple votes. If the user accepted some votes, but rejected others, then this error is raised, AND `rejectedVotes` is present in the Error instance. + +## Governance Extension to CIP-30 + +### cardano.{walletName}.governance.apiVersion: String + +The version number of the Governance Extension API that the wallet supports. + +### cardano.{walletName}.governance.enable(purpose: VotingPurpose[]): Promise\ + +Errors: [`APIError`](#extended-apierror) + +The `cardano.{walletName}.governance.enable()` method is used to enable the +governance API. It should request permission from the wallet to enable the API for the requested purposes. + +If permission is granted, the rest of the API will be available. The wallet +should maintain a specific whitelist of allowed clients and voting purposes for +this API. This whitelist can be used to avoid asking for permission every time. + +This api, being an extension of +[CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/), +expects that `cardano.{walletName}.enable()` to be enabled and added to CIP-30 +whitelist implicitly. + +When both this API and [CIP-30](https://cips.cardano.org/cips/cip30/) being +enabled, is up to the wallet to decide the number of prompts requesting +permissions to be displayed to the user. + +* `purpose` - this is a list of purposes that the dApp is advising that it will be using on the API. The wallet must respond with an error if the purpose is not supported by the Wallet. + + Note: Currently only voting purpose 0 (Catalyst) is defined. The wallet should reject any other purpose requested. + +### Returns + +Upon successful connection via +[`cardano.{walletName}.governance.enable()`](#cardanowalletnamegovernanceenablepurpose-votingpurpose-promiseapi), +a javascript object we will refer to as `API` (type) / `api` (instance) is +returned to the dApp with the following methods. + +## Governance API + +All methods (all but the signing functionality) should not require any user +interaction as the user has already consented to the dApp reading information +about the wallet's governance state when they agreed to +[`cardano.{walletName}.governance.enable()`](#cardanowalletnamegovernanceenablepurpose-votingpurpose-promiseapi). +The remaining methods +[`api.signVotes()`](#apisignvotesvotes-vote-promisebytes) and +[`api.signData()`](#apisubmitdelegationdelegation-delegation-promisesigneddelegationmetadata) +must request the user's consent in an informative way for each and every API +call in order to maintain security. + +The API chosen here is for the mini mum API necessary for dApp <-> Wallet +interactions without convenience functions that don't strictly need the wallet's +state to work. -##### `voteOptions`: -The vote options. This is the set of options we can vote for. +## api.signVotes(votes: Vote[]): Promise\[] -### **Returns** +Errors: [`APIError`](#extended-apierror), [`TxSignError`](#extended-txsignerror) -`hash32` - This is the hash of the transaction that will be submitted to the node. +* votes - an array of up to 10 votes to be validated with the wallet user, and if valid, signed. -#### **Errors** -`InvalidArgumentError` - Generic error for errors in the formatting of the arguments. +IF the wallet user declines SOME of the votes, a [`TxSignError`](#extended-txsignerror) should be raised with `code` set to `VoteRejected` and the optional `rejectedVotes` array specifying the votes rejected. -`UnknownChoiceError` - If the `choice` is not within the `proposal` option set. +However, if the wallet user declines the entire set of votes, the wallet should raise a [`TxSignError`](#extended-txsignerror) with the `code` set to `UserDeclined`. -`InvalidBlockDateError` - If the `validUntil` is not a valid block date. +In either case, where the user declines to sign at least 1 of the votes, no signed votes are returned. -`InvalidVotePlanError` - If the `votePlanId` is not a valid vote plan. +### Returns -`InvalidVoteOptionError` - If the `index` is not a valid vote option. +`Bytes[]` - An array of the hex-encoded strings of the fully encoded and signed vote transactions. The dApp will submit these votes on behalf of the wallet. -# **`Delegation API`** +## api.getVotingKeys(): Promise[]> -## **api.getVotingKeys**(): Promise[]> -Should return a list of all the voting keys for the current wallet. +Should return a list of all the voting keys for the current wallet. + +### Returns -### **Returns** An array with the cbor hex encoded public keys. -## **api.rotateVotingKey**(): Promise> +## api.rotateVotingKey(): Promise> + This call should explicitly rotate the current in-use voting key. Given the current `address_index` in the derivation path defined in [CIP-36](https://cips.cardano.org/cips/cip36/), it should be incremented by 1. -The key should be derived from the following path. +The key should be derived from the following path. -``` +```text m / 1694' / 1815' / account' / role' / address_index' ``` -`1694` (year Voltaire was born) Sets a dedicated `purpose` in the derivation path for the voting profile. +`1694` (year Voltaire was born) Sets a dedicated `purpose` in the derivation path for the voting profile. -`address_index` - index of the key to use. +`address_index` - index of the key to use. -### **Returns** -cbor hex encoded representation of the public key +### Returns +cbor hex encoded representation of the [public key](#publickey). -## **api.getCurrentVotingKey**(): Promise\> +## api.getCurrentVotingKey(): Promise\> -Should return the current in-use voting public-key. The wallet should maintain a reference to the current `adress_index` counter and return the public key for that index. +Should return the current in-use voting [public key](#publickey). The wallet should maintain a reference to the current `address_index` counter and return the public key for that index. This call does NOT rotate the `address_index`. + +### Returns -### **Returns** cbor hex encoded representation of the public key. -## **api.submitDelegation(delegation: Delegation): Promise\** +## api.submitDelegation(delegation: Delegation): Promise\ + +Errors: [`APIError`](#extended-apierror), +[`TxSendError`](https://cips.cardano.org/cips/cip30/#txsenderror), +[`TxSignError`](https://cips.cardano.org/cips/cip30/#txsignerror) This endpoint should construct the cbor encoded delegation certificate according to the specs in [CIP-36 Example](https://github.com/Zeegomo/CIPs/blob/472181b9c69feeedae0b5b2db8b42d0cf4eb1a11/CIP-0036/README.md#example). It should then sign the certificate with the staking key as described in the same example as above. -The implementation of this endpoint can make use of the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.signData` and `api.submitTx` to perform the broadcasting of the transaction containing the metadata. +The implementation of this endpoint can make use of the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.signData` and `api.submitTx` to perform the broadcasting of the transaction containing the metadata. Upon submission of the transaction containing the delegation cert as part of metadata, the wallet should store the delegation in its local storage and return an object that contains the delegation cert, the signature and the txhash of the transaction that the certificate was submitted with. -## **`Delegation`** - -``` -export interface Delegation { - delegations: GovernanceKey[], - purpose: Purpose -} -``` - -Defines the structure to be crafted and signed for delegation of voting & their respectively voting power. Embeds the stake key and reward address from the wallet, and constructs a suitable nonce. - -***`delegations`***: List of keys and their voting weight to delegate voting power to. +* delegation - the voter registration [delegation](#delegation) record. This should be a call that implicitly cbor encodes the `delegation` object and uses the already existing [CIP-30](https://cips.cardano.org/cips/cip30/) `api.submitTx` to submit the transaction. The resulting transaction hash should be returned. -This should be trigger a request to the wallet to approve the transaction. +This should trigger a request to the user of the wallet to approve the transaction. -### **Returns** +### Returns -``` -interface SignedDelegationMetadata { - certificate: DelegatedCertificate, - signature: string, // signature on the CIP-36 delegation certificate - txHash: string // of the transaction that submitted the delegation -} -``` +The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registration delegation passed in the `delegation` parameter. -#### **DelegatedCertificate** -``` -interface DelegatedCertificate { - delegations: GovernanceKey[] // key delegations, - stakingPub: string // staking public key - rewardAddress: string // reward address - nonce: number //nonce used in the transaction - purpose: Purpose -} -``` +# Examples of Message Flows and Processes + +## Delegation Cert process -Errors: `APIError`, `TxSendError` +1. **`Get Voting Key`** - dApp call the method [**api.getCurrentVotingKey**](#apigetcurrentvotingkey-promisecborpublickey) to return a ed25519 32 bytes public key (x value of the point on the curve). -## **Delegation Cert process** +2. **`Collect Voting Keys`** - The dApp Collects the dRep keys to delegate voting power to from the Catalyst Voting Center backend, and the user selects the required delegation. -1. **`Get Voting Key`** - use the method **api.getVotingKey** to return a ed25519 32 bytes public key (x value of the point on the curve). +3. **`Submit delegation`** - Submit the metadata transaction to the chain using [**api.submitDelegation**](#apisubmitdelegationdelegation-delegation-promisesigneddelegationmetadata) which implicitly sign and/or can use the already existing [**api.submitTx**](https://cips.cardano.org/cips/cip30/#apisubmittxtxcbortransactionpromisehash32), available from [CIP-30](https://cips.cardano.org/cips/cip30/) -2. **`Collect Voting Keys`** - Collect the keys to delegate voting power to. +## Casting a vote -3. **`Submit delegation`** - Submit the metadata transaction to the chain using **api.submitDelegation** which implicitly sign and/or can use the already existing **api.submitTx**, available from [CIP-30](https://cips.cardano.org/cips/cip30/) +1. The dApp collects the users voting choices for a particular voting proposal. +2. The dApp submits that choice through [api.signVotes](#apisignvotesvotes-vote-promisebytes) which confirms the votes with the user, and signs them. From da063a42f196a00787c06f82f91bdfe456ca1667 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Tue, 13 Sep 2022 06:38:28 +0100 Subject: [PATCH 11/30] Remove unnecessary rotateVotingKeys and getVotingKeys --- CIP-0062/README.md | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index c2c68f5a34..2511950ed9 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -302,40 +302,6 @@ In either case, where the user declines to sign at least 1 of the votes, no sign `Bytes[]` - An array of the hex-encoded strings of the fully encoded and signed vote transactions. The dApp will submit these votes on behalf of the wallet. -## api.getVotingKeys(): Promise[]> - -Should return a list of all the voting keys for the current wallet. - -### Returns - -An array with the cbor hex encoded public keys. - -## api.rotateVotingKey(): Promise> - -This call should explicitly rotate the current in-use voting key. Given the current `address_index` in the derivation path defined in [CIP-36](https://cips.cardano.org/cips/cip36/), it should be incremented by 1. - -The key should be derived from the following path. - -```text -m / 1694' / 1815' / account' / role' / address_index' -``` - -`1694` (year Voltaire was born) Sets a dedicated `purpose` in the derivation path for the voting profile. - -`address_index` - index of the key to use. - -### Returns - -cbor hex encoded representation of the [public key](#publickey). - -## api.getCurrentVotingKey(): Promise\> - -Should return the current in-use voting [public key](#publickey). The wallet should maintain a reference to the current `address_index` counter and return the public key for that index. This call does NOT rotate the `address_index`. - -### Returns - -cbor hex encoded representation of the public key. - ## api.submitDelegation(delegation: Delegation): Promise\ Errors: [`APIError`](#extended-apierror), From a12b8a6fbea76aa0c3dfc64c83701cb61e389358 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Thu, 15 Sep 2022 08:14:57 +0100 Subject: [PATCH 12/30] Add sample data for delegation certificates and related keys --- CIP-0062/README.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 2511950ed9..43d69cfb24 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -340,3 +340,72 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr 1. The dApp collects the users voting choices for a particular voting proposal. 2. The dApp submits that choice through [api.signVotes](#apisignvotesvotes-vote-promisebytes) which confirms the votes with the user, and signs them. + +## **Test Vectors** + +### *** keys *** + +`payment verification key`: +``` +{ + "type": "PaymentVerificationKeyShelley_ed25519", + "description": "Payment Verification Key", + "cborHex": "58203bc3383b1b88a628e6fa55dbca446972d5b0cd71bcd8c133b2fa9cd3afbd1d48" +} + +``` + +`payment secret key`: +``` +{ + "type": "PaymentSigningKeyShelley_ed25519", + "description": "Payment Signing Key", + "cborHex": "5820b5c85fa8fb2d8cd4e4f624c206946652b6764e1af83034a79b32320ce3940dd9" +} +``` + +`staking verification key`: +``` +{ + "type": "StakeVerificationKeyShelley_ed25519", + "description": "Stake Verification Key", + "cborHex": "5820b5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555" +} +``` + +`staking secret key`: +``` +{ + "type": "StakeSigningKeyShelley_ed25519", + "description": "Stake Signing Key", + "cborHex": "58202f669f45365099666940922d47b29563d2c9f885c88a077bfea17631a7579d65" +} +``` + +### *** Delegation Certificate *** + +`Delegation certificate sample`: +``` +{ + "1":[["1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["b48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], + "2":"93bf1450ec2a3b18eebc7acfd311e695e12232efdf9ce4ac21e8b536dfacc70f", + + "3":"e1160a9d8f375f8e72b4bdbfa4867ca341a5aa6f17fde654c1a7d3254e", + "4":5479467, + "5":0 +} +``` + +`Delegation certificate after signature`: +``` +{ + "61284":{ + "1":[["1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["b48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], + "2":"93bf1450ec2a3b18eebc7acfd311e695e12232efdf9ce4ac21e8b536dfacc70f", + "3":"e1160a9d8f375f8e72b4bdbfa4867ca341a5aa6f17fde654c1a7d3254e", + "4":5479467, + "5":0 + }, + "61285":"0x3c25da29d43e70fb331c93b1197863e0d0a2e1cf7048994c580b0fc974f16bbb18c389aee380a66c0e7b6141f1df77b5db132dc228dbae9167238d96d4c4a80a" +} +``` \ No newline at end of file From 5dc31ab065f6bf7a9e7e8c7ddb94c85851252cbe Mon Sep 17 00:00:00 2001 From: ehanoc Date: Tue, 27 Sep 2022 17:40:11 +0100 Subject: [PATCH 13/30] GetVotingKey endpoint --- CIP-0062/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 43d69cfb24..8d2c58a606 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -302,6 +302,12 @@ In either case, where the user declines to sign at least 1 of the votes, no sign `Bytes[]` - An array of the hex-encoded strings of the fully encoded and signed vote transactions. The dApp will submit these votes on behalf of the wallet. +## api.getVotingKey(): Promise\\> + +Should return the voting [public key](#publickey). The wallet should use `address_index`= 0 and return the public key for that index. +### Returns +cbor hex encoded representation of the public key. + ## api.submitDelegation(delegation: Delegation): Promise\ Errors: [`APIError`](#extended-apierror), From dd1a2e87d6adff2a1e4bf8eb301693b90402b4d1 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Thu, 3 Nov 2022 14:07:02 +0000 Subject: [PATCH 14/30] votePlanId as Hex encoded. Add votePublic boolean --- CIP-0062/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 8d2c58a606..ea133e4dd3 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -83,15 +83,17 @@ interface BlockDate { ```js interface Proposal { - votePlanId: number + votePlanId: string voteOptions: number[] + votePublic: boolean } ``` Proposal information. -* votePlanId - The unique ID of this proposal in the vote plan. This will be the same as anchored on voting chain, and is managed by the dApp. +* votePlanId - Hex encoded string to represent vote plan unique identifier. This will be the same as anchored on voting chain, and is managed by the dApp. * voteOptions - List of possible "choices" which can be made for this proposal. +* votePublic - Boolean indicating whether the vote is public or private. ### Vote From b6a6b5214a561fe869b1b6fd8d8f558f7e7163c8 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Wed, 30 Nov 2022 09:39:15 +0000 Subject: [PATCH 15/30] Add missing rationale. Small improvements, formatting, typos add proposalIndex --- CIP-0062/README.md | 92 +++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index ea133e4dd3..6cdf2b5255 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -23,6 +23,15 @@ splitting or combining of private votes, the use of different voting keys or delegations for different purposes (Catalyst etc). +## Rationale +To provide governance specific functionality to wallet's and expose such API to the dApps (i.e Voting Centers). + +This also addresses some short-comings of [CIP-30](https://cips.cardano.org/cips/cip30/); which signData can only be done by known an address; This signature is not relevant to a specific address, nor the dApp will know an address attached to the voting key. The voting key derivation is defined in [CIP-36](https://cips.cardano.org/cips/cip36/). + +Perhaps [CIP-30](https://cips.cardano.org/cips/cip30/) could be expanded to also know how to perform `signData` from a given public key from a specific derivation path; instead of doing so only by known address. + +The other reason for this specification is to have a specific, but optional, namespace for governance specific wallet functionality. As such, wallet providers might choose not to implement this specification on top of [CIP-30](https://cips.cardano.org/cips/cip30/). + # Specification ## Version @@ -37,9 +46,9 @@ TODO: Define this. ### GovernanceKey -```js +```ts type GovernanceKey = { - votingKey: string, + votingKey: string weight: number } ``` @@ -50,7 +59,7 @@ type GovernanceKey = { ### Voting Purpose -```js +```ts type enum VotingPurpose = { CATALYST = 0 } @@ -69,7 +78,7 @@ future CIP listing currently allocated Voting Purposes. ### BlockDate -```js +```ts interface BlockDate { epoch: number slot: number @@ -81,11 +90,12 @@ interface BlockDate { #### Proposal -```js +```ts interface Proposal { votePlanId: string voteOptions: number[] votePublic: boolean + proposalIndex: number } ``` @@ -97,12 +107,12 @@ Proposal information. ### Vote -```js +```ts interface Vote { - proposal: Proposal, - choice: number, + proposal: Proposal + choice: number expiration: BlockDate - purpose: VotingPurpose, + purpose: VotingPurpose spendingCounter: number } ``` @@ -119,9 +129,9 @@ It is required to attach it to the vote according to [Jormungandr Voting] ( Date: Wed, 30 Nov 2022 09:48:20 +0000 Subject: [PATCH 16/30] Fix description refering to old method name --- CIP-0062/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 6cdf2b5255..4bef516a92 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -348,7 +348,7 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr ## Delegation Cert process -1. **`Get Voting Key`** - dApp call the method [**api.getCurrentVotingKey**](#apigetcurrentvotingkey-promisecborpublickey) to return a ed25519 32 bytes public key (x value of the point on the curve). +1. **`Get Voting Key`** - dApp call the method [**api.getVotingKey**](#apigetvotingkey-promise-cborpublickey) to get the voting public key. 2. **`Collect Voting Keys`** - The dApp Collects the dRep keys to delegate voting power to from the Catalyst Voting Center backend, and the user selects the required delegation. From 239d9438f09a291e27ffd25540246c68326b483f Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Mon, 12 Dec 2022 17:53:16 +0700 Subject: [PATCH 17/30] md formatting --- CIP-0062/README.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 4bef516a92..b5fdd28288 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -24,9 +24,10 @@ the use of different voting keys or delegations for different purposes (Catalyst etc). ## Rationale -To provide governance specific functionality to wallet's and expose such API to the dApps (i.e Voting Centers). -This also addresses some short-comings of [CIP-30](https://cips.cardano.org/cips/cip30/); which signData can only be done by known an address; This signature is not relevant to a specific address, nor the dApp will know an address attached to the voting key. The voting key derivation is defined in [CIP-36](https://cips.cardano.org/cips/cip36/). +To provide governance specific functionality to wallet's and expose such API to the dApps (i.e Voting Centers). + +This also addresses some short-comings of [CIP-30](https://cips.cardano.org/cips/cip30/); which signData can only be done by known an address; This signature is not relevant to a specific address, nor the dApp will know an address attached to the voting key. The voting key derivation is defined in [CIP-36](https://cips.cardano.org/cips/cip36/). Perhaps [CIP-30](https://cips.cardano.org/cips/cip30/) could be expanded to also know how to perform `signData` from a given public key from a specific derivation path; instead of doing so only by known address. @@ -317,7 +318,9 @@ In either case, where the user declines to sign at least 1 of the votes, no sign ## api.getVotingKey(): Promise\\> Should return the voting [public key](#publickey). The wallet should use `address_index`= 0 and return the public key for that index. + ### Returns + cbor hex encoded representation of the public key. ## api.submitDelegation(delegation: Delegation): Promise\ @@ -361,19 +364,21 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr ## **Test Vectors** -### *** keys *** +### ***keys*** `payment verification key`: + ```json { "type": "PaymentVerificationKeyShelley_ed25519", "description": "Payment Verification Key", "cborHex": "58203bc3383b1b88a628e6fa55dbca446972d5b0cd71bcd8c133b2fa9cd3afbd1d48" } - -``` -`payment secret key`: +``` + +`payment secret key`: + ```json { "type": "PaymentSigningKeyShelley_ed25519", @@ -383,6 +388,7 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr ``` `staking verification key`: + ```json { "type": "StakeVerificationKeyShelley_ed25519", @@ -392,6 +398,7 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr ``` `staking secret key`: + ```json { "type": "StakeSigningKeyShelley_ed25519", @@ -400,14 +407,15 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr } ``` -### *** Delegation Certificate *** +### ***Delegation Certificate*** `Delegation certificate sample`: + ```json { "1":[["1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["b48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], "2":"93bf1450ec2a3b18eebc7acfd311e695e12232efdf9ce4ac21e8b536dfacc70f", - + "3":"e1160a9d8f375f8e72b4bdbfa4867ca341a5aa6f17fde654c1a7d3254e", "4":5479467, "5":0 @@ -415,6 +423,7 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr ``` `Delegation certificate after signature`: + ```json { "61284":{ @@ -426,4 +435,4 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr }, "61285":"0x3c25da29d43e70fb331c93b1197863e0d0a2e1cf7048994c580b0fc974f16bbb18c389aee380a66c0e7b6141f1df77b5db132dc228dbae9167238d96d4c4a80a" } -``` \ No newline at end of file +``` From 48acc62a61268067dfac04f6f3719c71308e5532 Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Mon, 12 Dec 2022 19:32:59 +0700 Subject: [PATCH 18/30] fix typo --- CIP-0062/README.md | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index b5fdd28288..1316d42dd7 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -110,11 +110,12 @@ Proposal information. ```ts interface Vote { - proposal: Proposal - choice: number - expiration: BlockDate - purpose: VotingPurpose - spendingCounter: number + proposal: Proposal; + choice: number; + expiration: BlockDate; + purpose: VotingPurpose; + spendingCounter?: number; + spendingCounterLane?: number; } ``` @@ -124,9 +125,10 @@ An individual raw Unsigned Vote record. * choice - This value MUST match one of the available `voteOptions` in the `proposal` element. An `UnknownChoiceError` should be thrown if the value is not one of the valid `voteOptions` of the `proposal`. * expiration - Voting Chain epoch \& slot for when the vote will expire. This value is supplied and maintained by the dApp, and forms a necessary component of a [Vote](#vote) * purpose - The [voting purpose](#voting-purpose) being voted on. (Currently always 0). -* spendingCounter - The spending counter is used to prevent double voting. The spending counter for the vote transaction will be supplied and maintained by the dApp. The dApp will manage supplying this in the correct order, and this should not be enforced by the Wallet. +* spendingCounter - Optional, but if present, the spending counter is used to prevent double voting. The spending counter for the vote transaction will be supplied and maintained by the dApp. The dApp will manage supplying this in the correct order, and this should not be enforced by the Wallet. +* spendingCounterLane - Optional, if not present but required defaults to 0. The spending counter may be spread across multiple lanes, this field defines which lane the spending counter relates to. -It is required to attach it to the vote according to [Jormungandr Voting] (). +Note: `spendingCounter` and `spendingCounterLane` are fully managed by the voting dApp and if present are used to create the vote fragment for proper submission to the voting system. The wallet should simply use the values defined, and does not need to track them. ## Delegation @@ -230,6 +232,7 @@ type enum TxSignErrorCode { ProofGeneration = 1, UserDeclined = 2, VoteRejected = 3, + UnsupportedVoteFormat = 4, } ``` @@ -295,21 +298,39 @@ The remaining methods must request the user's consent in an informative way for each and every API call in order to maintain security. -The API chosen here is for the mini mum API necessary for dApp <-> Wallet +The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. -## api.signVotes(votes: Vote[]): Promise\[] +## api.signVotes(votes: Vote[], settings: string): Promise\[] Errors: [`APIError`](#extended-apierror), [`TxSignError`](#extended-txsignerror) -* votes - an array of up to 10 votes to be validated with the wallet user, and if valid, signed. +* `votes` - an array of up to 10 votes to be validated with the wallet user and, if valid, signed. +* `settings` - *Optional*. Settings which are universally applicable to all `votes` being signed. This is a json string. The fields within the settings json string depend on the format of the vote record. The wallet does not need to interpret this field and should pass it unchanged to the logic used to format the vote transaction. However, to support multiple future vote transaction formats, the `settings` must contain at least: + `'{"purpose":,"ver":,...}'` + + * `"purpose"` is the purpose of the vote transaction, which defines its format. It is a number and matches the defined [voting purposes](#voting-purpose). + * `"ver"` is the version of the vote transaction, which also defines its format. It is a number. + * `...` Variable fields defined by the vote transaction type being formatted and signed. + + These two fields allow the transaction format to be changed to accommodate future voting systems using this CIP standard. The wallet can inspect these two fields to ensure the correct vote format is being signed. It is legal for voting purposes to reuse or share vote formats. + + Vote transaction formats are defined by the [voting purposes](#voting-purpose), and are not documented in this CIP. + +### List of known vote transaction formats + +| `"purpose"` | `"ver"` | Vote Format | Specification | +| --- | --- | --- | --- | +| 0 | 0 | Project Catalyst vote: V0 | [Catalyst Core Specifications](https://input-output-hk.github.io/catalyst-core/) | IF the wallet user declines SOME of the votes, a [`TxSignError`](#extended-txsignerror) should be raised with `code` set to `VoteRejected` and the optional `rejectedVotes` array specifying the votes rejected. However, if the wallet user declines the entire set of votes, the wallet should raise a [`TxSignError`](#extended-txsignerror) with the `code` set to `UserDeclined`. -In either case, where the user declines to sign at least 1 of the votes, no signed votes are returned. +If the `purpose` and `ver` of the vote transaction format as defined by the `settings` field is unknown to the wallet, a [`TxSignError`](#extended-txsignerror) should be raised with the `code` set to `UnsupportedVoteFormat`. + +In all cases, where an error occurs, no signed votes are returned. ### Returns From 864ef7205c27e948160f6c1d71946af0171c1045 Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Mon, 12 Dec 2022 22:54:57 +0700 Subject: [PATCH 19/30] correct the proposal structure --- CIP-0062/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 1316d42dd7..00923e30a5 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -93,18 +93,19 @@ interface BlockDate { ```ts interface Proposal { - votePlanId: string - voteOptions: number[] - votePublic: boolean - proposalIndex: number + votePlanId: string; + proposalIndex: number; + voteOptions?: number; + voteEncKey?: string; } ``` Proposal information. * votePlanId - Hex encoded string to represent vote plan unique identifier. This will be the same as anchored on voting chain, and is managed by the dApp. -* voteOptions - List of possible "choices" which can be made for this proposal. -* votePublic - Boolean indicating whether the vote is public or private. +* proposalIndex - The index of the proposal within the vote plan. +* voteOptions - *Optional*. Total number of vote options. Only present in a private/encrypted vote. +* voteEncKey - *Optional*. If this vote is Private, this field is present and contains the key used to encrypt the vote. When the vote is public, this key is absent from the proposal. ### Vote From 52a2d3c50299a7b5239c7424bdbbf97fefd6d9ab Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Tue, 13 Dec 2022 22:18:28 +0700 Subject: [PATCH 20/30] add example settings string for the project catalyst vote v0 format --- CIP-0062/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 00923e30a5..c6204239bc 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -321,9 +321,9 @@ Errors: [`APIError`](#extended-apierror), [`TxSignError`](#extended-txsignerror) ### List of known vote transaction formats -| `"purpose"` | `"ver"` | Vote Format | Specification | -| --- | --- | --- | --- | -| 0 | 0 | Project Catalyst vote: V0 | [Catalyst Core Specifications](https://input-output-hk.github.io/catalyst-core/) | +| `"purpose"` | `"ver"` | Vote Format | Specification | Example Settings String | +| --- | --- | --- | --- | --- | +| 0 | 0 | Project Catalyst vote: V0 | [Catalyst Core Specifications](https://input-output-hk.github.io/catalyst-core/) | `{"purpose":0,"ver":0,"fees":{"constant":10,"coefficient":2,"certificate":100},"discrimination":"production","block0_initial_hash":{"hash":"baf6b54817cf2a3e865f432c3922d28ac5be641e66662c66d445f141e409183e"},"block0_date":1586637936,"slot_duration":20,"time_era":{"epoch_start":0,"slot_start":0,"slots_per_epoch":180},"transaction_max_expiry_epochs":1}` | IF the wallet user declines SOME of the votes, a [`TxSignError`](#extended-txsignerror) should be raised with `code` set to `VoteRejected` and the optional `rejectedVotes` array specifying the votes rejected. From fe0247d0c3e2c4a7608f5a92a0ecc39fd1914bc2 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Mon, 19 Dec 2022 03:54:08 -0500 Subject: [PATCH 21/30] Update CIP-0062/README.md Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- CIP-0062/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 4bef516a92..02aee2a7d5 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -284,7 +284,7 @@ returned to the dApp with the following methods. ## Governance API -All methods (all but the signing functionality) should not require any user +Except `signVotes`, no other method should require any user interaction as the user has already consented to the dApp reading information about the wallet's governance state when they agreed to [`cardano.{walletName}.governance.enable()`](#cardanowalletnamegovernanceenablepurpose-votingpurpose-promiseapi). From 9a98ee69fd6473d6e863a2e7bc9be7ac222d41b9 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 6 Jan 2023 14:45:28 +0000 Subject: [PATCH 22/30] Replaced .getVotingKey with .getVotingCredentials --- CIP-0062/README.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 02aee2a7d5..5856d49e31 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -42,18 +42,18 @@ The API Extension specified in this document will count as version 0.2.0 for ver ### PublicKey -TODO: Define this. +A string representing a 32 byte Ed25519 public key, Bech32 encoded with appropriate prefixes from [CIP-0005](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0005). ### GovernanceKey ```ts type GovernanceKey = { - votingKey: string + votingKey: cbor weight: number } ``` -* `votingKey` - Ed25519 pubkey 32 bytes HEX string +* `votingKey` - A cbor encoded `PublicKey` used to represent the target of the delegation. * `weight` - Used to calculate the actual voting power using the rules described in [CIP-36](https://cips.cardano.org/cips/cip36/). @@ -76,6 +76,18 @@ authoritative list of known purposes, subject to future amendment. Other voting purposes will be defined as required, by either an update to this CIP or a future CIP listing currently allocated Voting Purposes. +### VotingCredentials +```ts +interface VotingCredentials { + votingKey: PublicKey + stakingCredential: PublicKey +} +``` +Information used to identify a wallet's voting credentials. + +* votingKey - Derivation as described within [CIP-0036](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036), wallets should use `address_index`= 0. +* stakingCredential - At the moment, the only supported staking credential is a public staking key. This is used to represent the wallet's staked ADA. + ### BlockDate ```ts @@ -314,11 +326,13 @@ In either case, where the user declines to sign at least 1 of the votes, no sign `Bytes[]` - An array of the hex-encoded strings of the fully encoded and signed vote transactions. The dApp will submit these votes on behalf of the wallet. -## api.getVotingKey(): Promise\\> +## api.getVotingCredentials(): Promise\ + +Should return the in use voting credentials of the wallet. -Should return the voting [public key](#publickey). The wallet should use `address_index`= 0 and return the public key for that index. ### Returns -cbor hex encoded representation of the public key. + +The [VotingCredentials](#votingcredentials) of the wallet, which contain it's voting key and associated staking credential used for governance. ## api.submitDelegation(delegation: Delegation): Promise\ From 7336a91a7bb5ff508e6066ec9410e9d8971312be Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Sun, 8 Jan 2023 16:17:44 +0000 Subject: [PATCH 23/30] Removed Bech32 encoding for public keys --- CIP-0062/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 5856d49e31..279cf461b1 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -42,18 +42,18 @@ The API Extension specified in this document will count as version 0.2.0 for ver ### PublicKey -A string representing a 32 byte Ed25519 public key, Bech32 encoded with appropriate prefixes from [CIP-0005](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0005). +A hex string representing a 32 byte Ed25519 public key. ### GovernanceKey ```ts type GovernanceKey = { - votingKey: cbor + votingKey: PublicKey weight: number } ``` -* `votingKey` - A cbor encoded `PublicKey` used to represent the target of the delegation. +* `votingKey` - A voting `PublicKey` used to represent the target of the delegation. * `weight` - Used to calculate the actual voting power using the rules described in [CIP-36](https://cips.cardano.org/cips/cip36/). @@ -83,7 +83,7 @@ interface VotingCredentials { stakingCredential: PublicKey } ``` -Information used to identify a wallet's voting credentials. +Information used to represent a wallet's voting credentials. * votingKey - Derivation as described within [CIP-0036](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036), wallets should use `address_index`= 0. * stakingCredential - At the moment, the only supported staking credential is a public staking key. This is used to represent the wallet's staked ADA. @@ -332,7 +332,7 @@ Should return the in use voting credentials of the wallet. ### Returns -The [VotingCredentials](#votingcredentials) of the wallet, which contain it's voting key and associated staking credential used for governance. +The [VotingCredentials](#votingcredentials) of the wallet, which contain it's voting key and associated staking credential used for [CIP-36](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0036) style governance. ## api.submitDelegation(delegation: Delegation): Promise\ From bbfce744647bd678404a473b475bad97441975d5 Mon Sep 17 00:00:00 2001 From: ehanoc Date: Thu, 19 Jan 2023 05:03:03 -0500 Subject: [PATCH 24/30] Update CIP-0062/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rafael Korbaš --- CIP-0062/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index c6204239bc..3a11bfa6f6 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -95,7 +95,7 @@ interface BlockDate { interface Proposal { votePlanId: string; proposalIndex: number; - voteOptions?: number; + voteOptions?: number[]; voteEncKey?: string; } ``` From d931f42180eb99278f7bf990343ec46299dc496c Mon Sep 17 00:00:00 2001 From: ehanoc Date: Thu, 19 Jan 2023 05:11:48 -0500 Subject: [PATCH 25/30] Update CIP-0062/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rafael Korbaš --- CIP-0062/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 0565830436..d3283d6a9d 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -163,7 +163,7 @@ The record of a voters delegation. interface DelegatedCertificate { delegations: GovernanceKey[] stakingPub: string - rewardAddress: string + paymentAddress: string nonce: number purpose: VotingPurpose } From d8b140b4f14b9f78e0299847f4323eb64cd881e2 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 20 Jan 2023 15:59:36 +0000 Subject: [PATCH 26/30] Refactor to match new CIP-01 requirements --- CIP-0062/README.md | 182 ++++++++++++++++------------------------ CIP-0062/test-vector.md | 97 +++++++++++++++++++++ 2 files changed, 168 insertions(+), 111 deletions(-) create mode 100644 CIP-0062/test-vector.md diff --git a/CIP-0062/README.md b/CIP-0062/README.md index d3283d6a9d..9254848d9a 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -1,20 +1,34 @@ --- CIP: 62 Title: Cardano dApp-Connector Governance extension -Authors: Bruno Martins , Steven Johnson -Status: Draft -Type: Standards +Status: Proposed +Category: Wallets +Authors: + - Bruno Martins + - Steven Johnson +Implementors: + - Begin + - Eternl + - Flint + - GeroWallet + - NuFi + - Lace + - Typhon +Discussions: + - https://github.com/cardano-foundation/CIPs/pull/296 Created: 2021-06-11 License: CC-BY-4.0 --- -# Abstract +# CIP-0062: Cardano dApp-Connector Governance extension + +## Abstract This document describe the interface between webpage / web-based stack and cardano wallets. This specifies that API of the javascript object that need to be injected into the web applications in order to support all the Governance features. These definitions extend [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/) to provide specific support for vote delegation. -# Motivation +## Motivation The goal for this CIP is to extend the dApp-Wallet web bridge to enable the construction of transactions containing metadata that conforms to [CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://cips.cardano.org/cips/cip36/), @@ -23,29 +37,19 @@ splitting or combining of private votes, the use of different voting keys or delegations for different purposes (Catalyst etc). -## Rationale - -To provide governance specific functionality to wallet's and expose such API to the dApps (i.e Voting Centers). - -This also addresses some short-comings of [CIP-30](https://cips.cardano.org/cips/cip30/); which signData can only be done by known an address; This signature is not relevant to a specific address, nor the dApp will know an address attached to the voting key. The voting key derivation is defined in [CIP-36](https://cips.cardano.org/cips/cip36/). +## Specification -Perhaps [CIP-30](https://cips.cardano.org/cips/cip30/) could be expanded to also know how to perform `signData` from a given public key from a specific derivation path; instead of doing so only by known address. - -The other reason for this specification is to have a specific, but optional, namespace for governance specific wallet functionality. As such, wallet providers might choose not to implement this specification on top of [CIP-30](https://cips.cardano.org/cips/cip30/). - -# Specification - -## Version +### Version The API Extension specified in this document will count as version 0.2.0 for version-checking purposes below. -## Data Types +### Data Types -### PublicKey +#### PublicKey A hex string representing a 32 byte Ed25519 public key. -### GovernanceKey +#### GovernanceKey ```ts type GovernanceKey = { @@ -58,7 +62,7 @@ type GovernanceKey = { * `weight` - Used to calculate the actual voting power using the rules described in [CIP-36](https://cips.cardano.org/cips/cip36/). -### Voting Purpose +#### Voting Purpose ```ts type enum VotingPurpose = { @@ -77,7 +81,7 @@ authoritative list of known purposes, subject to future amendment. Other voting purposes will be defined as required, by either an update to this CIP or a future CIP listing currently allocated Voting Purposes. -### VotingCredentials +#### VotingCredentials ```ts interface VotingCredentials { votingKey: PublicKey @@ -89,7 +93,7 @@ Information used to represent a wallet's voting credentials. * votingKey - Derivation as described within [CIP-0036](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036), wallets should use `address_index`= 0. * stakingCredential - At the moment, the only supported staking credential is a public staking key. This is used to represent the wallet's staked ADA. -### BlockDate +#### BlockDate ```ts interface BlockDate { @@ -119,7 +123,7 @@ Proposal information. * voteOptions - *Optional*. Total number of vote options. Only present in a private/encrypted vote. * voteEncKey - *Optional*. If this vote is Private, this field is present and contains the key used to encrypt the vote. When the vote is public, this key is absent from the proposal. -### Vote +#### Vote ```ts interface Vote { @@ -143,7 +147,7 @@ An individual raw Unsigned Vote record. Note: `spendingCounter` and `spendingCounterLane` are fully managed by the voting dApp and if present are used to create the vote fragment for proper submission to the voting system. The wallet should simply use the values defined, and does not need to track them. -## Delegation +#### Delegation ```ts interface Delegation { @@ -157,7 +161,7 @@ The record of a voters delegation. * delegations - List of [Governance Keys](#governancekey) and their voting weight to delegate voting power to. * purpose - The [Voting Purpose](#voting-purpose) being delegated. A voter may have multiple active delegations for different purposes, but only 1 active delegation per unique Voting Purpose. -## DelegatedCertificate +#### DelegatedCertificate ```ts interface DelegatedCertificate { @@ -171,7 +175,7 @@ interface DelegatedCertificate { See [CIP-36](https://cips.cardano.org/cips/cip36/) for an explanation of these fields. Note: this object is not in exactly the same format as CIP-36, but the information it contains is the same. -## SignedDelegationMetadata +#### SignedDelegationMetadata ```ts interface SignedDelegationMetadata { @@ -185,9 +189,9 @@ interface SignedDelegationMetadata { * signature: signature on the CIP-36 delegation certificate. * txHash: of the transaction that submitted the delegation. -## Error Types +### Error Types -### Extended APIError +#### Extended APIError ```ts type enum APIErrorCode { @@ -231,14 +235,14 @@ API Error Codes, which are continue to be valid for this API Extension. * InvalidVotePlanError - If the `votePlanId` is not a valid vote plan. * InvalidVoteOptionError - If the `index` is not a valid vote option. -#### APIError elements +##### APIError elements * code - The `APIErrorCode` which is being reported. * info - A Human readable description of the error. * votingPurpose - (*OPTIONAL*) - Only present if the error relates to a voting purpose, and will list all the voting purposes which are involved in the error. See the individual error code descriptions for more information. * rejectedVotes - (*OPTIONAL*) - In a voting transaction, there may be multiple votes being signed simultaneously. -### Extended TxSignError +#### Extended TxSignError ```ts type enum TxSignErrorCode { @@ -262,13 +266,13 @@ All TxSignErrors defined in [CIP-30](https://cips.cardano.org/cips/cip30/#txsign * UserDeclined - Raised when the user declined to sign the entire transaction, in the case of a vote submission, this would be returned if the user declined to sign ALL of the votes. * VoteRejected - On a vote transaction, where there may be multiple votes. If the user accepted some votes, but rejected others, then this error is raised, AND `rejectedVotes` is present in the Error instance. -## Governance Extension to CIP-30 +### Governance Extension to CIP-30 -### cardano.{walletName}.governance.apiVersion: String +#### cardano.{walletName}.governance.apiVersion: String The version number of the Governance Extension API that the wallet supports. -### cardano.{walletName}.governance.enable(purpose: VotingPurpose[]): Promise\ +#### cardano.{walletName}.governance.enable(purpose: VotingPurpose[]): Promise\ Errors: [`APIError`](#extended-apierror) @@ -292,14 +296,14 @@ permissions to be displayed to the user. Note: Currently only voting purpose 0 (Catalyst) is defined. The wallet should reject any other purpose requested. -### Returns +##### Returns Upon successful connection via [`cardano.{walletName}.governance.enable()`](#cardanowalletnamegovernanceenablepurpose-votingpurpose-promiseapi), a javascript object we will refer to as `API` (type) / `api` (instance) is returned to the dApp with the following methods. -## Governance API +### Governance API Except `signVotes`, no other method should require any user interaction as the user has already consented to the dApp reading information @@ -315,7 +319,7 @@ The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. -## api.signVotes(votes: Vote[], settings: string): Promise\[] +#### api.signVotes(votes: Vote[], settings: string): Promise\[] Errors: [`APIError`](#extended-apierror), [`TxSignError`](#extended-txsignerror) @@ -331,7 +335,7 @@ Errors: [`APIError`](#extended-apierror), [`TxSignError`](#extended-txsignerror) Vote transaction formats are defined by the [voting purposes](#voting-purpose), and are not documented in this CIP. -### List of known vote transaction formats +##### List of known vote transaction formats | `"purpose"` | `"ver"` | Vote Format | Specification | Example Settings String | | --- | --- | --- | --- | --- | @@ -345,20 +349,20 @@ If the `purpose` and `ver` of the vote transaction format as defined by the `set In all cases, where an error occurs, no signed votes are returned. -### Returns +##### Returns `Bytes[]` - An array of the hex-encoded strings of the fully encoded and signed vote transactions. The dApp will submit these votes on behalf of the wallet. -## api.getVotingCredentials(): Promise\ +#### api.getVotingCredentials(): Promise\ Should return the in use voting credentials of the wallet. -### Returns +##### Returns The [VotingCredentials](#votingcredentials) of the wallet, which contain it's voting key and associated staking credential used for [CIP-36](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0036) style governance. -## api.submitDelegation(delegation: Delegation): Promise\ +#### api.submitDelegation(delegation: Delegation): Promise\ Errors: [`APIError`](#extended-apierror), [`TxSendError`](https://cips.cardano.org/cips/cip30/#txsenderror), @@ -378,96 +382,52 @@ This should be a call that implicitly cbor encodes the `delegation` object and u This should trigger a request to the user of the wallet to approve the transaction. -### Returns +##### Returns The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registration delegation passed in the `delegation` parameter. -# Examples of Message Flows and Processes +### Examples of Message Flows and Processes -## Delegation Cert process +#### Delegation -1. **`Get Voting Key`** - dApp call the method [**api.getVotingKey**](#apigetvotingkey-promise-cborpublickey) to get the voting public key. +Recall from [CIP-36](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036) a registration is a self-delegation, allocating one's voting power to one's own voting key. -2. **`Collect Voting Keys`** - The dApp Collects the dRep keys to delegate voting power to from the Catalyst Voting Center backend, and the user selects the required delegation. +1. **Get Voting Key** - dApp calls the method `api.getVotingCredentials()` to return the connected wallet account's public `VotingKey`. -3. **`Submit delegation`** - Submit the metadata transaction to the chain using [**api.submitDelegation**](#apisubmitdelegationdelegation-delegation-promisesigneddelegationmetadata) which implicitly sign and/or can use the already existing [**api.submitTx**](https://cips.cardano.org/cips/cip30/#apisubmittxtxcbortransactionpromisehash32), available from [CIP-30](https://cips.cardano.org/cips/cip30/) +2. **Construct Delegation** - The dApp constructs `Delegation` using the Wallet's public `VotingKey`, `weight` of 1 and choice of `VotingPurpose`. -## Casting a vote +3. **Submit Delegation** - The dApp passes the `Delegation` object to the Wallet to build a metadata transaction and submit this to Cardano blockchain. Wallets are able employ the already existing [`api.submitTx()`](https://cips.cardano.org/cips/cip30/#apisubmittxtxcbortransactionpromisehash32), available from [CIP-30](https://cips.cardano.org/cips/cip30/). -1. The dApp collects the users voting choices for a particular voting proposal. -2. The dApp submits that choice through [api.signVotes](#apisignvotesvotes-vote-promisebytes) which confirms the votes with the user, and signs them. +#### Voting -## **Test Vectors** +TODO -### ***keys*** +### Test Vector -`payment verification key`: +See [test vector file](./test-vector.md). -```json -{ - "type": "PaymentVerificationKeyShelley_ed25519", - "description": "Payment Verification Key", - "cborHex": "58203bc3383b1b88a628e6fa55dbca446972d5b0cd71bcd8c133b2fa9cd3afbd1d48" -} - -``` +## Rationale -`payment secret key`: +To provide governance specific functionality to wallet's and expose such API to the dApps (i.e Voting Centers). -```json -{ - "type": "PaymentSigningKeyShelley_ed25519", - "description": "Payment Signing Key", - "cborHex": "5820b5c85fa8fb2d8cd4e4f624c206946652b6764e1af83034a79b32320ce3940dd9" -} -``` +This also addresses some short-comings of [CIP-30](https://cips.cardano.org/cips/cip30/); which signData can only be done by known an address; This signature is not relevant to a specific address, nor the dApp will know an address attached to the voting key. The voting key derivation is defined in [CIP-36](https://cips.cardano.org/cips/cip36/). -`staking verification key`: +Perhaps [CIP-30](https://cips.cardano.org/cips/cip30/) could be expanded to also know how to perform `signData` from a given public key from a specific derivation path; instead of doing so only by known address. -```json -{ - "type": "StakeVerificationKeyShelley_ed25519", - "description": "Stake Verification Key", - "cborHex": "5820b5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555" -} -``` +The other reason for this specification is to have a specific, but optional, namespace for governance specific wallet functionality. As such, wallet providers might choose not to implement this specification on top of [CIP-30](https://cips.cardano.org/cips/cip30/). -`staking secret key`: +## Path to Active -```json -{ - "type": "StakeSigningKeyShelley_ed25519", - "description": "Stake Signing Key", - "cborHex": "58202f669f45365099666940922d47b29563d2c9f885c88a077bfea17631a7579d65" -} -``` +### Acceptance Criteria -### ***Delegation Certificate*** +- [ ] The interface is implemented and supported by various wallet providers. +- [ ] The interface is used by DApps to interact with wallet providers. -`Delegation certificate sample`: +### Implementation Plan -```json -{ - "1":[["1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["b48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], - "2":"93bf1450ec2a3b18eebc7acfd311e695e12232efdf9ce4ac21e8b536dfacc70f", +- [x] Provide javascript package for Catalyst vote signing + - [wallet-wasm-js](https://www.npmjs.com/package/@catalyst-core/wallet-wasm-js) - "3":"e1160a9d8f375f8e72b4bdbfa4867ca341a5aa6f17fde654c1a7d3254e", - "4":5479467, - "5":0 -} -``` +## Copyright -`Delegation certificate after signature`: - -```json -{ - "61284":{ - "1":[["1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["b48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], - "2":"93bf1450ec2a3b18eebc7acfd311e695e12232efdf9ce4ac21e8b536dfacc70f", - "3":"e1160a9d8f375f8e72b4bdbfa4867ca341a5aa6f17fde654c1a7d3254e", - "4":5479467, - "5":0 - }, - "61285":"0x3c25da29d43e70fb331c93b1197863e0d0a2e1cf7048994c580b0fc974f16bbb18c389aee380a66c0e7b6141f1df77b5db132dc228dbae9167238d96d4c4a80a" -} -``` +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode \ No newline at end of file diff --git a/CIP-0062/test-vector.md b/CIP-0062/test-vector.md new file mode 100644 index 0000000000..8d2800a7ba --- /dev/null +++ b/CIP-0062/test-vector.md @@ -0,0 +1,97 @@ +# Test Vector for CIP-0062 + +## Delegation + +### Keys + +Payment **public** verification key Hex: +``` +3bc3383b1b88a628e6fa55dbca446972d5b0cd71bcd8c133b2fa9cd3afbd1d48 +``` + +Payment **private** signing key Hex: +``` +b5c85fa8fb2d8cd4e4f624c206946652b6764e1af83034a79b32320ce3940dd9 +``` + +Staking **public** verification key Hex: +``` +b5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555 +``` + +Staking **private** signing key: +``` +2f669f45365099666940922d47b29563d2c9f885c88a077bfea17631a7579d65 +``` + +### Addresses + +* Addresses for Pre-Production testnet (testnet-magic 1). + +#### Payment Address +``` +bech32: "addr_test1qp7n0mudgm6gkyaf6q883nqw7ls73a89mt8exk4gkk44gaeez0pen8lxnyz4nejgal24e7zegkk53p3h6twnafy5ra2qpy52u6" + +hex-encoded: "007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54" +``` + +### Delegation Certificate Example + +* In this example voting power is delegated to two voting keys with varying weights; assigning key 1 25% voting power and key 2 75% voting power. +* For Project Catalyst, so using voting purpose 0. +* Transaction submitted to Pre-Production testnet. + +#### Delegation Certificate + +``` +{ + "1":[["0x1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["0xb48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], + "2":"0xb5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555", + "3":"0x007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54", + "4":5479467, + "5":0 +} +``` + +#### Delegation Certificate with Signature + +``` +{ + "61284":{ + "1":[["0x1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["0xb48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], + "2":"0xb5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555", + "3":"0x007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54", + "4":5479467, + "5":0 + }, + "61285": { + "1":"0xafb9e76a6ba5e391fc11bb233d77b54bb6a1222d9a52cf420143445d3397861917d5dc6f106d5969a45fe2067109fc12697596cf5c1c2d006993ea5cbcc35307" + } +} +``` + +#### Transaction with Delegation Certificate as Metadata Hex + +``` +84a40081825820117ca91fc909a8d8741fe93b732f4d1433eb6c645e564249217f2c357be8abbe000181a2005839007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54011a05f312d7021a0002ce290758202ff4fc9e1fe0e8d5a0154b6d9c5ca5e281416f5c54fd8b32b0653b2c9fac93a0a100818258203bc3383b1b88a628e6fa55dbca446972d5b0cd71bcd8c133b2fa9cd3afbd1d4858401092539f644df9b8cce12c8c7bff1d2a570b83d3e75e1659ccd349bb6599afe415a1726621626d6b6afd1fd68591c73474a69baa897070c1483c91631222840bf5d90103a100a219ef64a501828258201788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed301825820b48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa03025820b5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555035839007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54041a00539c2b050019ef65a1015840afb9e76a6ba5e391fc11bb233d77b54bb6a1222d9a52cf420143445d3397861917d5dc6f106d5969a45fe2067109fc12697596cf5c1c2d006993ea5cbcc35307 +``` + +#### On-Chain View + +``` +Transaction Hash: "1439e90955c2b5d87bc07149840981b5257e4a7f60a584e57f954f7229f67397" + +Block: "308719" + +Epoch / Slot: "34 / 397143" + +Absolute Slot: "13443543" +``` + +## Voting + +* Each project utilizing this standard should provide their own set of test vectors for voting + +### Catalyst Version 0 + +TODO \ No newline at end of file From 9a07508b6f2b11599725096bdc0fa538dfb5d481 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 20 Jan 2023 16:05:30 +0000 Subject: [PATCH 27/30] Fixed Copyright link --- CIP-0062/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 9254848d9a..d9ecbc9c41 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -430,4 +430,4 @@ The other reason for this specification is to have a specific, but optional, nam ## Copyright -[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode \ No newline at end of file +This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode) \ No newline at end of file From 04edd0c1f45726d9f91b149291c6ede007d45b18 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 27 Jan 2023 19:13:47 +0000 Subject: [PATCH 28/30] Addressed weekly meetings comments --- CIP-0062/README.md | 108 +++++++++++++++++----------------------- CIP-0062/test-vector.md | 97 ------------------------------------ 2 files changed, 45 insertions(+), 160 deletions(-) delete mode 100644 CIP-0062/test-vector.md diff --git a/CIP-0062/README.md b/CIP-0062/README.md index d9ecbc9c41..8982733e29 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -6,6 +6,7 @@ Category: Wallets Authors: - Bruno Martins - Steven Johnson + - Ryan Williams Implementors: - Begin - Eternl @@ -24,14 +25,14 @@ License: CC-BY-4.0 ## Abstract -This document describe the interface between webpage / web-based stack and cardano wallets. This specifies that API of the javascript object that need to be injected into the web applications in order to support all the Governance features. +This document describes an interface between webpage/web-based stacks and Cardano wallets. This specification defines the API of the javascript object that needs to be injected into web applications in order to support [CIP-36](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036) style governance functionality. -These definitions extend [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/) to provide specific support for vote delegation. +These definitions extend [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030). ## Motivation The goal for this CIP is to extend the dApp-Wallet web bridge to enable the construction of transactions containing metadata that conforms to -[CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://cips.cardano.org/cips/cip36/), +[CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036), enabling new functionality including vote delegation to either private or public representatives (dReps), splitting or combining of private votes, the use of different voting keys or delegations @@ -41,7 +42,7 @@ for different purposes (Catalyst etc). ### Version -The API Extension specified in this document will count as version 0.2.0 for version-checking purposes below. +The API Extension specified in this document will count as version `0.2.0` for version-checking purposes below. ### Data Types @@ -49,16 +50,16 @@ The API Extension specified in this document will count as version 0.2.0 for ver A hex string representing a 32 byte Ed25519 public key. -#### GovernanceKey +#### WeightedKey ```ts -type GovernanceKey = { - votingKey: PublicKey +type WeightedKey = { + voteKey: PublicKey weight: number } ``` -* `votingKey` - A voting `PublicKey` used to represent the target of the delegation. +* `voteKey` - A vote `PublicKey` used to represent the target of the delegation. * `weight` - Used to calculate the actual voting power using the rules described in [CIP-36](https://cips.cardano.org/cips/cip36/). @@ -74,9 +75,9 @@ type enum VotingPurpose = { to limit the scope of the governance functions. For example, a voting purpose might be a subset of Catalyst proposals, a council election, or even some private purpose (agreed by convention). Currently, only voting purpose 0 (Zero) -is defined, and it is for Catalyst events. +is defined, and it is for Catalyst events. As described in [CIP-36](https://cips.cardano.org/cips/cip36/). -**IMPORTANT**: The List of purposes in this CIP should be considered the +**IMPORTANT**: The list of purposes in this CIP should be considered the authoritative list of known purposes, subject to future amendment. Other voting purposes will be defined as required, by either an update to this CIP or a future CIP listing currently allocated Voting Purposes. @@ -84,44 +85,38 @@ future CIP listing currently allocated Voting Purposes. #### VotingCredentials ```ts interface VotingCredentials { - votingKey: PublicKey + voteKey: PublicKey stakingCredential: PublicKey } ``` Information used to represent a wallet's voting credentials. -* votingKey - Derivation as described within [CIP-0036](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036), wallets should use `address_index`= 0. +* voteKey - Derivation as described within [CIP-0036](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036), wallets should use `address_index` = 0. * stakingCredential - At the moment, the only supported staking credential is a public staking key. This is used to represent the wallet's staked ADA. -#### BlockDate - -```ts -interface BlockDate { - epoch: number - slot: number -} -``` - -* epoch - an epoch value on the voting block chain. -* slot - a block slot number on the voting block chain. - #### Proposal ```ts interface Proposal { - votePlanId: string; - proposalIndex: number; - voteOptions?: number[]; - voteEncKey?: string; -} + votePublic: boolean // false + votePlanId: string + proposalIndex: number + voteOptions: number + voteEncKey: string + }|{ + votePublic: boolean // true + votePlanId: string + proposalIndex: number + } ``` Proposal information. -* votePlanId - Hex encoded string to represent vote plan unique identifier. This will be the same as anchored on voting chain, and is managed by the dApp. -* proposalIndex - The index of the proposal within the vote plan. -* voteOptions - *Optional*. Total number of vote options. Only present in a private/encrypted vote. -* voteEncKey - *Optional*. If this vote is Private, this field is present and contains the key used to encrypt the vote. When the vote is public, this key is absent from the proposal. +* votePublic - Boolean flag for if this `Proposal` should be included in a public or private vote. Additional fields are required in the `Proposal` for private votes (`votePublic = false`). IF the incorrect fields are provided based on `votePublic` then a `InvalidProposalError` should be thrown. +* votePlanId - Hex encoded string to represent vote plan unique identifier. This will be the same as anchored on voting blockchain, and is managed by the dApp. This is present in both public and private settings. +* proposalIndex - The index of the `Proposal` within the vote plan. This is present in both public and private settings. +* voteOptions - Total number of vote options. Only present in a private/encrypted vote. +* voteEncKey - This field contains the election public key used to encrypt every private vote, this is part of an [ElGamal encryption scheme](https://en.wikipedia.org/wiki/ElGamal_encryption). Further information can be seen in [Jormungandr Voting](https://input-output-hk.github.io/jormungandr/jcli/vote.html). When the vote is public, this field is absent from the `Proposal`. #### Vote @@ -129,43 +124,35 @@ Proposal information. interface Vote { proposal: Proposal; choice: number; - expiration: BlockDate; purpose: VotingPurpose; - spendingCounter?: number; - spendingCounterLane?: number; } ``` An individual raw Unsigned Vote record. -* proposal - The [proposal](#proposal) being voted on. +* proposal - The [Proposal](#proposal) being voted on. * choice - This value MUST match one of the available `voteOptions` in the `proposal` element. An `UnknownChoiceError` should be thrown if the value is not one of the valid `voteOptions` of the `proposal`. -* expiration - Voting Chain epoch \& slot for when the vote will expire. This value is supplied and maintained by the dApp, and forms a necessary component of a [Vote](#vote) * purpose - The [voting purpose](#voting-purpose) being voted on. (Currently always 0). -* spendingCounter - Optional, but if present, the spending counter is used to prevent double voting. The spending counter for the vote transaction will be supplied and maintained by the dApp. The dApp will manage supplying this in the correct order, and this should not be enforced by the Wallet. -* spendingCounterLane - Optional, if not present but required defaults to 0. The spending counter may be spread across multiple lanes, this field defines which lane the spending counter relates to. - -Note: `spendingCounter` and `spendingCounterLane` are fully managed by the voting dApp and if present are used to create the vote fragment for proper submission to the voting system. The wallet should simply use the values defined, and does not need to track them. #### Delegation ```ts interface Delegation { - delegations: GovernanceKey[] - purpose: VotingPurpose + delegations: WeightedKey[] + purpose: VotingPurpose } ``` The record of a voters delegation. -* delegations - List of [Governance Keys](#governancekey) and their voting weight to delegate voting power to. -* purpose - The [Voting Purpose](#voting-purpose) being delegated. A voter may have multiple active delegations for different purposes, but only 1 active delegation per unique Voting Purpose. +* delegations - List of [Weighted Keys](#WeightedKey) denoting the `voteKey` and `weight` of each delegation. +* purpose - The associated [Voting Purpose](#voting-purpose). A voter may have multiple active delegations for different purposes, but only once active delegation per unique `Voting Purpose`. #### DelegatedCertificate ```ts interface DelegatedCertificate { - delegations: GovernanceKey[] + delegations: WeightedKey[] stakingPub: string paymentAddress: string nonce: number @@ -198,7 +185,7 @@ type enum APIErrorCode { UnsupportedVotingPurpose = -100 InvalidArgumentError = -101 UnknownChoiceError = -102 - InvalidBlockDateError = -103 + InvalidProposalError = -103 InvalidVotePlanError = -104 InvalidVoteOptionError = -105 } @@ -211,13 +198,12 @@ interface APIError { ``` These are the extended API Error Codes used by this specification. See -[CIP-30 Errors](https://cips.cardano.org/cips/cip30/#apierror) for the standard +[CIP-30 Errors](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apierror) for the standard API Error Codes, which are continue to be valid for this API Extension. -* UnsupportedVotingPurpose - The wallet does not support one of the requested - voting purposes. The `votingPurpose` element will be present in the `APIError` object and will list all the voting purposes requested, which are unsupported bgy the wallet. Eg: +* UnsupportedVotingPurpose - The wallet does not support one of the requested voting purposes. The `votingPurpose` element will be present in the `APIError` object and will list all the voting purposes requested, which are unsupported bgy the wallet. Eg: - If Voting purposes 0,5 and 9 were requested, and only 0 was supported by the + If voting purposes 0,5 and 9 were requested, and only 0 was supported by the wallet. Then the errors will be: ```js @@ -231,7 +217,7 @@ API Error Codes, which are continue to be valid for this API Extension. * InvalidArgumentError - Generic error for errors in the formatting of the arguments. * UnknownChoiceError - If a `choice` is not within the [`proposal`](#proposal) option set. -* InvalidBlockDateError - If a [block date](#blockdate) is invalid. +* InvalidProposalError - If the incorrect fields are provided based on if a `Proposal` is meant to be public or private. * InvalidVotePlanError - If the `votePlanId` is not a valid vote plan. * InvalidVoteOptionError - If the `index` is not a valid vote option. @@ -284,7 +270,7 @@ should maintain a specific whitelist of allowed clients and voting purposes for this API. This whitelist can be used to avoid asking for permission every time. This api, being an extension of -[CIP-30 (Cardano dApp-Wallet Web Bridge)](https://cips.cardano.org/cips/cip30/), +[CIP-30](https://cips.cardano.org/cips/cip30/), expects that `cardano.{walletName}.enable()` to be enabled and added to CIP-30 whitelist implicitly. @@ -368,7 +354,7 @@ Errors: [`APIError`](#extended-apierror), [`TxSendError`](https://cips.cardano.org/cips/cip30/#txsenderror), [`TxSignError`](https://cips.cardano.org/cips/cip30/#txsignerror) -This endpoint should construct the cbor encoded delegation certificate according to the specs in [CIP-36 Example](https://github.com/Zeegomo/CIPs/blob/472181b9c69feeedae0b5b2db8b42d0cf4eb1a11/CIP-0036/README.md#example). +This endpoint should construct the cbor encoded delegation certificate according to the specs in [CIP-36 example](https://github.com/Zeegomo/CIPs/blob/472181b9c69feeedae0b5b2db8b42d0cf4eb1a11/CIP-0036/README.md#example). It should then sign the certificate with the staking key as described in the same example as above. @@ -392,9 +378,9 @@ The [Signed Delegation Metadata](#signeddelegationmetadata) of the voter registr Recall from [CIP-36](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036) a registration is a self-delegation, allocating one's voting power to one's own voting key. -1. **Get Voting Key** - dApp calls the method `api.getVotingCredentials()` to return the connected wallet account's public `VotingKey`. +1. **Get Voting Key** - dApp calls the method `api.getVotingCredentials()` to return the connected wallet account's public `voteKey`. -2. **Construct Delegation** - The dApp constructs `Delegation` using the Wallet's public `VotingKey`, `weight` of 1 and choice of `VotingPurpose`. +2. **Construct Delegation** - The dApp constructs `Delegation` using the Wallet's public `voteKey`, `weight` of 1 and choice of `VotingPurpose`. 3. **Submit Delegation** - The dApp passes the `Delegation` object to the Wallet to build a metadata transaction and submit this to Cardano blockchain. Wallets are able employ the already existing [`api.submitTx()`](https://cips.cardano.org/cips/cip30/#apisubmittxtxcbortransactionpromisehash32), available from [CIP-30](https://cips.cardano.org/cips/cip30/). @@ -402,13 +388,9 @@ Recall from [CIP-36](https://github.com/cardano-foundation/CIPs/tree/master/CIP- TODO -### Test Vector - -See [test vector file](./test-vector.md). - ## Rationale -To provide governance specific functionality to wallet's and expose such API to the dApps (i.e Voting Centers). +To provide [CIP-36](https://cips.cardano.org/cips/cip36/) style governance specific functionality to wallet's and expose such API to the dApps (i.e Voting Centers). This also addresses some short-comings of [CIP-30](https://cips.cardano.org/cips/cip30/); which signData can only be done by known an address; This signature is not relevant to a specific address, nor the dApp will know an address attached to the voting key. The voting key derivation is defined in [CIP-36](https://cips.cardano.org/cips/cip36/). @@ -430,4 +412,4 @@ The other reason for this specification is to have a specific, but optional, nam ## Copyright -This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode) \ No newline at end of file +This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). \ No newline at end of file diff --git a/CIP-0062/test-vector.md b/CIP-0062/test-vector.md deleted file mode 100644 index 8d2800a7ba..0000000000 --- a/CIP-0062/test-vector.md +++ /dev/null @@ -1,97 +0,0 @@ -# Test Vector for CIP-0062 - -## Delegation - -### Keys - -Payment **public** verification key Hex: -``` -3bc3383b1b88a628e6fa55dbca446972d5b0cd71bcd8c133b2fa9cd3afbd1d48 -``` - -Payment **private** signing key Hex: -``` -b5c85fa8fb2d8cd4e4f624c206946652b6764e1af83034a79b32320ce3940dd9 -``` - -Staking **public** verification key Hex: -``` -b5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555 -``` - -Staking **private** signing key: -``` -2f669f45365099666940922d47b29563d2c9f885c88a077bfea17631a7579d65 -``` - -### Addresses - -* Addresses for Pre-Production testnet (testnet-magic 1). - -#### Payment Address -``` -bech32: "addr_test1qp7n0mudgm6gkyaf6q883nqw7ls73a89mt8exk4gkk44gaeez0pen8lxnyz4nejgal24e7zegkk53p3h6twnafy5ra2qpy52u6" - -hex-encoded: "007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54" -``` - -### Delegation Certificate Example - -* In this example voting power is delegated to two voting keys with varying weights; assigning key 1 25% voting power and key 2 75% voting power. -* For Project Catalyst, so using voting purpose 0. -* Transaction submitted to Pre-Production testnet. - -#### Delegation Certificate - -``` -{ - "1":[["0x1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["0xb48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], - "2":"0xb5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555", - "3":"0x007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54", - "4":5479467, - "5":0 -} -``` - -#### Delegation Certificate with Signature - -``` -{ - "61284":{ - "1":[["0x1788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed3",1],["0xb48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa",3]], - "2":"0xb5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555", - "3":"0x007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54", - "4":5479467, - "5":0 - }, - "61285": { - "1":"0xafb9e76a6ba5e391fc11bb233d77b54bb6a1222d9a52cf420143445d3397861917d5dc6f106d5969a45fe2067109fc12697596cf5c1c2d006993ea5cbcc35307" - } -} -``` - -#### Transaction with Delegation Certificate as Metadata Hex - -``` -84a40081825820117ca91fc909a8d8741fe93b732f4d1433eb6c645e564249217f2c357be8abbe000181a2005839007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54011a05f312d7021a0002ce290758202ff4fc9e1fe0e8d5a0154b6d9c5ca5e281416f5c54fd8b32b0653b2c9fac93a0a100818258203bc3383b1b88a628e6fa55dbca446972d5b0cd71bcd8c133b2fa9cd3afbd1d4858401092539f644df9b8cce12c8c7bff1d2a570b83d3e75e1659ccd349bb6599afe415a1726621626d6b6afd1fd68591c73474a69baa897070c1483c91631222840bf5d90103a100a219ef64a501828258201788b78997774daae45ae42ce01cf59aec6ae2acee7f7cf5f76abfdd505ebed301825820b48b946052e07a95d5a85443c821bd68a4eed40931b66bd30f9456af8c092dfa03025820b5462be6a8a8ec0c4d6ee6edb83794a03df1bca43edc72b380df2ad3a982a555035839007d37ef8d46f48b13a9d00e78cc0ef7e1e8f4e5dacf935aa8b5ab54773913c3999fe6990559e648efd55cf85945ad488637d2dd3ea4941f54041a00539c2b050019ef65a1015840afb9e76a6ba5e391fc11bb233d77b54bb6a1222d9a52cf420143445d3397861917d5dc6f106d5969a45fe2067109fc12697596cf5c1c2d006993ea5cbcc35307 -``` - -#### On-Chain View - -``` -Transaction Hash: "1439e90955c2b5d87bc07149840981b5257e4a7f60a584e57f954f7229f67397" - -Block: "308719" - -Epoch / Slot: "34 / 397143" - -Absolute Slot: "13443543" -``` - -## Voting - -* Each project utilizing this standard should provide their own set of test vectors for voting - -### Catalyst Version 0 - -TODO \ No newline at end of file From 46d6c98614a3c52b6d1f318e25fee09b1ec97c33 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 17 Feb 2023 20:34:58 +0000 Subject: [PATCH 29/30] Rescope to Catalyst --- CIP-0062/README.md | 60 +++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 8982733e29..862a567c8f 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -1,6 +1,6 @@ --- CIP: 62 -Title: Cardano dApp-Connector Governance extension +Title: Cardano dApp-Connector Project Catalyst Extension Status: Proposed Category: Wallets Authors: @@ -21,28 +21,22 @@ Created: 2021-06-11 License: CC-BY-4.0 --- -# CIP-0062: Cardano dApp-Connector Governance extension +# CIP-0062: Cardano dApp-Connector Project Catalyst Extension ## Abstract -This document describes an interface between webpage/web-based stacks and Cardano wallets. This specification defines the API of the javascript object that needs to be injected into web applications in order to support [CIP-36](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036) style governance functionality. +This document describes an interface between webpage/web-based stacks and Cardano wallets. This specification defines the API of the javascript object that needs to be injected into web applications in order to support Cardano's [Project Catalyst](https://projectcatalyst.io/). -These definitions extend [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030). +These definitions extend the [CIP-30 (Cardano dApp-Wallet Web Bridge)](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030) to provide specific support for Catalyst vote delegation and vote signing. ## Motivation + -The goal for this CIP is to extend the dApp-Wallet web bridge to enable the construction of transactions containing metadata that conforms to -[CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036), -enabling new functionality including vote delegation to either private or public representatives (dReps), -splitting or combining of private votes, -the use of different voting keys or delegations -for different purposes (Catalyst etc). +The goal for this CIP is to extend the [CIP-30](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030) dApp-Wallet web bridge to enable the creation of Project Catalyst focussed dApps. Where wallets can connect, share the user's key information, register to vote and or delegate voting rights. -## Specification - -### Version +This is achieved by facilitating the construction of transactions containing metadata aligned with [CIP-36 (Catalyst/Voltaire Registration Transaction Metadata Format - Updated)](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0036). This enables new functionality for Project Catalyst; including vote delegation to either private or public representatives (dReps), splitting or combining of votes, the use of different voting keys or delegations for different purposes. -The API Extension specified in this document will count as version `0.2.0` for version-checking purposes below. +## Specification ### Data Types @@ -71,8 +65,8 @@ type enum VotingPurpose = { } ``` -`VotingPurpose`: Defines the voting purpose of the governance functions. This is used -to limit the scope of the governance functions. For example, a voting purpose +`VotingPurpose`: Defines the voting purpose of the Catalyst governance functions. This is used +to limit the scope of the Catalyst functions. For example, a voting purpose might be a subset of Catalyst proposals, a council election, or even some private purpose (agreed by convention). Currently, only voting purpose 0 (Zero) is defined, and it is for Catalyst events. As described in [CIP-36](https://cips.cardano.org/cips/cip36/). @@ -143,7 +137,7 @@ interface Delegation { } ``` -The record of a voters delegation. +The record of a voter's delegation. * delegations - List of [Weighted Keys](#WeightedKey) denoting the `voteKey` and `weight` of each delegation. * purpose - The associated [Voting Purpose](#voting-purpose). A voter may have multiple active delegations for different purposes, but only once active delegation per unique `Voting Purpose`. @@ -252,18 +246,18 @@ All TxSignErrors defined in [CIP-30](https://cips.cardano.org/cips/cip30/#txsign * UserDeclined - Raised when the user declined to sign the entire transaction, in the case of a vote submission, this would be returned if the user declined to sign ALL of the votes. * VoteRejected - On a vote transaction, where there may be multiple votes. If the user accepted some votes, but rejected others, then this error is raised, AND `rejectedVotes` is present in the Error instance. -### Governance Extension to CIP-30 +### Catalyst Extension to CIP-30 -#### cardano.{walletName}.governance.apiVersion: String +#### cardano.{walletName}.catalyst.apiVersion: String -The version number of the Governance Extension API that the wallet supports. +The version number of the Catalyst Extension API that the wallet supports. -#### cardano.{walletName}.governance.enable(purpose: VotingPurpose[]): Promise\ +#### cardano.{walletName}.catalyst.enable(purpose: VotingPurpose[]): Promise\ Errors: [`APIError`](#extended-apierror) -The `cardano.{walletName}.governance.enable()` method is used to enable the -governance API. It should request permission from the wallet to enable the API for the requested purposes. +The `cardano.{walletName}.catalyst.enable()` method is used to enable the +Catalyst API. It should request permission from the wallet to enable the API for the requested purposes. If permission is granted, the rest of the API will be available. The wallet should maintain a specific whitelist of allowed clients and voting purposes for @@ -285,16 +279,16 @@ permissions to be displayed to the user. ##### Returns Upon successful connection via -[`cardano.{walletName}.governance.enable()`](#cardanowalletnamegovernanceenablepurpose-votingpurpose-promiseapi), +[`cardano.{walletName}.catalyst.enable()`](#cardanowalletnamecatalystenablepurpose-votingpurpose-promiseapi), a javascript object we will refer to as `API` (type) / `api` (instance) is returned to the dApp with the following methods. -### Governance API +### Catalyst API Except `signVotes`, no other method should require any user interaction as the user has already consented to the dApp reading information -about the wallet's governance state when they agreed to -[`cardano.{walletName}.governance.enable()`](#cardanowalletnamegovernanceenablepurpose-votingpurpose-promiseapi). +about the wallet's state when they agreed to +[`cardano.{walletName}.catalyst.enable()`](#cardanowalletnamecatalystenablepurpose-votingpurpose-promiseapi). The remaining methods [`api.signVotes()`](#apisignvotesvotes-vote-promisebytes) and [`api.signData()`](#apisubmitdelegationdelegation-delegation-promisesigneddelegationmetadata) @@ -323,9 +317,9 @@ Errors: [`APIError`](#extended-apierror), [`TxSignError`](#extended-txsignerror) ##### List of known vote transaction formats -| `"purpose"` | `"ver"` | Vote Format | Specification | Example Settings String | -| --- | --- | --- | --- | --- | -| 0 | 0 | Project Catalyst vote: V0 | [Catalyst Core Specifications](https://input-output-hk.github.io/catalyst-core/) | `{"purpose":0,"ver":0,"fees":{"constant":10,"coefficient":2,"certificate":100},"discrimination":"production","block0_initial_hash":{"hash":"baf6b54817cf2a3e865f432c3922d28ac5be641e66662c66d445f141e409183e"},"block0_date":1586637936,"slot_duration":20,"time_era":{"epoch_start":0,"slot_start":0,"slots_per_epoch":180},"transaction_max_expiry_epochs":1}` | +| `"purpose"` | `"ver"` | Vote Format | Specification | Example Settings String | +| ----------- | ------- | ------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 0 | 0 | Project Catalyst vote: V0 | [Catalyst Core Specifications](https://input-output-hk.github.io/catalyst-core/) | `{"purpose":0,"ver":0,"fees":{"constant":10,"coefficient":2,"certificate":100},"discrimination":"production","block0_initial_hash":{"hash":"baf6b54817cf2a3e865f432c3922d28ac5be641e66662c66d445f141e409183e"},"block0_date":1586637936,"slot_duration":20,"time_era":{"epoch_start":0,"slot_start":0,"slots_per_epoch":180},"transaction_max_expiry_epochs":1}` | IF the wallet user declines SOME of the votes, a [`TxSignError`](#extended-txsignerror) should be raised with `code` set to `VoteRejected` and the optional `rejectedVotes` array specifying the votes rejected. @@ -346,7 +340,7 @@ Should return the in use voting credentials of the wallet. ##### Returns -The [VotingCredentials](#votingcredentials) of the wallet, which contain it's voting key and associated staking credential used for [CIP-36](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0036) style governance. +The [VotingCredentials](#votingcredentials) of the wallet, which contain it's voting key and associated staking credential used for [CIP-36](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0036). #### api.submitDelegation(delegation: Delegation): Promise\ @@ -390,13 +384,13 @@ TODO ## Rationale -To provide [CIP-36](https://cips.cardano.org/cips/cip36/) style governance specific functionality to wallet's and expose such API to the dApps (i.e Voting Centers). +To provide [CIP-36](https://cips.cardano.org/cips/cip36/) style governance specific functionality for Catalyst to wallet's and expose such API to the dApps (i.e Catalyst Voting Centers). This also addresses some short-comings of [CIP-30](https://cips.cardano.org/cips/cip30/); which signData can only be done by known an address; This signature is not relevant to a specific address, nor the dApp will know an address attached to the voting key. The voting key derivation is defined in [CIP-36](https://cips.cardano.org/cips/cip36/). Perhaps [CIP-30](https://cips.cardano.org/cips/cip30/) could be expanded to also know how to perform `signData` from a given public key from a specific derivation path; instead of doing so only by known address. -The other reason for this specification is to have a specific, but optional, namespace for governance specific wallet functionality. As such, wallet providers might choose not to implement this specification on top of [CIP-30](https://cips.cardano.org/cips/cip30/). +The other reason for this specification is to have a specific, but optional, namespace for Catalyst specific wallet functionality. As such, wallet providers might choose not to implement this specification on top of [CIP-30](https://cips.cardano.org/cips/cip30/). ## Path to Active From a00b591c07b7bd27c7254a9a4ce25d46c3dda44e Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Tue, 7 Mar 2023 18:48:47 +0000 Subject: [PATCH 30/30] Changed title to match CIP-30's naming --- CIP-0062/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CIP-0062/README.md b/CIP-0062/README.md index 862a567c8f..7fe4cef3ea 100644 --- a/CIP-0062/README.md +++ b/CIP-0062/README.md @@ -1,6 +1,6 @@ --- CIP: 62 -Title: Cardano dApp-Connector Project Catalyst Extension +Title: Cardano dApp-Wallet Web Bridge Catalyst Extension Status: Proposed Category: Wallets Authors: @@ -21,7 +21,7 @@ Created: 2021-06-11 License: CC-BY-4.0 --- -# CIP-0062: Cardano dApp-Connector Project Catalyst Extension +# CIP-0062: Cardano dApp-Wallet Web Bridge Catalyst Extension ## Abstract