Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cardano): add support for CIP-36 Catalyst registration format #6735

Merged
merged 6 commits into from
Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/packages/connect/methods/cardanoGetAddress.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const result = await TrezorConnect.cardanoGetAddress(params);

- `addressParameters` — _required_ see description below
- `address` — _optional_ `string` address for validation (read `Handle button request` section below)
- `protocolMagic` - _required_ `Integer` 764824073 for Mainnet, 1097911063 for Testnet
- `protocolMagic` - _required_ `Integer` 764824073 for Mainnet, 1 for Preprod Testnet, 2 for Preview Testnet
- `networkId` - _required_ `Integer` 1 for Mainnet, 0 for Testnet
- `showOnTrezor` — _optional_ `boolean` determines if address will be displayed on device. Default is set to `true`
- `derivationType` — _optional_ `CardanoDerivationType` enum. determines used derivation type. Default is set to ICARUS_TREZOR=2
Expand Down Expand Up @@ -242,7 +242,7 @@ TrezorConnect.cardanoGetAddress({
addressType: 8,
path: "m/44'/1815'/1'/0/2",
},
protocolMagic: 1097911063,
protocolMagic: 1,
networkId: 0,
showOnTrezor: false,
},
Expand Down
27 changes: 19 additions & 8 deletions docs/packages/connect/methods/cardanoSignTransaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const result = await TrezorConnect.cardanoSignTransaction(params);
- `inputs` - _required_ `Array` of [CardanoInput](https://github.com/trezor/trezor-suite/blob/develop/packages/connect/src/types/api/cardano/index.ts)
- `outputs` - _required_ `Array` of [CardanoOutput](https://github.com/trezor/trezor-suite/blob/develop/packages/connect/src/types/api/cardano/index.ts)
- `fee` - _required_ `String`
- `protocolMagic` - _required_ `Integer` 764824073 for Mainnet, 1097911063 for Testnet
- `protocolMagic` - _required_ `Integer` 764824073 for Mainnet, 1 for Preprod Testnet, 2 for Preview Testnet
- `networkId` - _required_ `Integer` 1 for Mainnet, 0 for Testnet
- `ttl` - _optional_ `String`
- `validityIntervalStart` - _optional_ `String`
Expand Down Expand Up @@ -46,7 +46,7 @@ The transaction

- _should_ have valid `path` property on all `inputs`
- _must not_ contain a pool registration certificate
- _must not_ contain `collateralInputs` and `requiredSigners`
- _must not_ contain `collateralInputs`, `collateralReturn`, `totalCollateral` and `referenceInputs`
- _must_ contain paths as stake credentials in certificates and withdrawals (no key hashes or script hashes)
- _may_ contain only 1852 and 1855 paths
- _must not_ contain 1855 witness requests when transaction is not minting/burning tokens
Expand All @@ -62,7 +62,7 @@ The transaction
- _must_ have single owner given by path on that certificate
- _must not_ contain withdrawals
- _must not_ contain token minting
- _must not_ contain `collateralInputs` and `requiredSigners`
- _must not_ contain `collateralInputs`, `requiredSigners`, `collateralReturn`, `totalCollateral` and `referenceInputs`
- _must_ contain only staking witness requests

These restrictions are in place due to a possibility of maliciously signing _another_ part of the transaction with the pool owner path as we are not displaying device-owned paths on the device screen.
Expand All @@ -76,7 +76,7 @@ The transaction
- _must_ have `path` undefined on all `inputs`
- _must not_ contain output addresses given by parameters
- _must not_ contain a pool registration certificate
- _must not_ contain `collateralInputs` and `requiredSigners`
- _must not_ contain `collateralInputs`, `collateralReturn`, `totalCollateral` and `referenceInputs`
- _must_ contain script hash stake credentials in certificates and withdrawals (no paths or key hashes)
- _may_ contain only 1854 and 1855 witness requests
- _must not_ contain 1855 witness requests when transaction is not minting/burning tokens
Expand All @@ -92,6 +92,8 @@ The transaction
- _may_ contain only 1852, 1854 and 1855 required signers
- _may_ contain only 1852, 1854 and 1855 witness requests

Note: `requiredSigners` are meant for Plutus transactions (from the blockchain point of view), but some applications utilize them for their own purposes, so we allow them in all signing modes (except for pool registration as owner).

### Stake pool registration certificate specifics

Trezor supports signing of stake pool registration certificates as a pool owner. The transaction may contain external inputs (e.g. belonging to the pool operator) and Trezor is not able to verify whether they are actually external or not, so if we allowed signing the transaction with a spending key, there is the risk of losing funds from an input that the user did not intend to spend from. Moreover there is the risk of inadvertedly signing a withdrawal in the transaction if there's any. To mitigate those risks, we introduced special validation rules for stake pool registration transactions which are validated on Trezor as well. The validation rules are the following:
Expand All @@ -101,7 +103,16 @@ Trezor supports signing of stake pool registration certificates as a pool owner.
1. The transaction inputs must all be external, i.e. path must be either undefined or null
1. Exactly one owner should be passed as a staking path and the rest of owners should be passed as bech32-encoded reward addresses

### Example
### Governance registration (Catalyst and other)

Trezor supports signing transactions with auxiliary data containing a governance registration. Governance registrations used to follow [CIP-15](https://cips.cardano.org/cips/cip15/), which has been superseded by [CIP-36](https://cips.cardano.org/cips/cip36/). Currently, Trezor supports both CIP-15 and CIP-36 formats, the intended standard can be specified in the `format` field (with CIP-15 being the default). They differ in the following:

- CIP-36 allows delegating the voting power to several voting public keys with different voting power ([CardanoGovernanceRegistrationDelegation](https://github.com/trezor/trezor-suite/blob/develop/packages/connect/src/types/api/cardano/index.ts)) as an alternative to providing only a single voting public key. Note that Trezor Firmware supports at most 32 delegations in a single governance registration.
- CIP-36 registrations contain the [votingPurpose](https://github.com/trezor/trezor-suite/blob/develop/packages/connect/src/types/api/cardano/index.ts) field. The value 0 is intended for Catalyst voting and the value 1 is intended for other purposes. If no value is provided, Trezor serializes 0 by default (if the CIP-36 format is used).

Trezor does not support the 1694 derivation paths at the moment.

### Transaction examples

#### Ordinary transaction

Expand Down Expand Up @@ -275,7 +286,7 @@ TrezorConnect.cardanoSignTransaction({
});
```

#### Catalyst voting key registration
#### Governance voting key registration

```javascript
TrezorConnect.cardanoSignTransaction({
Expand All @@ -297,7 +308,7 @@ TrezorConnect.cardanoSignTransaction({
fee: '42',
ttl: '10',
auxiliaryData: {
catalystRegistrationParameters: {
governanceRegistrationParameters: {
votingPublicKey: '1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc',
stakingPath: "m/1852'/1815'/0'/2/0",
rewardAddressParameters: {
Expand Down Expand Up @@ -568,7 +579,7 @@ Example:
type: 1,
auxiliaryDataHash:
'a943e9166f1bb6d767b175384d3bd7d23645170df36fc1861fbf344135d8e120',
catalystSignature:
governanceSignature:
'74f27d877bbb4a5fc4f7c56869905c11f70bad0af3de24b23afaa1d024e750930f434ecc4b73e5d1723c2cb8548e8bf6098ac876487b3a6ed0891cb76994d409',
},
}
Expand Down
22 changes: 11 additions & 11 deletions packages/connect/e2e/__fixtures__/cardanoGetAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export default {
path: "m/1852'/1815'/4'/0/0",
stakingPath: "m/1852'/1815'/4'/2/0",
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -193,7 +193,7 @@ export default {
path: "m/1852'/1815'/4'/0/0",
stakingKeyHash: '1bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff',
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -232,7 +232,7 @@ export default {
paymentScriptHash: '0d5acbf6a1dfb0c8724e60df314987315ccbf78bb6c0f9b6f3d568fe',
stakingPath: "m/1852'/1815'/0'/2/0",
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -276,7 +276,7 @@ export default {
path: "m/1852'/1815'/0'/0/0",
stakingScriptHash: '8d7bebc7a58f1c7b5fb7c9391071ecd3b51b032695522f8c555343a9',
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -320,7 +320,7 @@ export default {
paymentScriptHash: '0d5acbf6a1dfb0c8724e60df314987315ccbf78bb6c0f9b6f3d568fe',
stakingScriptHash: '8d7bebc7a58f1c7b5fb7c9391071ecd3b51b032695522f8c555343a9',
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -356,7 +356,7 @@ export default {
addressType: CardanoAddressType.ENTERPRISE,
path: "m/1852'/1815'/0'/0/0",
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -391,7 +391,7 @@ export default {
addressType: CardanoAddressType.ENTERPRISE_SCRIPT,
paymentScriptHash: '0d5acbf6a1dfb0c8724e60df314987315ccbf78bb6c0f9b6f3d568fe',
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -436,7 +436,7 @@ export default {
certificateIndex: 42,
},
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -481,7 +481,7 @@ export default {
certificateIndex: 42,
},
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -516,7 +516,7 @@ export default {
addressType: CardanoAddressType.REWARD,
stakingPath: "m/1852'/1815'/0'/2/0",
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down Expand Up @@ -551,7 +551,7 @@ export default {
addressType: CardanoAddressType.REWARD_SCRIPT,
stakingScriptHash: '8d7bebc7a58f1c7b5fb7c9391071ecd3b51b032695522f8c555343a9',
},
protocolMagic: PROTOCOL_MAGICS.testnet,
protocolMagic: PROTOCOL_MAGICS.testnet_preprod,
networkId: NETWORK_IDS.testnet,
},
result: {
Expand Down
Loading