From a6db2a5d44be5b5f08061bdff1473ba64ed81072 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Mon, 21 Oct 2024 10:23:53 +0100 Subject: [PATCH 01/25] Initial draft at wallet connector CPS --- CPS-XXXX/README.md | 116 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 CPS-XXXX/README.md diff --git a/CPS-XXXX/README.md b/CPS-XXXX/README.md new file mode 100644 index 0000000000..98685c84c5 --- /dev/null +++ b/CPS-XXXX/README.md @@ -0,0 +1,116 @@ +--- +CPS: ? +Title: Full-data wallet connector +Status: Open +Category: Tools +Authors: + - Giovanni Garufi +Proposed Solutions: [] +Discussions: + - https://github.com/cardano-foundation/cips/pulls/? +Created: YYYY-MM-DD +--- + +## Abstract + + +CIP-30 is the standard interface of communication between wallets and DApps. While this CIP has been instrumental in the development of dApps for Cardano, it also has some shortcomings that have been observed across several implementations. + +We have identified three steps in the path to provide a better alternative to CIP-30: + +- Defining a universal JSON encoding for Cardano domain types. CIP-30 requires CBOR encoding and decoding for data passed to and from the wallet, which is often an extra burden for the client. This problem is stated in [CPS-0011](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0011) and it's corresponding [CIP-0116](link). + +- Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012] and it's corresponding [CIP-????](link). + +- Define an API for transaction building. This is the last step required to build a full-data wallet connector as specified in [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md#full-data-wallets). + +[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) defines the responsibilities for wallet connector, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. In this CPS we hope to explain the need and our design for a full-data wallet connector. + +## Problem + + +CIP-30 is a universally accepted web-based wallet standard for Cardano. It provides a minimalistic interface that, in principle, can be used to build almost any kind of Cardano dApp. However, the way dApp<->wallet interaction is defined leads to suboptimal dApp architecture due to CIP-30 limits. + + +Consider the following problems: + +### Use of CBOR representations + +CIP-30 standard uses CBOR encoding for all data passed from the wallet, e.g. addresses and UTxOs. Interpreting this data within the app requires CBOR decoding functionality that is tedious to implement manually, and so users resort to using cardano-serialization-lib or its close alternative, cardano-multiplatform-lib, which both require loading a WebAssembly blob of >1M in size. + +For comparison, to start a new Web3 app on Ethereum there is no need to use a library for data serialization. It’s possible to interact with a provider object that is given by the wallet directly, although there are libraries to further simplify this. Using CBOR looks unnecessary for most dApps, given that JSON is a de-facto standard for web data serialization. + +### Limited scope of available queries + +Most dApps require interacting with scripts, which implies the need to query for available UTxOs locked at script addresses and other blockchain data. CIP-30 is intentionally limited in scope to management of UTxOs "owned" by the wallet itself. + +Some other useful queries, like getting delegation and reward info, stake pool info, transaction metadata or contents, and epoch data, are also outside of scope. + +As a result, dApp developers are forced to implement their own query layers on the backend side - which leads to one more problem - inconsistency between states of two query layers: + +### Inconsistency of Query Layers + +On Cardano, every running node has its own opinion on the set of currently unspent transaction outputs. Only eventual consistency is guaranteed. + +Any dApp that interacts with a CIP-30 wallet has to deal with the inconsistency between the local cardano-node-based query layer and the light wallet query layer, especially when dApp workflow involves sending multiple transactions with the wallet in quick succession. + +Thus, the goal of the developers is to ensure that the set of UTxOs available to the wallet and the set of UTxOs the backend cardano-node knows about are synchronized enough to not cause errors when a wallet or backend operations are performed. To give a few examples of potential issues, consider the following scenarios: + +A dApp tries to balance a transaction with UTxOs from the wallet that is not yet available in dApp backend's cardano node, causing an error response during execution units evaluation +A transaction is passed for signing, but the wallet does not yet know about the UTxOs it spends, and thus refuses to sign it +A transaction is sent to the network via the dApp backend (bypassing CIP-30 submit method) and is confirmed there, but the wallet still does not know about its consumed inputs, and thus returns outdated data. + +### No support for transaction building + +Finally, CIP-30 leaves the burden of building transactions fully in the hands of the user. +This necessarily forces users to add another layer to their frontend (cardano-transaction-library, cardano-serialization-library, etc) to actually construct, balance and serialize transactions. + +The problem is further exacerbated by the fact that these extra layers for transaction building usually offer diverse API, both in terms of coverage and overall approach to transaction building. This makes switching between different transaction-building libraries very complicated. + +Finally, some concerns around transaction building such as balancing or coin selection, are both hard to implement correctly, and may have significant consequences for the users that are building and submitting transactions. Forcing libraries to re-implement solutions to this problem fragments the efforts and research that is done in these topics. + +## Use cases + + +The use cases listed in [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md#use-cases). + +## Goals + + +- Define a CIP that extends CIP-30 to provide a tighter interaction between wallets and dApps. + +- Build upon the work done in CIP-0116 and CIP-XXXX to offer a full transaction building API based on JSON instead of CBOR, and utilizing the query layer spec to query the blockchain. + +- Define a transaction building API which is based on JSON and is expressive enough to cover many possible different use cases. + +- Provide a simple and unified view of wallet and blockchain data to dApps to prevent many of the pitfalls described above. + +## Open Questions + + +### Choice of transaction building API + +Historically transaction-building APIs for Cardano are either "imperative" or "declarative". The difference between the two is that in the imperative case, the user is operating and building the transaction directly, while in the declarative case the user specifies a set of constraints that the transaction should have, and then a transaction that satisfies those constraints is build from there. +An example of the imperative approach is the API offered by [cardano-api](insert-link), while an example of the declarative one is the [Contract monad](insert-link). It is still unclear which of these two approach is superior to the other, or even if there is a significant difference between the two. A CIP implementing a solution for this CPS would have to decide on which of the two approaches to follow. + +There is also another interesting aspect to transaction building, namely that different users require different levels of control over transaction building process for reasons such as: optimizing fees, ensuring proper ordering of transaction inputs, or backwards compatibility. + +There are three conceptual levels of control: + +- CL1. transaction constraints level - the user only cares about particular requirements a transaction must satisfy in order to be valid in the context of the app, such as sending a certain amount to an address, consuming a UTxO, or submitting a stake delegation. +- CL2. transaction contents level - the user cares about particular details of transaction structure, such as number and contents of change outputs, or ordering of inputs. +- CL3. CBOR level - the user cares about CBOR layout of the transaction, in particular, about key ordering in maps and definite/indefinite length serialization format of CBOR arrays + +A solution must allow all three levels of controls, without forcing users to care about details from lower levels, if they don't need to. + +### Other CIP-30 improvements + + + +-------- + + From 2f4e70bc600dd3b7a14a7a3aa1a0561a2e6efbc0 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Mon, 4 Nov 2024 15:45:00 +0100 Subject: [PATCH 02/25] Add query layer api --- CIP-XXXX/README.md | 460 +++++++++++++++++++++++++++++++++++++++++++++ CPS-XXXX/README.md | 58 +++--- 2 files changed, 489 insertions(+), 29 deletions(-) create mode 100644 CIP-XXXX/README.md diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md new file mode 100644 index 0000000000..15ddee55b1 --- /dev/null +++ b/CIP-XXXX/README.md @@ -0,0 +1,460 @@ +# Adapt CIP-30 to JSON + +Here we define an API that is exactly the same as the one specified in CIP-30, with the only difference of using the JSON encodings of CDDL types, as defined in [CIP-0116](./link). + +We omit the definition of the different functions, or data types, and only provide the updated signatures as the intended behavior is to follow exactly what is specified in CIP-30. The only other change is that we do not support pagination. Errors are updated to reflect that, and some signatures drop the pagination argument. + +## Additional Data Types + +Other than the types defined in [CIP-0116](./link) we will refer to types defined by the following schemas. + +### Data Types + +#### Extensions + +``` +{ + "type": "object", + "title": "Extensions", + "properties": { + "extensions": { + "type": "array" + "items": { + { + "type": "object", + "title": "Extension", + "properties": { + "cip": { + "type": "number" + } + }, + "required": ["cip"], + "unevaluatedProperties": false + } + } + } + }, + "required": ["extensions"], + "unevaluatedProperties": false +} +``` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#extension) + +#### CollateralParams + +``` +{ + "type": "object", + "title": "CollateralParams", + "properties": { + "params": { + "type": "object", + "title": "Amount", + "properties": { + "amount": { + "type": "number" + } + }, + "required": ["amount"], + "unevaluatedProperties": false + } + }, + "required": ["params"], + "unevaluatedProperties": false +} +``` + +This type is not explicitly defined in CIP-30, but is used as an argument to `getCollateral`. + +#### DataSignature + +``` +{ + "type": "object", + "title": "DataSignature", + "properties": { + "signature": { + "title": "Ed25519Signature", + "type": "string", + "format": "hex", + "pattern": "^([0-9a-f][0-9a-f]){64}$" + }, + "key": { + "title": "Ed25519PublicKey", + "type": "string", + "format": "hex", + "pattern": "^([0-9a-f][0-9a-f]){32}$" + } + }, + "required": ["signature", "key"], + "unevaluatedProperties": false +} +``` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#datasignature) + +### Errors + +#### APIError + +``` +{ + "type": "object", + "title": "APIError", + "properties": { + "code": { + "type": "number", + "title": "APIErrorCode" + "enum": [-1, -2, -3, -4] + }, + "info": { + "type": "string" + } + }, + "required": ["code", "info"], + "unevaluatedProperties": false +} +``` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apierror) + +#### DataSignError + +``` +{ + "type": "object", + "title": "DataSignError", + "properties": { + "code": { + "type": "number", + "title": "DataSignErrorCode" + "enum": [1, 2, 3] + }, + "info": { + "type": "string" + } + }, + "required": ["code", "info"], + "unevaluatedProperties": false +} +``` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#datasignerror) + +#### TxSendError + +``` +{ + "type": "object", + "title": "TxSendError", + "properties": { + "code": { + "type": "number", + "title": "TxSendErrorCode" + "enum": [1, 2] + }, + "info": { + "type": "string" + } + }, + "required": ["code", "info"], + "unevaluatedProperties": false +} +``` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#txsenderror) + +#### TxSignError + +``` +{ + "type": "object", + "title": "TxSignError", + "properties": { + "code": { + "type": "number", + "title": "TxSignErrorCode" + "enum": [1, 2] + }, + "info": { + "type": "string" + } + }, + "required": ["code", "info"], + "unevaluatedProperties": false +} +``` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#txsenderror) + +## Main APIs + +### Wallet connection API + +``` +notes: + +Do we need to repeat this section from cip-30? +``` + +In order to initiate communication from webpages to a user's Cardano wallet, the wallet must provide the following javascript API to the webpage. A shared, namespaced `cardano` object must be injected into the page if it did not exist already. Each wallet implementing this standard must then create a field in this object with a name unique to each wallet containing a `wallet` object with the following methods. The API is split into two stages to maintain the user's privacy, as the user will have to consent to `cardano.{walletName}.enable()` in order for the dApp to read any information pertaining to the user's wallet with `{walletName}` corresponding to the wallet's namespaced name of its choice. + +Optional values are marked with a `?`. Refer to the CIP-30 definition for the behavior of the function when a parameter is omitted. + +#### `cardano.{walletName}.enable(extensions?: Extensions): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnameenable-extensions-extension----promiseapi) + +#### `cardano.{walletName}.isEnabled(): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnameisenabled-promisebool) + +#### `cardano.{walletName}.apiVersion: String` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnameapiversion-string) + +#### `cardano.{walletName}.supportedExtensions: Extension[]` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnamesupportedextensions-extension) + +#### `cardano.{walletName}.name: String` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnamename-string) + +#### `cardano.{walletName}.icon: String` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnameicon-string) + +### Wallet own data API + +Upon successful connection via `cardano.{walletName}.enable()`, a javascript object we will refer to as `API` (type) / `api` (instance) is returned to the dApp with the following methods. All read-only 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 state when they agreed to `cardano.{walletName}.enable()`. The remaining methods `api.signTx()`, `api.signData()` and `api.submitTx()` (Note: Should submit also enforce this constraint?) must request the user's consent in an informative way for each and every API call in order to maintain security. + +#### `api.getExtensions(): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetextensions-promiseextension) + +#### `api.getNetworkId(): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetnetworkid-promisenumber) + +#### `api.getUtxos(amount?: Value): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetutxosamount-cborvalue--undefined-paginate-paginate--undefined-promisetransactionunspentoutput--null) + + +#### `api.getCollateral(params: CollateralParams): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetcollateralparams--amount-cborcoin--promisetransactionunspentoutput--null) + + +#### `api.getBalance(): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetbalance-promisecborvalue) + + +#### `api.getUnusedAddresses(): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetunusedaddresses-promiseaddress) + +#### `api.getChangeAddress(): Promise
` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetchangeaddress-promiseaddress) + +#### `api.getRewardAddresses(): Promise` + +Errors: `APIError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetrewardaddresses-promiseaddress) + +#### `api.signTx(tx: Transaction, partialSign?: bool): Promise` + +Errors: `APIError`, `TxSignError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apisigntxtx-cbortransaction-partialsign-bool--false-promisecbortransaction_witness_set) + +#### `api.signData(addr: Address, payload: ByteString): Promise` + +Errors: `APIError`, `DataSignError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apisigndataaddr-address-payload-bytes-promisedatasignature) + + +#### `api.submitTx(tx: Transaction): Promise` + +Errors: `APIError`, `TxSendError` + +[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apisubmittxtx-cbortransaction-promisehash32) + +### Wallet query layer API + +Upon successful connection via `cardano.{walletName}.enable()`, a javascript object we will refer to as `API` (type) / `api` (instance) is returned to the dApp with the following methods. +All methods should not require any user interaction as the user has already consented to the dApp reading information about the wallet's state when they agreed to `cardano.{walletName}.enable()`. + +#### Utxos + +##### `api.query.utxos.asset(asset_name: AssetName, minting_policy_hash: ScriptHash) : Promise` + +Get all UTxOs that contain some of the specified asset + +##### `api.query.utxos.transaction_hash(transaction_hash: TransactionHash) : Promise` + +Get all UTxOs produced by the transaction + +##### `api.query.utxos.address(address: Address) : Promise` + +Get all UTxOs present at the address + +##### `api.query.utxos.payment_credential(credential: Credential) : Promise` + +Get all UTxOs present at the addresses which use the payment credential + +##### `api.query.utxos.stake_credential(reward_address: RewardAddress) : Promise` + +Get all UTxOs present at the addresses which use the stake credential + +#### Block + +##### `api.query.block.number(u_int64: UInt64) : Promise` + +Get the block with the supplied block number + +##### `api.query.block.hash(block_hash: BlockHash) : Promise` + +Get the block with the supplied block hash + +#### Transaction + +##### `api.query.transaction.hash(transaction_hash: TransactionHash) : Promise` + +Get the transaction with the supplied transaction hash + +#### Transactions + +##### `api.query.transactions.block_number(u_int64: UInt64) : Promise` + +Get all transactions contained in the block with the supplied block number [] + +##### `api.query.transactions.block_hash(block_hash: BlockHash) : Promise` + +Get all transactions contained in the block with the supplied block hash + +#### Datum + +##### `api.query.datum.hash(data_hash: DataHash) : Promise` + +Get the datum that hashes to the supplied data hash + +#### Plutus Script + +##### `api.query.plutus_script.hash(script_hash: ScriptHash) : Promise` + +Get the plutus script that hashes to the supplied script hash + +#### Native Script + +##### `api.query.native_script.hash(script_hash: ScriptHash) : Promise` + +Get the native script that hashes to the supplied script hash + +#### Metadata + +##### `api.query.metadata.transaction_hash(transaction_hash: TransactionHash) : Promise` + +Get the metadata present on the transaction with the supplied transaction hash + +#### Protocol Parameters + +##### `api.query.protocol_parameters.latest() : Promise` + +Get the latest protocol parameters + +##### `api.query.protocol_parameters.epoch(u_int32: UInt32) : Promise` + +Get the protocol parameters at the supplied epoch number + +#### Votes + +##### `api.query.votes.cc_id(cc_hot_id: CCHotId) : Promise` + +Votes cast by the supplied cc credential + +##### `api.query.votes.spo_id(pool_pubkeyhash: PoolPubKeyHash) : Promise` + +Votes cast by the supplied stake pool operator + +##### `api.query.votes.drep_id(drep_id: DRepId) : Promise` + +Votes cast by the supplied DRep + +##### `api.query.votes.proposal_id(proposal_id: ProposalId) : Promise` + +Votes cast on the supplied proposal + +#### Drep + +##### `api.query.drep.all() : Promise` + +Get all the known DReps + +##### `api.query.drep.id(drep_id: DRepId) : Promise` + +Get a specific DRep by id + +##### `api.query.drep.stake_credential(reward_address: RewardAddress) : Promise` + +Get the DRep that the stake credential has delegated to + +#### Committee + +##### `api.query.committee.all() : Promise` + +Get all known committee members + +##### `api.query.committee.id(cc_hot_id: CCHotId) : Promise` + +Get a specific Committee member by id + +#### Pool + +##### `api.query.pool.all() : Promise` + +Get all known stake pools + +##### `api.query.pool.id(pool_pubkeyhash: PoolPubKeyHash) : Promise` + +Get a specific stake pool by id + +#### Proposal + +##### `api.query.proposal.all() : Promise` + +Get all known proposals + +##### `api.query.proposal.id(proposal_id: ProposalId) : Promise` + +Get a specific proposal by id + +#### Era + +##### `api.query.era.summary() : Promise` + +Get the start and end of each era along with parameters that can vary between hard forks diff --git a/CPS-XXXX/README.md b/CPS-XXXX/README.md index 98685c84c5..c3e52af101 100644 --- a/CPS-XXXX/README.md +++ b/CPS-XXXX/README.md @@ -16,15 +16,14 @@ Created: YYYY-MM-DD CIP-30 is the standard interface of communication between wallets and DApps. While this CIP has been instrumental in the development of dApps for Cardano, it also has some shortcomings that have been observed across several implementations. -We have identified three steps in the path to provide a better alternative to CIP-30: +We have identified and carried out two steps in the path to provide a better alternative to CIP-30: -- Defining a universal JSON encoding for Cardano domain types. CIP-30 requires CBOR encoding and decoding for data passed to and from the wallet, which is often an extra burden for the client. This problem is stated in [CPS-0011](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0011) and it's corresponding [CIP-0116](link). +- Defining a universal JSON encoding for Cardano domain types. CIP-30 requires CBOR encoding and decoding for data passed to and from the wallet, which is often an extra burden for the client. This problem is stated in [CPS-0011](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0011) and a potential solution is given in [CIP-0116](link). -- Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012] and it's corresponding [CIP-????](link). +- Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012] and a potential solution is given in [CIP-????](link). -- Define an API for transaction building. This is the last step required to build a full-data wallet connector as specified in [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md#full-data-wallets). - -[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) defines the responsibilities for wallet connector, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. In this CPS we hope to explain the need and our design for a full-data wallet connector. +[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) defines the responsibilities for wallet connector, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. +In this CPS we hope to explain why a full-data wallet connector would be useful, and how putting all these pieces together we can make an improvement over CIP-30. ## Problem @@ -60,19 +59,17 @@ A dApp tries to balance a transaction with UTxOs from the wallet that is not yet A transaction is passed for signing, but the wallet does not yet know about the UTxOs it spends, and thus refuses to sign it A transaction is sent to the network via the dApp backend (bypassing CIP-30 submit method) and is confirmed there, but the wallet still does not know about its consumed inputs, and thus returns outdated data. -### No support for transaction building - -Finally, CIP-30 leaves the burden of building transactions fully in the hands of the user. -This necessarily forces users to add another layer to their frontend (cardano-transaction-library, cardano-serialization-library, etc) to actually construct, balance and serialize transactions. - -The problem is further exacerbated by the fact that these extra layers for transaction building usually offer diverse API, both in terms of coverage and overall approach to transaction building. This makes switching between different transaction-building libraries very complicated. - -Finally, some concerns around transaction building such as balancing or coin selection, are both hard to implement correctly, and may have significant consequences for the users that are building and submitting transactions. Forcing libraries to re-implement solutions to this problem fragments the efforts and research that is done in these topics. - ## Use cases -The use cases listed in [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md#use-cases). +The use cases listed in [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md#use-cases), +which lists some use cases for wallet connectors, equally apply to this CPS as well. + +Ultimately, the problem we are trying to solve is the "two sources of truth" that exist when a dApp has to both query the wallet for its own UTxO state, and then query some other data provider (blockfrost, maestro, a local node) for the state of the blockchain. + +By giving the wallets direct control over the data-fetching API, we allow them to present an unified view of all the UTxOs, reducing the issues that currently happen because of wallet vs dApp UTxO contention, and making optimizations (i.e. transaction chaining) easier to implement and more robust. +This benefits both end users of the wallets, because it reduces the chance to build and submit transactions that will end up being phase-1 invalid, +and dApp developers by relieving them of having to deal with synchronization between the (local) wallet state and the (global) chain state. ## Goals -- Define a CIP that extends CIP-30 to provide a tighter interaction between wallets and dApps. +- Define a CIP that extends CIP-30 to provide a tighter interaction between wallets and dApps by following the principles outlined in CPS-0010. -- Build upon the work done in CIP-0116 and CIP-XXXX to offer a full transaction building API based on JSON instead of CBOR, and utilizing the query layer spec to query the blockchain. - -- Define a transaction building API which is based on JSON and is expressive enough to cover many possible different use cases. +- Build upon the work done in CIP-0116 and CIP-XXXX to offer a full transaction building API based on JSON instead of CBOR, and utilizing the query layer spec to fetch data from the blockchain. - Provide a simple and unified view of wallet and blockchain data to dApps to prevent many of the pitfalls described above. ## Open Questions -### Choice of transaction building API -Historically transaction-building APIs for Cardano are either "imperative" or "declarative". The difference between the two is that in the imperative case, the user is operating and building the transaction directly, while in the declarative case the user specifies a set of constraints that the transaction should have, and then a transaction that satisfies those constraints is build from there. -An example of the imperative approach is the API offered by [cardano-api](insert-link), while an example of the declarative one is the [Contract monad](insert-link). It is still unclear which of these two approach is superior to the other, or even if there is a significant difference between the two. A CIP implementing a solution for this CPS would have to decide on which of the two approaches to follow. +### Translating CIP-30 API + +There are some choices that will need to be done while translating the CIP-30 API to JSON. The types defined in [CIP-0116](./link) should provide almost all that is required, but types for errors, and other domain types used by CIP-30 will need to be added as well. +Furthermore, CIP-30 specifies options for pagination. While useful in practice, pagination has turned out to be complex to implement properly and is not supported in [CIP-XXXX](./). CIP authors should decide wether to attempt to support the pagination from CIP-30 or to drop it completely. -There is also another interesting aspect to transaction building, namely that different users require different levels of control over transaction building process for reasons such as: optimizing fees, ensuring proper ordering of transaction inputs, or backwards compatibility. +### Transaction building API -There are three conceptual levels of control: +The new proposed interface allows to submit transactions directly as native JS objects. +It is currently not clear if it is worth adding a layer to the wallet connector to standardize transaction building. -- CL1. transaction constraints level - the user only cares about particular requirements a transaction must satisfy in order to be valid in the context of the app, such as sending a certain amount to an address, consuming a UTxO, or submitting a stake delegation. -- CL2. transaction contents level - the user cares about particular details of transaction structure, such as number and contents of change outputs, or ordering of inputs. -- CL3. CBOR level - the user cares about CBOR layout of the transaction, in particular, about key ordering in maps and definite/indefinite length serialization format of CBOR arrays +APIs for transaction building also come in many flavors: there are prominent examples both of "declarative APIs", that allow building the transaction by specifying a set of constraints +that the transaction must respect, and the "imperative API", that allows building a transaction object directly. These two APIs don't necessarily rule each other out: +some implementations mix the two with input or transaction builders. -A solution must allow all three levels of controls, without forcing users to care about details from lower levels, if they don't need to. +The CIP authors should decide if they want to add this interface to the CIP directly, or perhaps leave it as future work. +Should a transaction building API be added, our recommendation would be to aim to make it as close as possible with +[cardano-serialization-lib](https://github.com/Emurgo/cardano-serialization-lib) which is widely used in the ecosystem and would be easy to adopt by many wallets. ### Other CIP-30 improvements +There are a few other issues with CIP-30 that are raised in CPS-0010. Since this CPS is advocating for a replacement to CIP-30, it would make sense to resolve some of those issues. However, since the update we are advocating for is already quite substantial, an argument can also be made to delay further changes to future and more specific CIPs. -------- From 78b4a10fb36655bc5d0dbc7659674734f1b2c67e Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Wed, 6 Nov 2024 12:17:39 +0100 Subject: [PATCH 03/25] Minor details --- CPS-XXXX/README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/CPS-XXXX/README.md b/CPS-XXXX/README.md index c3e52af101..dccbe45a9b 100644 --- a/CPS-XXXX/README.md +++ b/CPS-XXXX/README.md @@ -93,24 +93,23 @@ Finally, goals may also serve as evaluation metrics to assess how good a propose There are some choices that will need to be done while translating the CIP-30 API to JSON. The types defined in [CIP-0116](./link) should provide almost all that is required, but types for errors, and other domain types used by CIP-30 will need to be added as well. Furthermore, CIP-30 specifies options for pagination. While useful in practice, pagination has turned out to be complex to implement properly and is not supported in [CIP-XXXX](./). CIP authors should decide wether to attempt to support the pagination from CIP-30 or to drop it completely. +### Other CIP-30 improvements + +There are a few other issues with CIP-30 that are raised in CPS-0010. Since this CPS is advocating for a replacement to CIP-30, it would make sense to resolve some of those issues. However, since the update we are advocating for is already quite substantial, an argument can also be made to delay further changes to future and more specific CIPs. + ### Transaction building API -The new proposed interface allows to submit transactions directly as native JS objects. -It is currently not clear if it is worth adding a layer to the wallet connector to standardize transaction building. +By revamping CIP-30 to directly accept JSON rather than CBOR, we potentially relieve the dApp from having to use an external library to build transactions. Users can simply build and submit the JSON translation of the CDDL `Transaction` object. +It is currently not clear if it is worth adding a specialized API to the wallet to help with transaction building. The main argument for doing so is that often times when adding something to a transaction (like an input, or a mint) you need to also add something else (i.e. a witness). This makes building the transaction object directly more cumbersome and error prone, while an intermediate API could make this process more straightforward. -APIs for transaction building also come in many flavors: there are prominent examples both of "declarative APIs", that allow building the transaction by specifying a set of constraints -that the transaction must respect, and the "imperative API", that allows building a transaction object directly. These two APIs don't necessarily rule each other out: -some implementations mix the two with input or transaction builders. +However, APIs for transaction building also come in many flavors: there are prominent examples both of "declarative APIs", that allow building the transaction by specifying a set of constraints that the transaction must respect, +and the "imperative API", that allows building a transaction object directly. These two APIs don't necessarily rule each other out: +some implementations mix the two through input or transaction builders. The CIP authors should decide if they want to add this interface to the CIP directly, or perhaps leave it as future work. Should a transaction building API be added, our recommendation would be to aim to make it as close as possible with [cardano-serialization-lib](https://github.com/Emurgo/cardano-serialization-lib) which is widely used in the ecosystem and would be easy to adopt by many wallets. -### Other CIP-30 improvements - -There are a few other issues with CIP-30 that are raised in CPS-0010. Since this CPS is advocating for a replacement to CIP-30, it would make sense to resolve some of those issues. However, since the update we are advocating for is already quite substantial, an argument can also be made to delay further changes to future and more specific CIPs. - - -------- From 30445f0e7f06000181a4d0f54bccfcccc3ce3c7d Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Wed, 18 Dec 2024 09:02:54 +0000 Subject: [PATCH 04/25] Restructure CIP document --- CIP-XXXX/README.md | 652 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 492 insertions(+), 160 deletions(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index 15ddee55b1..cb9027d2cc 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -1,16 +1,464 @@ -# Adapt CIP-30 to JSON +--- +CIP: ? +Title: Full-data wallet connector +Status: Open +Category: Tools +Authors: + - Giovanni Garufi +Implementors: [] +Discussions: + - https://github.com/cardano-foundation/cips/pulls/? +Created: 2024-12-13 +License: CC-BY-4.0 +Version: 0.0.0 +--- -Here we define an API that is exactly the same as the one specified in CIP-30, with the only difference of using the JSON encodings of CDDL types, as defined in [CIP-0116](./link). +## Abstract -We omit the definition of the different functions, or data types, and only provide the updated signatures as the intended behavior is to follow exactly what is specified in CIP-30. The only other change is that we do not support pagination. Errors are updated to reflect that, and some signatures drop the pagination argument. -## Additional Data Types +CIP-30 is the standard interface of communication between wallets and DApps. While this CIP has been instrumental in the development of dApps for Cardano, it also has some shortcomings that have been observed across several implementations. -Other than the types defined in [CIP-0116](./link) we will refer to types defined by the following schemas. +We have identified and carried out two steps in the path to provide a better alternative to CIP-30: -### Data Types +- Defining a universal JSON encoding for Cardano domain types. CIP-30 requires CBOR encoding and decoding for data passed to and from the wallet, which is often an extra burden for the client. This problem is stated in [CPS-0011](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0011) and a potential solution is given in [CIP-0116](link). -#### Extensions +- Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012](link) and a potential solution is given in [CIP-0139](link). + + +Finally, [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) defines the responsibilities for wallet connectors, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. + +In this CIP we want to put these together, defining a wallet connector standard for a full-data wallet. + +## Motivation: why is this CIP necessary? + +CIP-30 is a universally accepted web-based wallet standard for Cardano. It provides a minimalistic interface that, in principle, can be used to build almost any kind of Cardano dApp. However, the way dApp<->wallet interaction is defined leads to suboptimal dApp architecture due to CIP-30 limits. + +[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses many limitations of CIP-30. In addition to the ones specified in the CPS, consider the following problems: + +### Use of CBOR representations + +CIP-30 standard uses CBOR encoding for all data passed from the wallet, e.g. addresses and UTxOs. Interpreting this data within the app requires CBOR decoding functionality that is tedious to implement manually, and so users resort to using cardano-serialization-lib or its close alternative, cardano-multiplatform-lib, which both require loading a WebAssembly blob of >1M in size. + +For comparison, to start a new Web3 app on Ethereum there is no need to use a library for data serialization. It’s possible to interact with a provider object that is given by the wallet directly, although there are libraries to further simplify this. Using CBOR looks unnecessary for most dApps, given that JSON is a de-facto standard for web data serialization. + +### Limited scope of available queries + +Most dApps require interacting with scripts, which implies the need to query for available UTxOs locked at script addresses and other blockchain data. CIP-30 is intentionally limited in scope to management of UTxOs "owned" by the wallet itself. + +Some other useful queries, like getting delegation and reward info, stake pool info, transaction metadata or contents, and epoch data, are also outside of scope. + +As a result, dApp developers are forced to implement their own query layers on the backend side - which leads to one more problem - inconsistency between states of two query layers: + +### Inconsistency of Query Layers + +On Cardano, every running node has its own opinion on the set of currently unspent transaction outputs. Only eventual consistency is guaranteed. + +Any dApp that interacts with a CIP-30 wallet has to deal with the inconsistency between the local cardano-node-based query layer and the light wallet query layer, especially when dApp workflow involves sending multiple transactions with the wallet in quick succession. + +Thus, the goal of the developers is to ensure that the set of UTxOs available to the wallet and the set of UTxOs the backend cardano-node knows about are synchronized enough to not cause errors when a wallet or backend operations are performed. To give a few examples of potential issues, consider the following scenarios: + +A dApp tries to balance a transaction with UTxOs from the wallet that is not yet available in dApp backend's cardano node, causing an error response during execution units evaluation +A transaction is passed for signing, but the wallet does not yet know about the UTxOs it spends, and thus refuses to sign it +A transaction is sent to the network via the dApp backend (bypassing CIP-30 submit method) and is confirmed there, but the wallet still does not know about its consumed inputs, and thus returns outdated data. + + +## Specification + +The goal of this CIP is to provide a better alternative to CIP-30 which supports full data wallet. Specifically we make the following contributions: + +- A clear separation between the connection mechanism and the actual API offered by the wallet connector +- Using JSON for Cardano domain types instead of CBOR +- Add a query layer API to enable a full data wallet +- Define this in a transport agnostic way + +In it's current state, CIP-30 defines it API through a specific transport layer, namely an injected Javascript object. +In this CIP we want to be able to define an API without committing to a specific transport layer. Implementors of this API can choose to support this API through several transports such as: HTTP, an injected Javascript object, JSON-RPC etc. +Furthermore, we want to use JSON-schema to clearly define the types that each method, or operation, expects to receive or returns. +To keep the specification abstract we will use the word "operation" to describe the actions supported by the API, these would map to "endpoints" for an HTTP implementation of the API, or to "methods" for an implementation based on an injected Javascript object. + + +We will use the following schema to define operations: + +``` +{ + "operation": { "type": "string" }, + "request": { "type": "object" }, + "response": { "type": "object" }, + "errors": { + "type": "array", + "items": { "type": "object" } + } +} +``` + +where `operation` will be the identifier for the operation, `request` and `response` will be the JSON-schemas for the request and response types respectively, and `errors` will be a list of schemas for the errors that the operation may raise. + +We will reference several JSON-schemas throughout the document, these are: + +- [cip-0116](link) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. [Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types] +- [cip-0139](link) which provides definitions for types used in the query layer +- [appendix](#appendix) in which we define schemas for types required by the connection API and the error types + +We will use an identifier in the anchor to refer to the schema where each type is defined. For example, if we want to reference the `Transaction` type, as defined in CIP-0116 we will use the following schema reference `{ "$ref": "#/cip-0116/Transaction" }`. + +If an operation does not require any arguments as part of it's request, or does not return a meaningful response, we will represent this as an `{}` on the respective operation field. The arguments to an operation will always be represented as an object. If a field is not marked as `required`, then that argument is to be considered optional. + +For each operation we will provide some details on how the implementation should behave. Note tht some of these are taken verbatim from CIP-30. + +### Connection API + +We start by defining the connection API. The role of this API is to provide generic information about the wallet and to allow the user to opt into the functionalities that they want the wallet to provide. + +##### Enable + +``` +{ + "operation": "enable", + "request": { "$ref": "#/appendix/Extensions" }, + "response": {}, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +This is the entrypoint to start communication with the user's wallet. The wallet should request the user's permission to connect the web page to the user's wallet, and if permission has been granted, the APIs will be made available for the DApp to use. The wallet can choose to maintain a whitelist to not necessarily ask the user's permission every time access is requested, but this behavior is up to the wallet and should be transparent to web pages using this API. If a wallet is already connected this function should not request access a second time. + +DApps can request a list of they expect as a list of CIP numbers capturing those extensions. This is used as an extensibility mechanism to document what functionalities can be provided by the wallet interface. We will see later in this document examples of what such extensions might be and which functionalities they will enable. New functionalities can be introduced via additional CIPs and may be all or partially supported by wallets. + +DApps are expected to use this endpoint to perform an initial handshake and ensure that the wallet supports all their required functionalities. Note that it's possible for two extensions to be mutually incompatible (because they provide two conflicting features). While we may try to avoid this as much as possible while designing CIPs, it is also the responsibility of wallet providers to assess whether they can support a given combination of extensions, or not. Wallets should throw an error if either they do not support the required extension, or they deem the combination of extensions requested by the DApp to be incompatible. + + +##### IsEnabled + +``` +{ + "operation": "isEnabled", + "request": {}, + "response": { "type": "boolean" }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +Returns true if the dApp is already connected to the user's wallet, or if requesting access would return true without user confirmation (e.g. the dApp is whitelisted), and false otherwise. + + +##### SupportedExtensions + +``` +{ + "operation": "supportedExtensions", + "request": {}, + "response": { "$ref": "#/appendix/Extensions" }, + "errors": [] +} +``` + +A list of extensions supported by the wallet. Extensions may be requested by dApps on initialization. Some extensions may be mutually conflicting and this list does not thereby reflect what extensions will be enabled by the wallet. Yet it informs on what extensions are known and can be requested by dApps if needed. + + +##### Name + +``` +{ + "operation": "name", + "request": {}, + "response": { "type": "string" }, + "errors": [] +} +``` + +A name for the wallet which can be used inside of the dApp for the purpose of asking the user which wallet they would like to connect with. + +##### Icon + +``` +{ + "operation": "icon", + "request": {}, + "response": { "type": "string" }, + "errors": [] +} +``` + +A URI image (e.g. data URI base64 or other) for img src for the wallet which can be used inside of the dApp for the purpose of asking the user which wallet they would like to connect with. + +### Extension APIs + +The following section will define the APIs offered by extensions that can be requested through the `enable` operation. With a slight abuse of notation, we will define the operations defined in CIP-30, in the [Full API](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#full-api) as belonging to the `cip-30` extension. +We will also define the `cip-139` extension which enables wallet to use the Universal Query Layer API. + +A wallet which enables both the `cip-30` and `cip-139` extension would then be considered a full-data wallet. + +Future CIPs can add more extensions to the supported list. + +#### CIP-30 + +This section defines the API for the `Full API` part of CIP-30. Enabling only this extension would give you an own-data wallet, which is essentially equivalent to what CIP-30 gives us today. + +Operations that sign data MUST require additional user consent before being performed. Additional details will be specified in the section for each operation. +Note that this API differs slightly from CIP-30 Full API in that it drops an endpoint which is not required (`getExtensions`) and removes the option for pagination. + +The removal of pagination follows the same [reasons](https://github.com/klntsky/CIPs/blob/klntsky/query-layer-cip/CIP-XXXX/README.md#pagination) pointed out in CIP-0139. In summary: pagination, while desirable, introduces some complications with the consistency of the returned results. We decide to drop it to keep the implementation as simple as possible, but welcome future CIPs to address this. + +##### GetNetworkId + +``` +{ + "operation": "getNetworkId", + "request": {}, + "response": { "type": "number" }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +Returns the network id of the currently connected account. 0 is testnet and 1 is mainnet but other networks can possibly be returned by wallets. Those other network ID values are not governed by this document. This result will stay the same unless the connected account has changed. + +##### GetUtxos + +``` +{ + "operation": "getUtxos", + "request": { + "type": "object", + "properties": { + "amount": { "$ref": "#/cip-116/Value" } + } + }, + "response": { "$ref": "#/cip-116/TransactionUnspentOutput" }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +If amount is not supplied, this shall return a list of all UTXOs controlled by the wallet. If amount is present, this request shall be limited to just the UTXOs that are required to reach the combined ADA/multiasset value target specified in amount, and if this cannot be attained, an `APIError` with error code `NotSatisfiable` (and optionally an info string) must be returned. + +##### GetCollateral + +``` +{ + "operation": "getCollateral", + "request": { + "type": "object", + "properties": { + "amount": { "type": "number" } + }, + "required": ["amount"] + }, + "response": { "$ref": "#/cip-116/TransactionUnspentOutput" }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +The operation takes an amount parameter. (NOTE: some wallets may be ignoring the amount parameter, in which case it might be possible to call the function without it, but this behavior is not recommended!). Reasons why the amount parameter is required: + +- Dapps must be motivated to understand what they are doing with the collateral, in case they decide to handle it manually. + +- Depending on the specific wallet implementation, requesting more collateral than necessarily might worsen the user experience with that dapp, requiring the wallet to make explicit wallet reorganisation when it is not necessary and can be avoided. + +- If dapps don't understand how much collateral they actually need to make their transactions work - they are placing more user funds than necessary in risk. + +So requiring the amount parameter would be a by-spec behavior for a wallet. Not requiring it is possible, but not specified, so dapps should not rely on that and the behavior is not recommended. + +This shall return a list of one or more UTXOs controlled by the wallet that are required to reach AT LEAST the combined ADA value target specified in amount AND the best suitable to be used as collateral inputs for transactions with plutus script inputs (pure ADA-only utxos). If this cannot be attained, an APIError with code `NotSatisfiable` and an explanation of the blocking problem shall be returned. NOTE: wallets are free to return utxos that add up to a greater total ADA value than requested in the amount parameter, but wallets must never return any result where utxos would sum up to a smaller total ADA value, instead in a case like that an error must be returned. + +The main point is to allow the wallet to encapsulate all the logic required to handle, maintain, and create (possibly on-demand) the UTXOs suitable for collateral inputs. For example, whenever attempting to create a plutus-input transaction the dapp might encounter a case when the set of all user UTXOs don't have any pure entries at all, which are required for the collateral, in which case the dapp itself is forced to try and handle the creation of the suitable entries by itself. If a wallet implements this function it allows the dapp to not care whether the suitable utxos exist among all utxos, or whether they have been stored in a separate address chain (see #104), or whether they have to be created at the moment on-demand - the wallet guarantees that the dapp will receive enough utxos to cover the requested amount, or get an error in case it is technically impossible to get collateral in the wallet (e.g. user does not have enough ADA at all). + +[The spec says that amount should agreed to be max 5 ada, is this enforced? The formulation in the CIP does not seem to be too precise] + + +##### GetBalance + +``` +{ + "operation": "getBalance", + "request": {}, + "response": { "$ref": "#/cip-116/Value" }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +Returns the total balance available of the wallet. This is the same as summing the results of api.getUtxos(), but it is both useful to dApps and likely already maintained by the implementing wallet in a more efficient manner so it has been included in the API as well. + + +##### GetUsedAddresses + +``` +{ + "operation": "getUsedAddresses", + "request": {}, + "response": { + "type": "array", + "items: { "$ref": "#/cip-116/Address" } + }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +Returns a list of all used (included in some on-chain transaction) addresses controlled by the wallet. + +##### GetUnusedAddresses + +``` +{ + "operation": "getUnusedAddresses", + "request": {}, + "response": { + "type": "array", + "items: { "$ref": "#/cip-116/Address" } + }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +Returns a list of unused addresses controlled by the wallet. + +##### GetChangeAddress + +``` +{ + "operation": "getChangeAddress", + "request": {}, + "response": { "$ref": "#/cip-116/Address" }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +Returns an address owned by the wallet that should be used as a change address to return leftover assets during transaction creation back to the connected wallet. This can be used as a generic receive address as well. + +##### GetRewardAddresses + +``` +{ + "operation": "getRewardAddresses", + "request": {}, + "response": { + "type": "array", + "items: { "$ref": "#/cip-116/RewardAddress" } + }, + "errors": [ + { "$ref": "#/appendix/APIError" } + ] +} +``` + +Returns the reward addresses owned by the wallet. This can return multiple addresses e.g. CIP-0018. + +##### SignTx + +``` +{ + "operation": "signTx", + "request": { + "type": "object", + "properties": { + "tx": { "$ref": #/cip-116/Transaction }, + "partialSign": { "type": "boolean" } + }, + "required": ["tx"] + }, + "response": { "$ref": "#/cip-116/TransactionWitnessSet" }, + "errors": [ + { "$ref": "#/appendix/APIError" }, + { "$ref": "#/appendix/TxSignError" } + ] +} +``` + +Requests that a user sign the unsigned portions of the supplied transaction. The wallet MUST ask the user for permission, and if given, try to sign the supplied transaction. If partialSign is true, the wallet only tries to sign what it can. If partialSign is false, or not supplied, and the wallet could not sign the entire transaction, `TxSignError` shall be returned with a `ProofGeneration` error code. Likewise if the user declined in either case it shall return the same error with a `UserDeclined` error code. + +Only the portions of the witness set that were signed as a result of this call are returned to encourage dApps to verify the contents returned by this endpoint while building the final transaction. + + +##### SignData + +``` +{ + "operation": "signData", + "request": { + "type": "object", + "properties": { + "addr": { "$ref": #/cip-116/Address }, + "payload": { "$ref": #/cip-116/ByteString } + }, + "required": ["addr", "payload"] + }, + "response": { "$ref": "#/appendix/DataSignature" }, + "errors": [ + { "$ref": "#/appendix/APIError" }, + { "$ref": "#/appendix/DataSignError" } + ] +} +``` + +[Is bytestring the correct type here?] + +This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/README.md) for standardization/safety reasons. It allows the dApp to request the user to sign a payload conforming to said spec. The user's consent MUST be requested and the message to sign shown to the user. The payment key from `addr` will be used for base, enterprise and pointer addresses to determine the EdDSA25519 key used. The staking key will be used for reward addresses. This key will be used to sign the `COSE_Sign1`'s `Sig_structure` with the following headers set: + +- `alg` (1) - must be set to EdDSA (-8) +- `kid` (4) - Optional, if present must be set to the same value as in the COSE_key specified below. It is recommended to be set to the same value as in the "address" header. +- `address` - must be set to the raw binary bytes of the address as per the binary spec + +The payload is not hashed and no `external_aad` is used. + +If the payment key for `addr` is not a P2Pk address then `DataSignError` will be returned with error code `AddressNotPK`. `ProofGeneration` error code shall be returned if the wallet cannot generate a signature (i.e. the wallet does not own the requested payment private key), and `UserDeclined` will be returned if the user refuses the request. The return shall be a `DataSignature` with `signature` set to the hex-encoded bytes of the `COSE_Sign1` object specified above and `key` shall be the hex-encoded bytes of a `COSE_Key` structure with the following headers set: + +- `kty` (1) - must be set to `OKP` (1) +- `kid` (2) - Optional, if present must be set to the same value as in the `COSE_Sign1` specified above. +- `alg` (3) - must be set to `EdDSA` (-8) +- `crv` (-1) - must be set to `Ed25519` (6) +- `x` (-2) - must be set to the public key bytes of the key used to sign the `Sig_structure` + +[What are these numbers appearing next to params? Copied them from cip-30 but not sure] + +##### SubmitTx + +``` +{ + "operation": "submitTx", + "request": { + "type": "object", + "properties": { + "tx": { "$ref": #/cip-116/Transaction } + }, + "required": ["tx"] + }, + "response": { "$ref": "#/cip-116/TransactionHash" }, + "errors": [ + { "$ref": "#/appendix/APIError" }, + { "$ref": "#/appendix/TxSendError" } + ] +} +``` + +As wallets should already have this ability, we allow dApps to request that a transaction be sent through it. If the wallet accepts the transaction and tries to send it, it shall return the transaction id for the dApp to track. The wallet is free to return the `TxSendError` with error code `Refused` if they do not wish to send it, or `Failure` if there was an error in sending it (e.g. preliminary checks failed on signatures). + + +#### CIP-139 + + +### Appendix + +This appendix contains additional schemas for types that are used in the APIs. + +#### Connection API Data Types + +##### Extensions ``` { @@ -29,45 +477,22 @@ Other than the types defined in [CIP-0116](./link) we will refer to types define } }, "required": ["cip"], - "unevaluatedProperties": false } } } }, "required": ["extensions"], - "unevaluatedProperties": false } ``` -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#extension) - -#### CollateralParams +An extension is an object with a single field "cip" that describes a CIP number extending the API. For example: ``` -{ - "type": "object", - "title": "CollateralParams", - "properties": { - "params": { - "type": "object", - "title": "Amount", - "properties": { - "amount": { - "type": "number" - } - }, - "required": ["amount"], - "unevaluatedProperties": false - } - }, - "required": ["params"], - "unevaluatedProperties": false -} +{ "cip": 30 } ``` -This type is not explicitly defined in CIP-30, but is used as an argument to `getCollateral`. -#### DataSignature +##### DataSignature ``` { @@ -88,15 +513,16 @@ This type is not explicitly defined in CIP-30, but is used as an argument to `ge } }, "required": ["signature", "key"], - "unevaluatedProperties": false } ``` -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#datasignature) +An object representing some data that has been signed. It contains 2 fields: `signature` which contains the signed data, and `key` which contains the derived Ed25519 PubKey used to sign the data. -### Errors +#### Errors -#### APIError +This section lists the possible errors the wallet connector may return. Each error is specified by an error code, and an optional info string describing the cause of the error. Below each error we list names for all the error codes, and a brief description of when they should be used. Other than when the spec dictates the use of a specific error code, wallets can choose the error code they deem more applicable to the situation. Wallets can also extend these errors with additional codes should they feel the need to. + +##### APIError ``` { @@ -106,20 +532,25 @@ This type is not explicitly defined in CIP-30, but is used as an argument to `ge "code": { "type": "number", "title": "APIErrorCode" - "enum": [-1, -2, -3, -4] + "enum": [-1, -2, -3, -4, -5] }, "info": { "type": "string" } }, - "required": ["code", "info"], - "unevaluatedProperties": false + "required": ["code"], } ``` -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apierror) +[Why are these negative? Seems arbitrary, is it too breaking to change them?] + +- `InvalidRequest`: (-1) Inputs do not conform to this spec or are otherwise invalid. +- `InternalError`: (-2) An error occurred during execution of this API call. +- `Refused`: (-3) The request was refused due to lack of access - e.g. wallet disconnects. +- `AccountChange`: (-4) The account has changed. The dApp should call wallet.enable() to reestablish connection to the new account. The wallet should not ask for confirmation as the user was the one who initiated the account change in the first place. +- `NotSatisfiable`: (-5) The request is structurally correct, but the wallet can not satisfy it for some reason. -#### DataSignError +##### DataSignError ``` { @@ -135,14 +566,15 @@ This type is not explicitly defined in CIP-30, but is used as an argument to `ge "type": "string" } }, - "required": ["code", "info"], - "unevaluatedProperties": false + "required": ["code"], } ``` -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#datasignerror) +- `ProofGeneration`: (1) Wallet could not sign the data (e.g. does not have the secret key associated with the address). +- `AddressNotPK`: (2) Address was not a P2PK address and thus had no SK associated with it. +- `UserDeclined`: (3) User declined to sign the data. -#### TxSendError +##### TxSendError ``` { @@ -158,14 +590,14 @@ This type is not explicitly defined in CIP-30, but is used as an argument to `ge "type": "string" } }, - "required": ["code", "info"], - "unevaluatedProperties": false + "required": ["code"], } ``` -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#txsenderror) +- `Refused`: (1) Wallet refuses to send the tx (could be rate limiting). +- `Failure`: (2) Wallet could not send the tx. -#### TxSignError +##### TxSignError ``` { @@ -181,128 +613,28 @@ This type is not explicitly defined in CIP-30, but is used as an argument to `ge "type": "string" } }, - "required": ["code", "info"], - "unevaluatedProperties": false + "required": ["code"], } ``` -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#txsenderror) - -## Main APIs - -### Wallet connection API - -``` -notes: - -Do we need to repeat this section from cip-30? -``` - -In order to initiate communication from webpages to a user's Cardano wallet, the wallet must provide the following javascript API to the webpage. A shared, namespaced `cardano` object must be injected into the page if it did not exist already. Each wallet implementing this standard must then create a field in this object with a name unique to each wallet containing a `wallet` object with the following methods. The API is split into two stages to maintain the user's privacy, as the user will have to consent to `cardano.{walletName}.enable()` in order for the dApp to read any information pertaining to the user's wallet with `{walletName}` corresponding to the wallet's namespaced name of its choice. - -Optional values are marked with a `?`. Refer to the CIP-30 definition for the behavior of the function when a parameter is omitted. - -#### `cardano.{walletName}.enable(extensions?: Extensions): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnameenable-extensions-extension----promiseapi) - -#### `cardano.{walletName}.isEnabled(): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnameisenabled-promisebool) - -#### `cardano.{walletName}.apiVersion: String` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnameapiversion-string) - -#### `cardano.{walletName}.supportedExtensions: Extension[]` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnamesupportedextensions-extension) - -#### `cardano.{walletName}.name: String` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnamename-string) - -#### `cardano.{walletName}.icon: String` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#cardanowalletnameicon-string) - -### Wallet own data API - -Upon successful connection via `cardano.{walletName}.enable()`, a javascript object we will refer to as `API` (type) / `api` (instance) is returned to the dApp with the following methods. All read-only 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 state when they agreed to `cardano.{walletName}.enable()`. The remaining methods `api.signTx()`, `api.signData()` and `api.submitTx()` (Note: Should submit also enforce this constraint?) must request the user's consent in an informative way for each and every API call in order to maintain security. - -#### `api.getExtensions(): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetextensions-promiseextension) - -#### `api.getNetworkId(): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetnetworkid-promisenumber) - -#### `api.getUtxos(amount?: Value): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetutxosamount-cborvalue--undefined-paginate-paginate--undefined-promisetransactionunspentoutput--null) - - -#### `api.getCollateral(params: CollateralParams): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetcollateralparams--amount-cborcoin--promisetransactionunspentoutput--null) - - -#### `api.getBalance(): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetbalance-promisecborvalue) - - -#### `api.getUnusedAddresses(): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetunusedaddresses-promiseaddress) - -#### `api.getChangeAddress(): Promise
` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetchangeaddress-promiseaddress) - -#### `api.getRewardAddresses(): Promise` - -Errors: `APIError` - -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apigetrewardaddresses-promiseaddress) - -#### `api.signTx(tx: Transaction, partialSign?: bool): Promise` +- `ProofGeneration`: (1) User has accepted the transaction sign, but the wallet was unable to sign the transaction (e.g. not having some of the private keys). +- `UserDeclined`: (2) User declined to sign the transaction. -Errors: `APIError`, `TxSignError` +## Rationale: how does this CIP achieve its goals? -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apisigntxtx-cbortransaction-partialsign-bool--false-promisecbortransaction_witness_set) +This CIP -#### `api.signData(addr: Address, payload: ByteString): Promise` +## Path to Active -Errors: `APIError`, `DataSignError` +- ??? -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apisigndataaddr-address-payload-bytes-promisedatasignature) +## Copyright -#### `api.submitTx(tx: Transaction): Promise` -Errors: `APIError`, `TxSendError` +----- +extra stuff -[Link to definition](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#apisubmittxtx-cbortransaction-promisehash32) ### Wallet query layer API From 0ea3b98b7bc8e85d297fe2f1bb34b586441a337e Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Mon, 23 Dec 2024 11:28:16 +0100 Subject: [PATCH 05/25] Removing extra section --- CIP-XXXX/README.md | 169 ++------------------------------------------- 1 file changed, 6 insertions(+), 163 deletions(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index cb9027d2cc..cd422203a7 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -367,7 +367,7 @@ Returns the reward addresses owned by the wallet. This can return multiple addre "request": { "type": "object", "properties": { - "tx": { "$ref": #/cip-116/Transaction }, + "tx": { "$ref": "#/cip-116/Transaction" }, "partialSign": { "type": "boolean" } }, "required": ["tx"] @@ -394,7 +394,7 @@ Only the portions of the witness set that were signed as a result of this call a "type": "object", "properties": { "addr": { "$ref": #/cip-116/Address }, - "payload": { "$ref": #/cip-116/ByteString } + "payload": { "$ref": "#/cip-116/ByteString" } }, "required": ["addr", "payload"] }, @@ -434,7 +434,7 @@ If the payment key for `addr` is not a P2Pk address then `DataSignError` will be "request": { "type": "object", "properties": { - "tx": { "$ref": #/cip-116/Transaction } + "tx": { "$ref": "#/cip-116/Transaction" } }, "required": ["tx"] }, @@ -452,6 +452,8 @@ As wallets should already have this ability, we allow dApps to request that a tr #### CIP-139 + + ### Appendix This appendix contains additional schemas for types that are used in the APIs. @@ -622,7 +624,7 @@ This section lists the possible errors the wallet connector may return. Each err ## Rationale: how does this CIP achieve its goals? -This CIP +??? ## Path to Active @@ -631,162 +633,3 @@ This CIP ## Copyright - ------ -extra stuff - - -### Wallet query layer API - -Upon successful connection via `cardano.{walletName}.enable()`, a javascript object we will refer to as `API` (type) / `api` (instance) is returned to the dApp with the following methods. -All methods should not require any user interaction as the user has already consented to the dApp reading information about the wallet's state when they agreed to `cardano.{walletName}.enable()`. - -#### Utxos - -##### `api.query.utxos.asset(asset_name: AssetName, minting_policy_hash: ScriptHash) : Promise` - -Get all UTxOs that contain some of the specified asset - -##### `api.query.utxos.transaction_hash(transaction_hash: TransactionHash) : Promise` - -Get all UTxOs produced by the transaction - -##### `api.query.utxos.address(address: Address) : Promise` - -Get all UTxOs present at the address - -##### `api.query.utxos.payment_credential(credential: Credential) : Promise` - -Get all UTxOs present at the addresses which use the payment credential - -##### `api.query.utxos.stake_credential(reward_address: RewardAddress) : Promise` - -Get all UTxOs present at the addresses which use the stake credential - -#### Block - -##### `api.query.block.number(u_int64: UInt64) : Promise` - -Get the block with the supplied block number - -##### `api.query.block.hash(block_hash: BlockHash) : Promise` - -Get the block with the supplied block hash - -#### Transaction - -##### `api.query.transaction.hash(transaction_hash: TransactionHash) : Promise` - -Get the transaction with the supplied transaction hash - -#### Transactions - -##### `api.query.transactions.block_number(u_int64: UInt64) : Promise` - -Get all transactions contained in the block with the supplied block number [] - -##### `api.query.transactions.block_hash(block_hash: BlockHash) : Promise` - -Get all transactions contained in the block with the supplied block hash - -#### Datum - -##### `api.query.datum.hash(data_hash: DataHash) : Promise` - -Get the datum that hashes to the supplied data hash - -#### Plutus Script - -##### `api.query.plutus_script.hash(script_hash: ScriptHash) : Promise` - -Get the plutus script that hashes to the supplied script hash - -#### Native Script - -##### `api.query.native_script.hash(script_hash: ScriptHash) : Promise` - -Get the native script that hashes to the supplied script hash - -#### Metadata - -##### `api.query.metadata.transaction_hash(transaction_hash: TransactionHash) : Promise` - -Get the metadata present on the transaction with the supplied transaction hash - -#### Protocol Parameters - -##### `api.query.protocol_parameters.latest() : Promise` - -Get the latest protocol parameters - -##### `api.query.protocol_parameters.epoch(u_int32: UInt32) : Promise` - -Get the protocol parameters at the supplied epoch number - -#### Votes - -##### `api.query.votes.cc_id(cc_hot_id: CCHotId) : Promise` - -Votes cast by the supplied cc credential - -##### `api.query.votes.spo_id(pool_pubkeyhash: PoolPubKeyHash) : Promise` - -Votes cast by the supplied stake pool operator - -##### `api.query.votes.drep_id(drep_id: DRepId) : Promise` - -Votes cast by the supplied DRep - -##### `api.query.votes.proposal_id(proposal_id: ProposalId) : Promise` - -Votes cast on the supplied proposal - -#### Drep - -##### `api.query.drep.all() : Promise` - -Get all the known DReps - -##### `api.query.drep.id(drep_id: DRepId) : Promise` - -Get a specific DRep by id - -##### `api.query.drep.stake_credential(reward_address: RewardAddress) : Promise` - -Get the DRep that the stake credential has delegated to - -#### Committee - -##### `api.query.committee.all() : Promise` - -Get all known committee members - -##### `api.query.committee.id(cc_hot_id: CCHotId) : Promise` - -Get a specific Committee member by id - -#### Pool - -##### `api.query.pool.all() : Promise` - -Get all known stake pools - -##### `api.query.pool.id(pool_pubkeyhash: PoolPubKeyHash) : Promise` - -Get a specific stake pool by id - -#### Proposal - -##### `api.query.proposal.all() : Promise` - -Get all known proposals - -##### `api.query.proposal.id(proposal_id: ProposalId) : Promise` - -Get a specific proposal by id - -#### Era - -##### `api.query.era.summary() : Promise` - -Get the start and end of each era along with parameters that can vary between hard forks From c2d2c90b121ae5ad862981880fe49fc0ff07c791 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Fri, 27 Dec 2024 13:36:01 +0100 Subject: [PATCH 06/25] Add versioning --- CIP-XXXX/README.md | 95 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index cd422203a7..0868eb16c7 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -10,13 +10,14 @@ Discussions: - https://github.com/cardano-foundation/cips/pulls/? Created: 2024-12-13 License: CC-BY-4.0 -Version: 0.0.0 +Version-Connection-API: 0.0.0 +Version-CIP-30-Extension: 0.0.0 --- ## Abstract -CIP-30 is the standard interface of communication between wallets and DApps. While this CIP has been instrumental in the development of dApps for Cardano, it also has some shortcomings that have been observed across several implementations. +CIP-30 is the standard interface of communication between wallets and dApps. While this CIP has been instrumental in the development of dApps for Cardano, it also has some shortcomings that have been observed across several implementations. We have identified and carried out two steps in the path to provide a better alternative to CIP-30: @@ -33,7 +34,7 @@ In this CIP we want to put these together, defining a wallet connector standard CIP-30 is a universally accepted web-based wallet standard for Cardano. It provides a minimalistic interface that, in principle, can be used to build almost any kind of Cardano dApp. However, the way dApp<->wallet interaction is defined leads to suboptimal dApp architecture due to CIP-30 limits. -[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses many limitations of CIP-30. In addition to the ones specified in the CPS, consider the following problems: +Consider the following problems: ### Use of CBOR representations @@ -61,12 +62,16 @@ A dApp tries to balance a transaction with UTxOs from the wallet that is not yet A transaction is passed for signing, but the wallet does not yet know about the UTxOs it spends, and thus refuses to sign it A transaction is sent to the network via the dApp backend (bypassing CIP-30 submit method) and is confirmed there, but the wallet still does not know about its consumed inputs, and thus returns outdated data. +### CPS-10 + +[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses several other limitations of CIP-30. In this CIP we try to solve some of the issues pointed out in the CPS. There are still some areas to improve on: things like the event listener API, and other potential improvements [should we list all the points we don't tackle here?] are intentionally left out of this CIP to prevent bloat of scope. We welcome future CIPs, or updates to this CIP to refine any limitation that is not tackled in this document. + ## Specification The goal of this CIP is to provide a better alternative to CIP-30 which supports full data wallet. Specifically we make the following contributions: -- A clear separation between the connection mechanism and the actual API offered by the wallet connector +- A clear separation between the connection mechanism and the different APIs offered by the wallet. - Using JSON for Cardano domain types instead of CBOR - Add a query layer API to enable a full data wallet - Define this in a transport agnostic way @@ -74,7 +79,7 @@ The goal of this CIP is to provide a better alternative to CIP-30 which supports In it's current state, CIP-30 defines it API through a specific transport layer, namely an injected Javascript object. In this CIP we want to be able to define an API without committing to a specific transport layer. Implementors of this API can choose to support this API through several transports such as: HTTP, an injected Javascript object, JSON-RPC etc. Furthermore, we want to use JSON-schema to clearly define the types that each method, or operation, expects to receive or returns. -To keep the specification abstract we will use the word "operation" to describe the actions supported by the API, these would map to "endpoints" for an HTTP implementation of the API, or to "methods" for an implementation based on an injected Javascript object. +To keep the specification abstract we will use the word "operation" to describe the actions supported by the API: these would map to "endpoints" for an HTTP implementation of the API, or to "methods" for an implementation based on an injected Javascript object. We will use the following schema to define operations: @@ -95,15 +100,15 @@ where `operation` will be the identifier for the operation, `request` and `respo We will reference several JSON-schemas throughout the document, these are: -- [cip-0116](link) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. [Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types] -- [cip-0139](link) which provides definitions for types used in the query layer +- [cip-116](link) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. [Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types] +- [cip-139](link) which provides definitions for types used in the query layer - [appendix](#appendix) in which we define schemas for types required by the connection API and the error types -We will use an identifier in the anchor to refer to the schema where each type is defined. For example, if we want to reference the `Transaction` type, as defined in CIP-0116 we will use the following schema reference `{ "$ref": "#/cip-0116/Transaction" }`. +We will use an identifier in the anchor to refer to the schema where each type is defined. For example, if we want to reference the `Transaction` type, as defined in CIP-116 we will use the following schema reference `{ "$ref": "#/cip-116/Transaction" }`. If an operation does not require any arguments as part of it's request, or does not return a meaningful response, we will represent this as an `{}` on the respective operation field. The arguments to an operation will always be represented as an object. If a field is not marked as `required`, then that argument is to be considered optional. -For each operation we will provide some details on how the implementation should behave. Note tht some of these are taken verbatim from CIP-30. +For each operation we will provide some details on how the implementation should behave. Note that some of these are taken verbatim from CIP-30. ### Connection API @@ -122,12 +127,20 @@ We start by defining the connection API. The role of this API is to provide gene } ``` -This is the entrypoint to start communication with the user's wallet. The wallet should request the user's permission to connect the web page to the user's wallet, and if permission has been granted, the APIs will be made available for the DApp to use. The wallet can choose to maintain a whitelist to not necessarily ask the user's permission every time access is requested, but this behavior is up to the wallet and should be transparent to web pages using this API. If a wallet is already connected this function should not request access a second time. +This is the entrypoint to start communication with the user's wallet. The wallet should request the user's permission to connect the web page to the user's wallet, and if permission has been granted, the APIs will be made available for the dApp to use. The wallet can choose to maintain a whitelist to not necessarily ask the user's permission every time access is requested, but this behavior is up to the wallet and should be transparent to web pages using this API. If a wallet is already connected this function should not request access a second time. + +Through the `extension` field, dApps can request a list of what functionality they expect as a list of CIP numbers (and optional versions) capturing those extensions. This is used as an extensibility mechanism to document what functionalities can be provided by the wallet interface. We will see later in this document examples of what such extensions might be and which functionalities they will enable. New functionalities can be introduced via additional CIPs and may be all or partially supported by wallets. + +When requesting the functionalities of a cip extension, dApps can optionally specify a version number for it. Every cip extension defined in the future, must also define a versioning scheme following SemVer. When the version argument is not specified, wallets should take that as the greater version they implement. In this context - and for the rest of this discussion - we will assume versions are ordered with the canonical ordering of SemVer. If the dApp requests a specific version of an extension, wallets can only accept the request if a version of the extension they implement has: -DApps can request a list of they expect as a list of CIP numbers capturing those extensions. This is used as an extensibility mechanism to document what functionalities can be provided by the wallet interface. We will see later in this document examples of what such extensions might be and which functionalities they will enable. New functionalities can be introduced via additional CIPs and may be all or partially supported by wallets. +- the same major value as the one requested by the dApp AND + - a greater minor value as the one requested by the dApp, OR + - an equal minor value AND + - a greater or equal patch value as the one requested by the dApp -DApps are expected to use this endpoint to perform an initial handshake and ensure that the wallet supports all their required functionalities. Note that it's possible for two extensions to be mutually incompatible (because they provide two conflicting features). While we may try to avoid this as much as possible while designing CIPs, it is also the responsibility of wallet providers to assess whether they can support a given combination of extensions, or not. Wallets should throw an error if either they do not support the required extension, or they deem the combination of extensions requested by the DApp to be incompatible. +If multiple versions satisfy these requirements, then wallets must return the greatest version amongst all candidate versions. +DApps are expected to use this endpoint to perform an initial handshake and ensure that the wallet supports all their required functionalities. Note that it's possible for two extensions to be mutually incompatible (because they provide two conflicting features). While we may try to avoid this as much as possible while designing CIPs, it is also the responsibility of wallet providers to assess whether they can support a given combination of extensions, or not. Wallets should throw an error with code `NotSatisfiable` if either they do not support the required extension, or they deem the combination of extensions requested by the dApp to be incompatible. In this case, it is up to the dApp to decide to retry with different requirements, or to give up on establishing a connection with the wallet. ##### IsEnabled @@ -156,7 +169,7 @@ Returns true if the dApp is already connected to the user's wallet, or if reques } ``` -A list of extensions supported by the wallet. Extensions may be requested by dApps on initialization. Some extensions may be mutually conflicting and this list does not thereby reflect what extensions will be enabled by the wallet. Yet it informs on what extensions are known and can be requested by dApps if needed. +A list of extensions and versions supported by the wallet. Extensions may be requested by dApps on initialization. Some extensions may be mutually conflicting and this list does not thereby reflect what extensions will be enabled by the wallet. Yet it informs on what extensions are known and can be requested by dApps if needed. Note that if a wallet supports multiple versions of the same CIP, then it must return each one of them as an element in the response. ##### Name @@ -185,6 +198,20 @@ A name for the wallet which can be used inside of the dApp for the purpose of as A URI image (e.g. data URI base64 or other) for img src for the wallet which can be used inside of the dApp for the purpose of asking the user which wallet they would like to connect with. +##### ApiVersion + +``` +{ + "operation": "apiVersion", + "request": {}, + "response": { "$ref": "#/appendix/SemVer" }, + "errors": [] +} +``` + +Returns the API version for the wallet connection API. This must correspond to the value of `Version-Connection-API` specified in this document, appropriately transformed into a `SemVer` object. + + ### Extension APIs The following section will define the APIs offered by extensions that can be requested through the `enable` operation. With a slight abuse of notation, we will define the operations defined in CIP-30, in the [Full API](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#full-api) as belonging to the `cip-30` extension. @@ -259,15 +286,15 @@ If amount is not supplied, this shall return a list of all UTXOs controlled by t The operation takes an amount parameter. (NOTE: some wallets may be ignoring the amount parameter, in which case it might be possible to call the function without it, but this behavior is not recommended!). Reasons why the amount parameter is required: -- Dapps must be motivated to understand what they are doing with the collateral, in case they decide to handle it manually. +- DApps must be motivated to understand what they are doing with the collateral, in case they decide to handle it manually. - Depending on the specific wallet implementation, requesting more collateral than necessarily might worsen the user experience with that dapp, requiring the wallet to make explicit wallet reorganisation when it is not necessary and can be avoided. -- If dapps don't understand how much collateral they actually need to make their transactions work - they are placing more user funds than necessary in risk. +- If dApps don't understand how much collateral they actually need to make their transactions work - they are placing more user funds than necessary in risk. -So requiring the amount parameter would be a by-spec behavior for a wallet. Not requiring it is possible, but not specified, so dapps should not rely on that and the behavior is not recommended. +So requiring the amount parameter would be a by-spec behavior for a wallet. Not requiring it is possible, but not specified, so dApps should not rely on that and the behavior is not recommended. -This shall return a list of one or more UTXOs controlled by the wallet that are required to reach AT LEAST the combined ADA value target specified in amount AND the best suitable to be used as collateral inputs for transactions with plutus script inputs (pure ADA-only utxos). If this cannot be attained, an APIError with code `NotSatisfiable` and an explanation of the blocking problem shall be returned. NOTE: wallets are free to return utxos that add up to a greater total ADA value than requested in the amount parameter, but wallets must never return any result where utxos would sum up to a smaller total ADA value, instead in a case like that an error must be returned. +This shall return a list of one or more UTXOs controlled by the wallet that are required to reach AT LEAST the combined ADA value target specified in amount AND the best suitable to be used as collateral inputs for transactions with plutus script inputs (pure ADA-only utxos). If this cannot be attained, an `APIError` with code `NotSatisfiable` and an explanation of the blocking problem shall be returned. NOTE: wallets are free to return utxos that add up to a greater total ADA value than requested in the amount parameter, but wallets must never return any result where utxos would sum up to a smaller total ADA value, instead in a case like that an error must be returned. The main point is to allow the wallet to encapsulate all the logic required to handle, maintain, and create (possibly on-demand) the UTXOs suitable for collateral inputs. For example, whenever attempting to create a plutus-input transaction the dapp might encounter a case when the set of all user UTXOs don't have any pure entries at all, which are required for the collateral, in which case the dapp itself is forced to try and handle the creation of the suitable entries by itself. If a wallet implements this function it allows the dapp to not care whether the suitable utxos exist among all utxos, or whether they have been stored in a separate address chain (see #104), or whether they have to be created at the moment on-demand - the wallet guarantees that the dapp will receive enough utxos to cover the requested amount, or get an error in case it is technically impossible to get collateral in the wallet (e.g. user does not have enough ADA at all). @@ -453,6 +480,11 @@ As wallets should already have this ability, we allow dApps to request that a tr +### Versioning + +In this CIP we are defining two different APIs: the connection API for wallets, and the CIP-30 [maybe this should have another name to prevent confusion?] extension which enables an own-data wallet. These two are separate components, at the top of this document there is a table with separate entries for the versions of the connection API and CIP-30 Extension respectively. + +While the CIP is in preparation, these versions shall be set to `0.0.0`. The moment this CIP is merged the versions should be set to `1.0.0`, and all implementations should consider that the current version. Any changes to the API should come in form of PRs to this CIP. Every PR must update at least one of the two versions in accordance to SemVer. ### Appendix @@ -476,6 +508,9 @@ This appendix contains additional schemas for types that are used in the APIs. "properties": { "cip": { "type": "number" + }, + "version: { + "$ref": "#/appendix/SemVer" } }, "required": ["cip"], @@ -487,7 +522,7 @@ This appendix contains additional schemas for types that are used in the APIs. } ``` -An extension is an object with a single field "cip" that describes a CIP number extending the API. For example: +An extension is an object with a "cip" field that describes a CIP number extending the API, and an optional version specified according to SemVer. For example: ``` { "cip": 30 } @@ -520,6 +555,30 @@ An extension is an object with a single field "cip" that describes a CIP number An object representing some data that has been signed. It contains 2 fields: `signature` which contains the signed data, and `key` which contains the derived Ed25519 PubKey used to sign the data. +##### SemVer + +``` +{ + "type": "object", + "title": "SemVer", + "properties": { + "major": { + "title": "Major", + "type": "number", + }, + "minor": { + "title": "Minor", + "type": "number", + }, + "patch": { + "title": "Patch", + "type": "number", + } + }, + "required": ["major", "minor", "patch"], +} +``` + #### Errors This section lists the possible errors the wallet connector may return. Each error is specified by an error code, and an optional info string describing the cause of the error. Below each error we list names for all the error codes, and a brief description of when they should be used. Other than when the spec dictates the use of a specific error code, wallets can choose the error code they deem more applicable to the situation. Wallets can also extend these errors with additional codes should they feel the need to. From 1b0c64d9c110d0e9dac576e0e895bb1096f738fd Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Mon, 30 Dec 2024 17:37:35 +0100 Subject: [PATCH 07/25] Minor refactors --- CIP-XXXX/README.md | 79 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index 0868eb16c7..f490ce2a21 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -74,6 +74,7 @@ The goal of this CIP is to provide a better alternative to CIP-30 which supports - A clear separation between the connection mechanism and the different APIs offered by the wallet. - Using JSON for Cardano domain types instead of CBOR - Add a query layer API to enable a full data wallet +- Add versioning support to the extension API - Define this in a transport agnostic way In it's current state, CIP-30 defines it API through a specific transport layer, namely an injected Javascript object. @@ -97,8 +98,9 @@ We will use the following schema to define operations: ``` where `operation` will be the identifier for the operation, `request` and `response` will be the JSON-schemas for the request and response types respectively, and `errors` will be a list of schemas for the errors that the operation may raise. +We do not add an explicit scope to operation names, we do however encourage transport-specific implementations of this API to pick the scoping structure that makes more sense to them. -We will reference several JSON-schemas throughout the document, these are: +We will reference several JSON schemas throughout the document, these are: - [cip-116](link) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. [Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types] - [cip-139](link) which provides definitions for types used in the query layer @@ -219,6 +221,12 @@ We will also define the `cip-139` extension which enables wallet to use the Univ A wallet which enables both the `cip-30` and `cip-139` extension would then be considered a full-data wallet. +`Note`: Several of the endpoints offered by the extension APIs, are there to query some on-chain resource. Unless explicitly specified, wallets are always free to omit or add some of the resources returned. +While it may sound confusing to allow this behavior, the intention is for wallets to be able to track and reconcile some local information, even if it is not necessarily available on-chain. +An example where this caveat becomes quite useful, is with *transaction chaining*. When a wallet supports that they may allow the user to submit several transactions which depend on each other, +without having to wait for each one to be approved by other nodes. When a wallet does that, it will mark some UTxOs internally as *spent*, and will avoid returning them in a `getUtxos` query, for example. +Wallets are in charge of keeping their internal state in sync with the results of the various queries that different extensions support. + Future CIPs can add more extensions to the supported list. #### CIP-30 @@ -479,12 +487,11 @@ As wallets should already have this ability, we allow dApps to request that a tr #### CIP-139 - ### Versioning In this CIP we are defining two different APIs: the connection API for wallets, and the CIP-30 [maybe this should have another name to prevent confusion?] extension which enables an own-data wallet. These two are separate components, at the top of this document there is a table with separate entries for the versions of the connection API and CIP-30 Extension respectively. -While the CIP is in preparation, these versions shall be set to `0.0.0`. The moment this CIP is merged the versions should be set to `1.0.0`, and all implementations should consider that the current version. Any changes to the API should come in form of PRs to this CIP. Every PR must update at least one of the two versions in accordance to SemVer. +While the CIP is in preparation, these versions shall be set to `0.0.0`. The moment this CIP is merged the versions shall be set to `1.0.0`, and all implementations should consider that the current version. Any changes to either API should come in form of PRs to this CIP. ### Appendix @@ -681,14 +688,74 @@ This section lists the possible errors the wallet connector may return. Each err - `ProofGeneration`: (1) User has accepted the transaction sign, but the wallet was unable to sign the transaction (e.g. not having some of the private keys). - `UserDeclined`: (2) User declined to sign the transaction. + +#### Transport specific connectors + +While this CIP attempts to define an API in a transport agnostic way, implementations will be forced to pick a specific transport. In the spec we have not given specifics on how to +namespace and generally structure the api in an implementation. This is both because details depend on the underlying transport that is chosen to implement the API, but also because +we wanted to make backwards compatibility with the original CIP-30 proposal as easy as possible. + +Each transport specific implementation will make a choice on how to namespace access to the operations. In the following we give a description of how this should work for an implementation +using an injected javascript object. Support for different transports can be added to this CIP in form of PRs. + +##### Injected Javascript Object + +In this spec we define how to provide access to the operations defined in this CIP on an injected javascript object. +We aim to define this in a way that is backwards compatible with existing CIP-30 implementations. + +In order to initiate communication from webpages to a user's Cardano wallet, the wallet must provide the following javascript API to the webpage. +A shared, namespaced `cardano` object must be injected into the page if it did not exist already. Each wallet implementing this standard must then create a field in this object with a name unique to each wallet containing a wallet object implementing the connection API. + +Upon successful connection via `cardano.{walletName}.enable()`, a javascript object we will refer to as `api` is returned to the dApp. +If the user requested any extensions they will be available under `api.cipXXXX`, without any leading zeros. + +For example; CIP-0123's endpoints should be accessed by: + +``` +api.cip123.endpoint1() +api.cip123.endpoint2() +``` + +###### CIP-30 Backwards compatibility + +Given this definition, we can take an existing CIP-30 compliant wallet, and make it compatible with this CIP with a wrapper. + +This wrapper will be relatively small, but must still take care in unifying the differences between this CIP and CIP-30. There is a list of some notable differences to keep in mind: + +- JSON is used instead of CBOR. The wrapper must take care of translating arguments and results. +- This API has no pagination, while CIP-30 generally does. The wrapper can either implement pagination locally, or error and inform the user if they request it. +- In the original CIP-30, the `api` object returned has, on the top-level, the methods that we expect on `api.cip30`. The wrapper must take care to translate calls appropriately. +- CIP-30 allows for a situation where the user requests some extensions in the enable call, but despite the wallet not supporting those extensions, the `enable` call succeeds. This makes it so the dApps always have to check what extensions were actually enabled. In this CIP we don't allow that, so the wrapper must take care of calling `api.getExtension` after `cardano.{walletName}.enable` to check all required extensions are enabled, if that's not the case then throw an error. +- CIP-30 endpoints will return `null` in some situations where the request is correct, but not satisfiable. In this CIP we introduce an error code specifically for that. The wrapper will need to check some results for `null` and throw an appropriate error. +- Add an `api.apiVersion` method that returns the version for the connector + +Implementing this wrapper is out of scope of this CIP, +but we welcome any effort in this direction, as it would make transitioning to this CIP easier for most wallets. + + ## Rationale: how does this CIP achieve its goals? -??? +The goal of this CIP is to define the standard for a new wallet connector. This connector improves on CIP-30, both by fixing some of the shortcomings that +have been identified over time, and by extending its capabilities to be able to perform more queries. + +We split the contributions of this CIP in two categories: + +- Improve CIP-30 + - Introducing a transport agnostic way to define the behavior of these APIs + - Separating the connection API from the different extension APIs the wallet can offer + - Using JSON for Cardano domain types instead of CBOR + - Making versioning explicit and adding support for specifying versions when enabling an extension + +- Universal Query Layer extension + - Adding a query layer extension API to enable a full data wallet + ## Path to Active -- ??? +- Implementing a wrapper that takes a CIP-30 compatible API and transforms it to be compatible with CIP-XXXX. +- This CIP depends on CIP-139 to be active, in particular wallets need to support the queries required by the `cip-139` extension. +- Two or more wallets implement support for this CIP. ## Copyright - +This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). From e0ba34a67f475b83adeda64e0f9ee0c3eda80ec3 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Fri, 3 Jan 2025 18:32:13 +0100 Subject: [PATCH 08/25] Add query layer API --- CIP-XXXX/README.md | 852 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 844 insertions(+), 8 deletions(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index f490ce2a21..9a2c17784f 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -64,7 +64,7 @@ A transaction is sent to the network via the dApp backend (bypassing CIP-30 subm ### CPS-10 -[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses several other limitations of CIP-30. In this CIP we try to solve some of the issues pointed out in the CPS. There are still some areas to improve on: things like the event listener API, and other potential improvements [should we list all the points we don't tackle here?] are intentionally left out of this CIP to prevent bloat of scope. We welcome future CIPs, or updates to this CIP to refine any limitation that is not tackled in this document. +[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses several other limitations of CIP-30. In this CIP we try to solve some of the issues pointed out in the CPS. There are still some areas to improve on: things like the event listener API, and other potential improvements *[should we list all the points we don't tackle here?]* are intentionally left out of this CIP to prevent bloat of scope. We welcome future CIPs, or updates to this CIP to refine any limitation that is not tackled in this document. ## Specification @@ -102,7 +102,7 @@ We do not add an explicit scope to operation names, we do however encourage tran We will reference several JSON schemas throughout the document, these are: -- [cip-116](link) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. [Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types] +- [cip-116](link) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. *[Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types]* - [cip-139](link) which provides definitions for types used in the query layer - [appendix](#appendix) in which we define schemas for types required by the connection API and the error types @@ -306,7 +306,7 @@ This shall return a list of one or more UTXOs controlled by the wallet that are The main point is to allow the wallet to encapsulate all the logic required to handle, maintain, and create (possibly on-demand) the UTXOs suitable for collateral inputs. For example, whenever attempting to create a plutus-input transaction the dapp might encounter a case when the set of all user UTXOs don't have any pure entries at all, which are required for the collateral, in which case the dapp itself is forced to try and handle the creation of the suitable entries by itself. If a wallet implements this function it allows the dapp to not care whether the suitable utxos exist among all utxos, or whether they have been stored in a separate address chain (see #104), or whether they have to be created at the moment on-demand - the wallet guarantees that the dapp will receive enough utxos to cover the requested amount, or get an error in case it is technically impossible to get collateral in the wallet (e.g. user does not have enough ADA at all). -[The spec says that amount should agreed to be max 5 ada, is this enforced? The formulation in the CIP does not seem to be too precise] +*[The spec says that amount should agreed to be max 5 ada, is this enforced? The formulation in the CIP does not seem to be too precise]* ##### GetBalance @@ -428,7 +428,7 @@ Only the portions of the witness set that were signed as a result of this call a "request": { "type": "object", "properties": { - "addr": { "$ref": #/cip-116/Address }, + "addr": { "$ref": "#/cip-116/Address" }, "payload": { "$ref": "#/cip-116/ByteString" } }, "required": ["addr", "payload"] @@ -441,7 +441,7 @@ Only the portions of the witness set that were signed as a result of this call a } ``` -[Is bytestring the correct type here?] +*[Is bytestring the correct type here?]* This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/README.md) for standardization/safety reasons. It allows the dApp to request the user to sign a payload conforming to said spec. The user's consent MUST be requested and the message to sign shown to the user. The payment key from `addr` will be used for base, enterprise and pointer addresses to determine the EdDSA25519 key used. The staking key will be used for reward addresses. This key will be used to sign the `COSE_Sign1`'s `Sig_structure` with the following headers set: @@ -459,7 +459,7 @@ If the payment key for `addr` is not a P2Pk address then `DataSignError` will be - `crv` (-1) - must be set to `Ed25519` (6) - `x` (-2) - must be set to the public key bytes of the key used to sign the `Sig_structure` -[What are these numbers appearing next to params? Copied them from cip-30 but not sure] +*[What are these numbers appearing next to params? Copied them from cip-30 but not sure]* ##### SubmitTx @@ -486,10 +486,846 @@ As wallets should already have this ability, we allow dApps to request that a tr #### CIP-139 +This section defines the API for the `Query Layer API` as defined in CIP-139. Enabling this extension, alongside the `cip-30` extension, would give you a full-data wallet. + +##### Utxos + +###### Asset + +``` +{ + "operation": "getUtxosByAsset", + "request": { + "type": "object", + "properties": { + "asset_name": { + "$ref": "#/cip-116/AssetName" + }, + "minting_policy_hash": { + "$ref": "#/cip-116/ScriptHash" + } + }, + "required": [ + "asset_name", + "minting_policy_hash" + ] + }, + "response": { + "type": "object", + "properties": { + "utxos": { + "type": "array", + "items": { + "$ref": "#/cip-116/TransactionUnspentOutput" + } + } + }, + "required": [ + "utxos" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all UTxOs that contain some of the specified asset. + +###### Transaction Hash + +``` +{ + "operation": "getUtxosByTransactionHash", + "request": { + "$ref": "#/cip-139/TransactionHash" + }, + "response": { + "type": "object", + "properties": { + "utxos": { + "type": "array", + "items": { + "$ref": "#/cip-116/TransactionUnspentOutput" + } + } + }, + "required": [ + "utxos" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all UTxOs produced by the transaction. + +###### Address + +``` +{ + "operation": "getUtxosByAddress", + "request": { + "$ref": "#/cip-116/Address" + }, + "response": { + "type": "object", + "properties": { + "utxos": { + "type": "array", + "items": { + "$ref": "#/cip-116/TransactionUnspentOutput" + } + } + }, + "required": [ + "utxos" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all UTxOs present at the address. + +###### Payment Credential + +``` +{ + "operation": "getUtxosByPaymentCredential", + "request": { + "$ref": "#/cip-116/Credential" + }, + "response": { + "type": "object", + "properties": { + "utxos": { + "type": "array", + "items": { + "$ref": "#/cip-116/TransactionUnspentOutput" + } + } + }, + "required": [ + "utxos" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all UTxOs present at the addresses which use the payment credential. + +###### Stake Credential + +``` +{ + "operation": "getUtxosByStakeCredential", + "request": { + "$ref": "#/cip-116/RewardAddress" + }, + "response": { + "type": "object", + "properties": { + "utxos": { + "type": "array", + "items": { + "$ref": "#/cip-116/TransactionUnspentOutput" + } + } + }, + "required": [ + "utxos" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all UTxOs present at the addresses which use the stake credential. + +##### Block + +###### Number + +``` +{ + "operation": "getBlockByNumber", + "request": { + "$ref": "#/cip-139/UInt64" + }, + "response": { + "$ref": "#/cip-116/Block" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the block with the supplied block number. + +###### Hash + +``` +{ + "operation": "getBlockByHash", + "request": { + "$ref": "#/cip-116/BlockHash" + }, + "response": { + "$ref": "#/cip-116/Block" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the block with the supplied block hash. + +##### Transaction + +###### Hash + +``` +{ + "operation": "getTransactionByHash", + "request": { + "$ref": "#/cip-139/TransactionHash" + }, + "response": { + "$ref": "#/cip-116/Transaction" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the transaction with the supplied transaction hash. + +###### Block Number + +``` +{ + "operation": "getTransactionByBlockNumber", + "request": { + "$ref": "#/cip-139/UInt64" + }, + "response": { + "type": "object", + "properties": { + "transactions": { + "type": "array", + "items": { + "$ref": "#/cip-116/Transaction" + } + } + }, + "required": [ + "transactions" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all transactions contained in the block with the supplied block number []. + +###### Block Hash + +``` +{ + "operation": "getTransactionByBlockHash", + "request": { + "$ref": "#/cip-116/BlockHash" + }, + "response": { + "type": "object", + "properties": { + "transactions": { + "type": "array", + "items": { + "$ref": "#/cip-116/Transaction" + } + } + }, + "required": [ + "transactions" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all transactions contained in the block with the supplied block hash. + +##### Datum + +###### Hash + +``` +{ + "operation": "getDatumByHash", + "request": { + "$ref": "#/cip-116/DataHash" + }, + "response": { + "$ref": "#/cip-116/PlutusData" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the datum that hashes to the supplied data hash. + +##### Plutus Script + +###### Hash + +``` +{ + "operation": "getPlutusScriptByHash", + "request": { + "$ref": "#/cip-116/ScriptHash" + }, + "response": { + "$ref": "#/cip-116/PlutusScript" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the plutus script that hashes to the supplied script hash. + +##### Native Script + +###### Hash + +``` +{ + "operation": "getNativeScriptByHash", + "request": { + "$ref": "#/cip-116/ScriptHash" + }, + "response": { + "$ref": "#/cip-116/NativeScript" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the native script that hashes to the supplied script hash. + +##### Metadata + +###### Transaction Hash + +``` +{ + "operation": "getMetadataByTransactionHash", + "request": { + "$ref": "#/cip-139/TransactionHash" + }, + "response": { + "$ref": "#/cip-116/TransactionMetadatum" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the metadata present on the transaction with the supplied transaction hash. + +##### Protocol Parameters + +###### Latest + +``` +{ + "operation": "getProtocolParametersByLatest", + "request": {}, + "response": { + "$ref": "#/cip-139/ProtocolParams" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the latest protocol parameters. + +###### Epoch + +``` +{ + "operation": "getProtocolParametersByEpoch", + "request": { + "$ref": "#/cip-139/UInt32" + }, + "response": { + "$ref": "#/cip-139/ProtocolParams" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the protocol parameters at the supplied epoch number. + +##### Votes + +###### Cc Id + +``` +{ + "operation": "getVotesByCcId", + "request": { + "$ref": "#/cip-139/CCHotId" + }, + "response": { + "type": "object", + "properties": { + "votes": { + "type": "array", + "items": { + "$ref": "#/cip-139/VoteInfo" + } + } + }, + "required": [ + "votes" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Votes cast by the supplied cc credential. + +###### Spo Id + +``` +{ + "operation": "getVotesBySpoId", + "request": { + "$ref": "#/cip-139/PoolPubKeyHash" + }, + "response": { + "type": "object", + "properties": { + "votes": { + "type": "array", + "items": { + "$ref": "#/cip-139/VoteInfo" + } + } + }, + "required": [ + "votes" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Votes cast by the supplied stake pool operator. + +###### Drep Id + +``` +{ + "operation": "getVotesByDrepId", + "request": { + "$ref": "#/cip-139/DRepId" + }, + "response": { + "type": "object", + "properties": { + "votes": { + "type": "array", + "items": { + "$ref": "#/cip-139/VoteInfo" + } + } + }, + "required": [ + "votes" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Votes cast by the supplied DRep. + +###### Proposal Id + +``` +{ + "operation": "getVotesByProposalId", + "request": { + "$ref": "#/cip-139/ProposalId" + }, + "response": { + "type": "object", + "properties": { + "votes": { + "type": "array", + "items": { + "$ref": "#/cip-139/VoteInfo" + } + } + }, + "required": [ + "votes" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Votes cast on the supplied proposal. + +##### Drep + +###### All + +``` +{ + "operation": "getAllDreps", + "request": {}, + "response": { + "type": "object", + "properties": { + "dreps": { + "type": "array", + "items": { + "$ref": "#/cip-139/DRepInfo" + } + } + }, + "required": [ + "dreps" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all the known DReps. + +###### Id + +``` +{ + "operation": "getDrepById", + "request": { + "$ref": "#/cip-139/DRepId" + }, + "response": { + "$ref": "#/cip-139/DRepInfo" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get a specific DRep by id. + +###### Stake Credential + +``` +{ + "operation": "getDrepByStakeCredential", + "request": { + "$ref": "#/cip-116/RewardAddress" + }, + "response": { + "$ref": "#/cip-139/DRepInfo" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the DRep that the stake credential has delegated to. + +##### Committee Member + +###### All + +``` +{ + "operation": "getAllCommitteeMembers", + "request": {}, + "response": { + "type": "object", + "properties": { + "cc_members": { + "type": "array", + "items": { + "$ref": "#/cip-139/CCMember" + } + } + }, + "required": [ + "cc_members" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all known committee members. + +###### Id + +``` +{ + "operation": "getCommitteeMemberById", + "request": { + "$ref": "#/cip-139/CCHotId" + }, + "response": { + "$ref": "#/cip-139/CCMember" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get a specific Committee member by id. + +##### Pool + +###### All + +``` +{ + "operation": "getAllPools", + "request": {}, + "response": { + "type": "object", + "properties": { + "pools": { + "type": "array", + "items": { + "$ref": "#/cip-139/Pool" + } + } + }, + "required": [ + "pools" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all known stake pools. + +###### Id + +``` +{ + "operation": "getPoolById", + "request": { + "$ref": "#/cip-139/PoolPubKeyHash" + }, + "response": { + "$ref": "#/cip-139/Pool" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get a specific stake pool by id. + +##### Proposal + +###### All + +``` +{ + "operation": "getAllProposals", + "request": {}, + "response": { + "type": "object", + "properties": { + "proposals": { + "type": "array", + "items": { + "$ref": "#/cip-139/Proposal" + } + } + }, + "required": [ + "proposals" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get all known proposals. + +###### Id + +``` +{ + "operation": "getProposalById", + "request": { + "$ref": "#/cip-139/ProposalId" + }, + "response": { + "$ref": "#/cip-139/Proposal" + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get a specific proposal by id. + +##### Era + +###### Summary + +``` +{ + "operation": "getEraBySummary", + "request": {}, + "response": { + "type": "object", + "properties": { + "summary": { + "type": "array", + "items": { + "$ref": "#/cip-139/EraSummary" + } + } + }, + "required": [ + "summary" + ] + }, + "errors": [ + { + "$ref": "#/appendix/APIError" + } + ] +} +``` + +Get the start and end of each era along with parameters that can vary between hard forks. + ### Versioning -In this CIP we are defining two different APIs: the connection API for wallets, and the CIP-30 [maybe this should have another name to prevent confusion?] extension which enables an own-data wallet. These two are separate components, at the top of this document there is a table with separate entries for the versions of the connection API and CIP-30 Extension respectively. +In this CIP we are defining two different APIs: the connection API for wallets, and the CIP-30 *[maybe this should have another name to prevent confusion?]* extension which enables an own-data wallet. These two are separate components, at the top of this document there is a table with separate entries for the versions of the connection API and CIP-30 Extension respectively. While the CIP is in preparation, these versions shall be set to `0.0.0`. The moment this CIP is merged the versions shall be set to `1.0.0`, and all implementations should consider that the current version. Any changes to either API should come in form of PRs to this CIP. @@ -610,7 +1446,7 @@ This section lists the possible errors the wallet connector may return. Each err } ``` -[Why are these negative? Seems arbitrary, is it too breaking to change them?] +*[Why are these negative? Seems arbitrary, is it too breaking to change them?]* - `InvalidRequest`: (-1) Inputs do not conform to this spec or are otherwise invalid. - `InternalError`: (-2) An error occurred during execution of this API call. From 419602dbd011beb16e4585e7dace6a4687f0f5cd Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 7 Jan 2025 10:57:05 +0100 Subject: [PATCH 09/25] Fix according to review --- CIP-XXXX/README.md | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index 9a2c17784f..2add60c86c 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -21,9 +21,9 @@ CIP-30 is the standard interface of communication between wallets and dApps. Whi We have identified and carried out two steps in the path to provide a better alternative to CIP-30: -- Defining a universal JSON encoding for Cardano domain types. CIP-30 requires CBOR encoding and decoding for data passed to and from the wallet, which is often an extra burden for the client. This problem is stated in [CPS-0011](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0011) and a potential solution is given in [CIP-0116](link). +- Defining a universal JSON encoding for Cardano domain types. CIP-30 requires CBOR encoding and decoding for data passed to and from the wallet, which is often an extra burden for the client. This problem is stated in [CPS-0011](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0011) and a potential solution is given in [CIP-0116](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116). -- Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012](link) and a potential solution is given in [CIP-0139](link). +- Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0012) and a potential solution is given in [CIP-0139](https://github.com/cardano-foundation/CIPs/pull/869). Finally, [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) defines the responsibilities for wallet connectors, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. @@ -64,8 +64,7 @@ A transaction is sent to the network via the dApp backend (bypassing CIP-30 subm ### CPS-10 -[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses several other limitations of CIP-30. In this CIP we try to solve some of the issues pointed out in the CPS. There are still some areas to improve on: things like the event listener API, and other potential improvements *[should we list all the points we don't tackle here?]* are intentionally left out of this CIP to prevent bloat of scope. We welcome future CIPs, or updates to this CIP to refine any limitation that is not tackled in this document. - +[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses several other limitations of CIP-30. In this CIP we try to solve the issues pointed out in that CPS. There are still some areas to improve on: things like the event listener API are intentionally left out of this CIP to prevent bloat of scope. We welcome future CIPs, or updates to this CIP to refine any limitation that is not tackled in this document. ## Specification @@ -77,7 +76,7 @@ The goal of this CIP is to provide a better alternative to CIP-30 which supports - Add versioning support to the extension API - Define this in a transport agnostic way -In it's current state, CIP-30 defines it API through a specific transport layer, namely an injected Javascript object. +In its current state, CIP-30 defines it API through a specific transport layer, namely an injected Javascript object. In this CIP we want to be able to define an API without committing to a specific transport layer. Implementors of this API can choose to support this API through several transports such as: HTTP, an injected Javascript object, JSON-RPC etc. Furthermore, we want to use JSON-schema to clearly define the types that each method, or operation, expects to receive or returns. To keep the specification abstract we will use the word "operation" to describe the actions supported by the API: these would map to "endpoints" for an HTTP implementation of the API, or to "methods" for an implementation based on an injected Javascript object. @@ -102,8 +101,8 @@ We do not add an explicit scope to operation names, we do however encourage tran We will reference several JSON schemas throughout the document, these are: -- [cip-116](link) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. *[Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types]* -- [cip-139](link) which provides definitions for types used in the query layer +- [cip-116](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. *[Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types]* +- [cip-139](https://github.com/cardano-foundation/CIPs/pull/869) which provides definitions for types used in the query layer - [appendix](#appendix) in which we define schemas for types required by the connection API and the error types We will use an identifier in the anchor to refer to the schema where each type is defined. For example, if we want to reference the `Transaction` type, as defined in CIP-116 we will use the following schema reference `{ "$ref": "#/cip-116/Transaction" }`. @@ -264,7 +263,12 @@ Returns the network id of the currently connected account. 0 is testnet and 1 is "amount": { "$ref": "#/cip-116/Value" } } }, - "response": { "$ref": "#/cip-116/TransactionUnspentOutput" }, + "response": { + "type": "array", + "items": { + "$ref": "#/cip-116/TransactionUnspentOutput" + } + }, "errors": [ { "$ref": "#/appendix/APIError" } ] @@ -285,7 +289,12 @@ If amount is not supplied, this shall return a list of all UTXOs controlled by t }, "required": ["amount"] }, - "response": { "$ref": "#/cip-116/TransactionUnspentOutput" }, + "response": { + "type": "array", + "items": { + "$ref": "#/cip-116/TransactionUnspentOutput" + } + }, "errors": [ { "$ref": "#/appendix/APIError" } ] @@ -306,8 +315,6 @@ This shall return a list of one or more UTXOs controlled by the wallet that are The main point is to allow the wallet to encapsulate all the logic required to handle, maintain, and create (possibly on-demand) the UTXOs suitable for collateral inputs. For example, whenever attempting to create a plutus-input transaction the dapp might encounter a case when the set of all user UTXOs don't have any pure entries at all, which are required for the collateral, in which case the dapp itself is forced to try and handle the creation of the suitable entries by itself. If a wallet implements this function it allows the dapp to not care whether the suitable utxos exist among all utxos, or whether they have been stored in a separate address chain (see #104), or whether they have to be created at the moment on-demand - the wallet guarantees that the dapp will receive enough utxos to cover the requested amount, or get an error in case it is technically impossible to get collateral in the wallet (e.g. user does not have enough ADA at all). -*[The spec says that amount should agreed to be max 5 ada, is this enforced? The formulation in the CIP does not seem to be too precise]* - ##### GetBalance @@ -333,7 +340,7 @@ Returns the total balance available of the wallet. This is the same as summing t "request": {}, "response": { "type": "array", - "items: { "$ref": "#/cip-116/Address" } + "items": { "$ref": "#/cip-116/Address" } }, "errors": [ { "$ref": "#/appendix/APIError" } @@ -351,7 +358,7 @@ Returns a list of all used (included in some on-chain transaction) addresses con "request": {}, "response": { "type": "array", - "items: { "$ref": "#/cip-116/Address" } + "items": { "$ref": "#/cip-116/Address" } }, "errors": [ { "$ref": "#/appendix/APIError" } @@ -384,7 +391,7 @@ Returns an address owned by the wallet that should be used as a change address t "request": {}, "response": { "type": "array", - "items: { "$ref": "#/cip-116/RewardAddress" } + "items": { "$ref": "#/cip-116/RewardAddress" } }, "errors": [ { "$ref": "#/appendix/APIError" } @@ -459,7 +466,6 @@ If the payment key for `addr` is not a P2Pk address then `DataSignError` will be - `crv` (-1) - must be set to `Ed25519` (6) - `x` (-2) - must be set to the public key bytes of the key used to sign the `Sig_structure` -*[What are these numbers appearing next to params? Copied them from cip-30 but not sure]* ##### SubmitTx @@ -1343,7 +1349,7 @@ This appendix contains additional schemas for types that are used in the APIs. "title": "Extensions", "properties": { "extensions": { - "type": "array" + "type": "array", "items": { { "type": "object", @@ -1446,8 +1452,6 @@ This section lists the possible errors the wallet connector may return. Each err } ``` -*[Why are these negative? Seems arbitrary, is it too breaking to change them?]* - - `InvalidRequest`: (-1) Inputs do not conform to this spec or are otherwise invalid. - `InternalError`: (-2) An error occurred during execution of this API call. - `Refused`: (-3) The request was refused due to lack of access - e.g. wallet disconnects. From 803b4d600c8c34a2eab694c6578ce9f999439795 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 7 Jan 2025 11:11:06 +0100 Subject: [PATCH 10/25] Remove CPS doc --- CPS-XXXX/README.md | 115 --------------------------------------------- 1 file changed, 115 deletions(-) delete mode 100644 CPS-XXXX/README.md diff --git a/CPS-XXXX/README.md b/CPS-XXXX/README.md deleted file mode 100644 index dccbe45a9b..0000000000 --- a/CPS-XXXX/README.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -CPS: ? -Title: Full-data wallet connector -Status: Open -Category: Tools -Authors: - - Giovanni Garufi -Proposed Solutions: [] -Discussions: - - https://github.com/cardano-foundation/cips/pulls/? -Created: YYYY-MM-DD ---- - -## Abstract - - -CIP-30 is the standard interface of communication between wallets and DApps. While this CIP has been instrumental in the development of dApps for Cardano, it also has some shortcomings that have been observed across several implementations. - -We have identified and carried out two steps in the path to provide a better alternative to CIP-30: - -- Defining a universal JSON encoding for Cardano domain types. CIP-30 requires CBOR encoding and decoding for data passed to and from the wallet, which is often an extra burden for the client. This problem is stated in [CPS-0011](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0011) and a potential solution is given in [CIP-0116](link). - -- Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012] and a potential solution is given in [CIP-????](link). - -[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) defines the responsibilities for wallet connector, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. -In this CPS we hope to explain why a full-data wallet connector would be useful, and how putting all these pieces together we can make an improvement over CIP-30. - -## Problem - - -CIP-30 is a universally accepted web-based wallet standard for Cardano. It provides a minimalistic interface that, in principle, can be used to build almost any kind of Cardano dApp. However, the way dApp<->wallet interaction is defined leads to suboptimal dApp architecture due to CIP-30 limits. - - -Consider the following problems: - -### Use of CBOR representations - -CIP-30 standard uses CBOR encoding for all data passed from the wallet, e.g. addresses and UTxOs. Interpreting this data within the app requires CBOR decoding functionality that is tedious to implement manually, and so users resort to using cardano-serialization-lib or its close alternative, cardano-multiplatform-lib, which both require loading a WebAssembly blob of >1M in size. - -For comparison, to start a new Web3 app on Ethereum there is no need to use a library for data serialization. It’s possible to interact with a provider object that is given by the wallet directly, although there are libraries to further simplify this. Using CBOR looks unnecessary for most dApps, given that JSON is a de-facto standard for web data serialization. - -### Limited scope of available queries - -Most dApps require interacting with scripts, which implies the need to query for available UTxOs locked at script addresses and other blockchain data. CIP-30 is intentionally limited in scope to management of UTxOs "owned" by the wallet itself. - -Some other useful queries, like getting delegation and reward info, stake pool info, transaction metadata or contents, and epoch data, are also outside of scope. - -As a result, dApp developers are forced to implement their own query layers on the backend side - which leads to one more problem - inconsistency between states of two query layers: - -### Inconsistency of Query Layers - -On Cardano, every running node has its own opinion on the set of currently unspent transaction outputs. Only eventual consistency is guaranteed. - -Any dApp that interacts with a CIP-30 wallet has to deal with the inconsistency between the local cardano-node-based query layer and the light wallet query layer, especially when dApp workflow involves sending multiple transactions with the wallet in quick succession. - -Thus, the goal of the developers is to ensure that the set of UTxOs available to the wallet and the set of UTxOs the backend cardano-node knows about are synchronized enough to not cause errors when a wallet or backend operations are performed. To give a few examples of potential issues, consider the following scenarios: - -A dApp tries to balance a transaction with UTxOs from the wallet that is not yet available in dApp backend's cardano node, causing an error response during execution units evaluation -A transaction is passed for signing, but the wallet does not yet know about the UTxOs it spends, and thus refuses to sign it -A transaction is sent to the network via the dApp backend (bypassing CIP-30 submit method) and is confirmed there, but the wallet still does not know about its consumed inputs, and thus returns outdated data. - -## Use cases - - -The use cases listed in [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md#use-cases), -which lists some use cases for wallet connectors, equally apply to this CPS as well. - -Ultimately, the problem we are trying to solve is the "two sources of truth" that exist when a dApp has to both query the wallet for its own UTxO state, and then query some other data provider (blockfrost, maestro, a local node) for the state of the blockchain. - -By giving the wallets direct control over the data-fetching API, we allow them to present an unified view of all the UTxOs, reducing the issues that currently happen because of wallet vs dApp UTxO contention, and making optimizations (i.e. transaction chaining) easier to implement and more robust. -This benefits both end users of the wallets, because it reduces the chance to build and submit transactions that will end up being phase-1 invalid, -and dApp developers by relieving them of having to deal with synchronization between the (local) wallet state and the (global) chain state. - -## Goals - - -- Define a CIP that extends CIP-30 to provide a tighter interaction between wallets and dApps by following the principles outlined in CPS-0010. - -- Build upon the work done in CIP-0116 and CIP-XXXX to offer a full transaction building API based on JSON instead of CBOR, and utilizing the query layer spec to fetch data from the blockchain. - -- Provide a simple and unified view of wallet and blockchain data to dApps to prevent many of the pitfalls described above. - -## Open Questions - - - -### Translating CIP-30 API - -There are some choices that will need to be done while translating the CIP-30 API to JSON. The types defined in [CIP-0116](./link) should provide almost all that is required, but types for errors, and other domain types used by CIP-30 will need to be added as well. -Furthermore, CIP-30 specifies options for pagination. While useful in practice, pagination has turned out to be complex to implement properly and is not supported in [CIP-XXXX](./). CIP authors should decide wether to attempt to support the pagination from CIP-30 or to drop it completely. - -### Other CIP-30 improvements - -There are a few other issues with CIP-30 that are raised in CPS-0010. Since this CPS is advocating for a replacement to CIP-30, it would make sense to resolve some of those issues. However, since the update we are advocating for is already quite substantial, an argument can also be made to delay further changes to future and more specific CIPs. - -### Transaction building API - -By revamping CIP-30 to directly accept JSON rather than CBOR, we potentially relieve the dApp from having to use an external library to build transactions. Users can simply build and submit the JSON translation of the CDDL `Transaction` object. -It is currently not clear if it is worth adding a specialized API to the wallet to help with transaction building. The main argument for doing so is that often times when adding something to a transaction (like an input, or a mint) you need to also add something else (i.e. a witness). This makes building the transaction object directly more cumbersome and error prone, while an intermediate API could make this process more straightforward. - -However, APIs for transaction building also come in many flavors: there are prominent examples both of "declarative APIs", that allow building the transaction by specifying a set of constraints that the transaction must respect, -and the "imperative API", that allows building a transaction object directly. These two APIs don't necessarily rule each other out: -some implementations mix the two through input or transaction builders. - -The CIP authors should decide if they want to add this interface to the CIP directly, or perhaps leave it as future work. -Should a transaction building API be added, our recommendation would be to aim to make it as close as possible with -[cardano-serialization-lib](https://github.com/Emurgo/cardano-serialization-lib) which is widely used in the ecosystem and would be easy to adopt by many wallets. - --------- - - From 4f637f1a5fa76510967017ecf41d32a0d9f4132a Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 7 Jan 2025 17:04:27 +0100 Subject: [PATCH 11/25] Update CIP-XXXX/README.md Co-authored-by: Ryan --- CIP-XXXX/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index 2add60c86c..4354d18346 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -26,7 +26,7 @@ We have identified and carried out two steps in the path to provide a better alt - Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0012) and a potential solution is given in [CIP-0139](https://github.com/cardano-foundation/CIPs/pull/869). -Finally, [CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) defines the responsibilities for wallet connectors, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. +Finally, [CPS-0010](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md) defines the responsibilities for wallet connectors, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. In this CIP we want to put these together, defining a wallet connector standard for a full-data wallet. From a680c007f1bf66c555f0f666bb8eacb164cfb0ef Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 7 Jan 2025 17:04:42 +0100 Subject: [PATCH 12/25] Update CIP-XXXX/README.md Co-authored-by: Ryan --- CIP-XXXX/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index 4354d18346..66a18c1cb5 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -2,7 +2,6 @@ CIP: ? Title: Full-data wallet connector Status: Open -Category: Tools Authors: - Giovanni Garufi Implementors: [] From 6a11997fe80d9fb96a2a0020e82fdd5539e7a860 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 7 Jan 2025 17:04:52 +0100 Subject: [PATCH 13/25] Update CIP-XXXX/README.md Co-authored-by: Ryan --- CIP-XXXX/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index 66a18c1cb5..3b88343711 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -6,7 +6,7 @@ Authors: - Giovanni Garufi Implementors: [] Discussions: - - https://github.com/cardano-foundation/cips/pulls/? + - https://github.com/cardano-foundation/cips/pulls/957 Created: 2024-12-13 License: CC-BY-4.0 Version-Connection-API: 0.0.0 From e8659e65958eadf872f3e31b5f8190776ba4ebe5 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 7 Jan 2025 17:05:06 +0100 Subject: [PATCH 14/25] Update CIP-XXXX/README.md Co-authored-by: Ryan --- CIP-XXXX/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CIP-XXXX/README.md b/CIP-XXXX/README.md index 3b88343711..8482b7dfcc 100644 --- a/CIP-XXXX/README.md +++ b/CIP-XXXX/README.md @@ -1,7 +1,8 @@ --- CIP: ? Title: Full-data wallet connector -Status: Open +Category: Tools +Status: Proposed Authors: - Giovanni Garufi Implementors: [] From 6b4789f5896b81e900f95700423946e9812934e8 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Thu, 9 Jan 2025 12:38:24 +0100 Subject: [PATCH 15/25] Add CIP number and remove extra version headers from top-level table --- {CIP-XXXX => CIP-0144}/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) rename {CIP-XXXX => CIP-0144}/README.md (99%) diff --git a/CIP-XXXX/README.md b/CIP-0144/README.md similarity index 99% rename from CIP-XXXX/README.md rename to CIP-0144/README.md index 2add60c86c..1663b8d982 100644 --- a/CIP-XXXX/README.md +++ b/CIP-0144/README.md @@ -1,5 +1,5 @@ --- -CIP: ? +CIP: 144 Title: Full-data wallet connector Status: Open Category: Tools @@ -10,8 +10,6 @@ Discussions: - https://github.com/cardano-foundation/cips/pulls/? Created: 2024-12-13 License: CC-BY-4.0 -Version-Connection-API: 0.0.0 -Version-CIP-30-Extension: 0.0.0 --- ## Abstract @@ -448,8 +446,6 @@ Only the portions of the witness set that were signed as a result of this call a } ``` -*[Is bytestring the correct type here?]* - This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/README.md) for standardization/safety reasons. It allows the dApp to request the user to sign a payload conforming to said spec. The user's consent MUST be requested and the message to sign shown to the user. The payment key from `addr` will be used for base, enterprise and pointer addresses to determine the EdDSA25519 key used. The staking key will be used for reward addresses. This key will be used to sign the `COSE_Sign1`'s `Sig_structure` with the following headers set: - `alg` (1) - must be set to EdDSA (-8) @@ -1331,10 +1327,15 @@ Get the start and end of each era along with parameters that can vary between ha ### Versioning -In this CIP we are defining two different APIs: the connection API for wallets, and the CIP-30 *[maybe this should have another name to prevent confusion?]* extension which enables an own-data wallet. These two are separate components, at the top of this document there is a table with separate entries for the versions of the connection API and CIP-30 Extension respectively. +In this CIP we are defining two different APIs: the connection API for wallets, and the CIP-30 *[maybe this should have another name to prevent confusion?]* extension which enables an own-data wallet. These two are separate components, below there is a table with separate entries for the versions of the connection API and CIP-30 Extension respectively. While the CIP is in preparation, these versions shall be set to `0.0.0`. The moment this CIP is merged the versions shall be set to `1.0.0`, and all implementations should consider that the current version. Any changes to either API should come in form of PRs to this CIP. +--- +Version-Connection-API: 0.0.0 +Version-CIP-30-Extension: 0.0.0 +--- + ### Appendix This appendix contains additional schemas for types that are used in the APIs. From 1b4e5b36837d9f67a3cea8052962ea52319eaf69 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Thu, 9 Jan 2025 12:52:28 +0100 Subject: [PATCH 16/25] Fix verion table formatting --- CIP-0144/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index 68b400c87d..a65893bea8 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -1331,10 +1331,11 @@ In this CIP we are defining two different APIs: the connection API for wallets, While the CIP is in preparation, these versions shall be set to `0.0.0`. The moment this CIP is merged the versions shall be set to `1.0.0`, and all implementations should consider that the current version. Any changes to either API should come in form of PRs to this CIP. ---- -Version-Connection-API: 0.0.0 -Version-CIP-30-Extension: 0.0.0 ---- +| | | +| --- | --- | +| Version-Connection-API | 0.0.0 | +| Version-CIP-30-Extension | 0.0.0 | + ### Appendix From ba79708fcdaef3501603079c180507283a6d5416 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Thu, 9 Jan 2025 12:58:59 +0100 Subject: [PATCH 17/25] Add Solution-To tag --- CIP-0144/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index a65893bea8..c66525bdba 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -10,6 +10,7 @@ Discussions: - https://github.com/cardano-foundation/cips/pulls/957 Created: 2024-12-13 License: CC-BY-4.0 +Solution-To: CPS-0010 --- ## Abstract From 1be28e7904e0cbde8944631728e01aa14d10cd96 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 14 Jan 2025 09:22:50 +0100 Subject: [PATCH 18/25] Update CIP-0144/README.md Co-authored-by: Robert Phair --- CIP-0144/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index c66525bdba..4b22e85d95 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -1332,7 +1332,7 @@ In this CIP we are defining two different APIs: the connection API for wallets, While the CIP is in preparation, these versions shall be set to `0.0.0`. The moment this CIP is merged the versions shall be set to `1.0.0`, and all implementations should consider that the current version. Any changes to either API should come in form of PRs to this CIP. -| | | +| API | Version | | --- | --- | | Version-Connection-API | 0.0.0 | | Version-CIP-30-Extension | 0.0.0 | From 8040b5c3813e7c134172a77b2aaf339b55177786 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 14 Jan 2025 09:28:23 +0100 Subject: [PATCH 19/25] Split Path to active into two sections --- CIP-0144/README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index c66525bdba..3d4c9520d0 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -1595,9 +1595,15 @@ We split the contributions of this CIP in two categories: ## Path to Active -- Implementing a wrapper that takes a CIP-30 compatible API and transforms it to be compatible with CIP-XXXX. -- This CIP depends on CIP-139 to be active, in particular wallets need to support the queries required by the `cip-139` extension. -- Two or more wallets implement support for this CIP. +### Acceptance Criteria + +- [ ] There is at least one implementation for a CIP-30 compatibility wrapper as explained in the `CIP-30 Backwards compatibility` section +- [ ] Two or more wallets implement support for this CIP. + +### Implementation Plan + +- [ ] This CIP depends on CIP-139 to be active, in particular wallets need to support the queries required by the `cip-139` extension. +- [ ] Implement a wrapper that takes a CIP-30 compatible API and transforms it to be compatible with CIP-XXXX. ## Copyright From de26e3c17761ee373dbdc632fcde7edc7e8228c5 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 28 Jan 2025 09:25:55 +0100 Subject: [PATCH 20/25] Update CIP-0144/README.md Co-authored-by: Ryan --- CIP-0144/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index fc61c82093..1f8f263c81 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -83,7 +83,7 @@ To keep the specification abstract we will use the word "operation" to describe We will use the following schema to define operations: -``` +```json { "operation": { "type": "string" }, "request": { "type": "object" }, From 87cace9bd27b51c8b42f39ec1f679be87eb348b5 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Tue, 28 Jan 2025 09:26:07 +0100 Subject: [PATCH 21/25] Update CIP-0144/README.md Co-authored-by: Ryan --- CIP-0144/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index 1f8f263c81..be9d4105d7 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -100,7 +100,7 @@ We do not add an explicit scope to operation names, we do however encourage tran We will reference several JSON schemas throughout the document, these are: -- [cip-116](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. *[Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types]* +- [CIP-116 | Standard JSON encoding for Domain Types](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. *[Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types]* - [cip-139](https://github.com/cardano-foundation/CIPs/pull/869) which provides definitions for types used in the query layer - [appendix](#appendix) in which we define schemas for types required by the connection API and the error types From b58bfe13efeb11eade4baf58d8fcc9dcdc69dd9d Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Mon, 3 Feb 2025 18:59:57 +0100 Subject: [PATCH 22/25] Remove extensions and leave wallet connector API --- CIP-0144/README.md | 1414 +++----------------------------------------- 1 file changed, 79 insertions(+), 1335 deletions(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index be9d4105d7..faaac58ce9 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -1,6 +1,6 @@ --- CIP: 144 -Title: Full-data wallet connector +Title: Wallet Connector API Category: Tools Status: Proposed Authors: @@ -18,22 +18,15 @@ Solution-To: CPS-0010 CIP-30 is the standard interface of communication between wallets and dApps. While this CIP has been instrumental in the development of dApps for Cardano, it also has some shortcomings that have been observed across several implementations. -We have identified and carried out two steps in the path to provide a better alternative to CIP-30: - -- Defining a universal JSON encoding for Cardano domain types. CIP-30 requires CBOR encoding and decoding for data passed to and from the wallet, which is often an extra burden for the client. This problem is stated in [CPS-0011](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0011) and a potential solution is given in [CIP-0116](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116). - -- Defining a universal query layer. CIP-30 is only concerned with obtaining data regarding the wallet, this forces dApps to integrate with other tools to query general blockchain data. This problem is stated in [CPS-0012](https://github.com/cardano-foundation/CIPs/tree/master/CPS-0012) and a potential solution is given in [CIP-0139](https://github.com/cardano-foundation/CIPs/pull/869). - - -Finally, [CPS-0010](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md) defines the responsibilities for wallet connectors, and also introduces the vocabulary to distinguish between different kinds of wallets, based on the functionality they offer. - -In this CIP we want to put these together, defining a wallet connector standard for a full-data wallet. +[CPS-0010](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md) outlines some shortcomings in CIP-30. In this CIP we aid to address some of the issues pointed out by CPS-10: splitting up the connection API, from the functionality provided by the [full API](https://cips.cardano.org/cip/CIP-30#full-api), defining the API in a transport agnostic way and defining a versioning mechanism for the connection API and it's extensions. ## Motivation: why is this CIP necessary? CIP-30 is a universally accepted web-based wallet standard for Cardano. It provides a minimalistic interface that, in principle, can be used to build almost any kind of Cardano dApp. However, the way dApp<->wallet interaction is defined leads to suboptimal dApp architecture due to CIP-30 limits. -Consider the following problems: +### CPS-10 + +[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses several limitations of CIP-30. In this CIP we try to solve the issues pointed out in that CPS. There are still some areas to improve on: things like the event listener API are intentionally left out of this CIP to prevent bloat of scope. We welcome future CIPs, or updates to this CIP to refine any limitation that is not tackled in this document. ### Use of CBOR representations @@ -41,39 +34,16 @@ CIP-30 standard uses CBOR encoding for all data passed from the wallet, e.g. add For comparison, to start a new Web3 app on Ethereum there is no need to use a library for data serialization. It’s possible to interact with a provider object that is given by the wallet directly, although there are libraries to further simplify this. Using CBOR looks unnecessary for most dApps, given that JSON is a de-facto standard for web data serialization. -### Limited scope of available queries - -Most dApps require interacting with scripts, which implies the need to query for available UTxOs locked at script addresses and other blockchain data. CIP-30 is intentionally limited in scope to management of UTxOs "owned" by the wallet itself. - -Some other useful queries, like getting delegation and reward info, stake pool info, transaction metadata or contents, and epoch data, are also outside of scope. - -As a result, dApp developers are forced to implement their own query layers on the backend side - which leads to one more problem - inconsistency between states of two query layers: - -### Inconsistency of Query Layers - -On Cardano, every running node has its own opinion on the set of currently unspent transaction outputs. Only eventual consistency is guaranteed. - -Any dApp that interacts with a CIP-30 wallet has to deal with the inconsistency between the local cardano-node-based query layer and the light wallet query layer, especially when dApp workflow involves sending multiple transactions with the wallet in quick succession. - -Thus, the goal of the developers is to ensure that the set of UTxOs available to the wallet and the set of UTxOs the backend cardano-node knows about are synchronized enough to not cause errors when a wallet or backend operations are performed. To give a few examples of potential issues, consider the following scenarios: - -A dApp tries to balance a transaction with UTxOs from the wallet that is not yet available in dApp backend's cardano node, causing an error response during execution units evaluation -A transaction is passed for signing, but the wallet does not yet know about the UTxOs it spends, and thus refuses to sign it -A transaction is sent to the network via the dApp backend (bypassing CIP-30 submit method) and is confirmed there, but the wallet still does not know about its consumed inputs, and thus returns outdated data. - -### CPS-10 - -[CPS-0010](https://github.com/Ryun1/CIPs/blob/cps-wallet-connector/CPS-0010/README.md) discusses several other limitations of CIP-30. In this CIP we try to solve the issues pointed out in that CPS. There are still some areas to improve on: things like the event listener API are intentionally left out of this CIP to prevent bloat of scope. We welcome future CIPs, or updates to this CIP to refine any limitation that is not tackled in this document. +In this work we build on the work carried out in [CIP-0116](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116) defining a universal JSON encoding for Cardano domain types. ## Specification -The goal of this CIP is to provide a better alternative to CIP-30 which supports full data wallet. Specifically we make the following contributions: +The goal of this CIP is to provide a better alternative to CIP-30, providing a base on which we can define a CIP-30 compatible API, and further extensions in the future. Specifically we make the following contributions: - A clear separation between the connection mechanism and the different APIs offered by the wallet. - Using JSON for Cardano domain types instead of CBOR -- Add a query layer API to enable a full data wallet - Add versioning support to the extension API -- Define this in a transport agnostic way +- Define the API in a transport agnostic way In its current state, CIP-30 defines it API through a specific transport layer, namely an injected Javascript object. In this CIP we want to be able to define an API without committing to a specific transport layer. Implementors of this API can choose to support this API through several transports such as: HTTP, an injected Javascript object, JSON-RPC etc. @@ -101,7 +71,6 @@ We do not add an explicit scope to operation names, we do however encourage tran We will reference several JSON schemas throughout the document, these are: - [CIP-116 | Standard JSON encoding for Domain Types](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. *[Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types]* -- [cip-139](https://github.com/cardano-foundation/CIPs/pull/869) which provides definitions for types used in the query layer - [appendix](#appendix) in which we define schemas for types required by the connection API and the error types We will use an identifier in the anchor to refer to the schema where each type is defined. For example, if we want to reference the `Transaction` type, as defined in CIP-116 we will use the following schema reference `{ "$ref": "#/cip-116/Transaction" }`. @@ -112,7 +81,7 @@ For each operation we will provide some details on how the implementation should ### Connection API -We start by defining the connection API. The role of this API is to provide generic information about the wallet and to allow the user to opt into the functionalities that they want the wallet to provide. +The role of the connection API is to provide generic information about the wallet and to allow the user to opt into the functionalities that they want the wallet to provide. ##### Enable @@ -211,1247 +180,105 @@ A URI image (e.g. data URI base64 or other) for img src for the wallet which can Returns the API version for the wallet connection API. This must correspond to the value of `Version-Connection-API` specified in this document, appropriately transformed into a `SemVer` object. +### Versioning -### Extension APIs - -The following section will define the APIs offered by extensions that can be requested through the `enable` operation. With a slight abuse of notation, we will define the operations defined in CIP-30, in the [Full API](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030#full-api) as belonging to the `cip-30` extension. -We will also define the `cip-139` extension which enables wallet to use the Universal Query Layer API. - -A wallet which enables both the `cip-30` and `cip-139` extension would then be considered a full-data wallet. - -`Note`: Several of the endpoints offered by the extension APIs, are there to query some on-chain resource. Unless explicitly specified, wallets are always free to omit or add some of the resources returned. -While it may sound confusing to allow this behavior, the intention is for wallets to be able to track and reconcile some local information, even if it is not necessarily available on-chain. -An example where this caveat becomes quite useful, is with *transaction chaining*. When a wallet supports that they may allow the user to submit several transactions which depend on each other, -without having to wait for each one to be approved by other nodes. When a wallet does that, it will mark some UTxOs internally as *spent*, and will avoid returning them in a `getUtxos` query, for example. -Wallets are in charge of keeping their internal state in sync with the results of the various queries that different extensions support. - -Future CIPs can add more extensions to the supported list. - -#### CIP-30 - -This section defines the API for the `Full API` part of CIP-30. Enabling only this extension would give you an own-data wallet, which is essentially equivalent to what CIP-30 gives us today. - -Operations that sign data MUST require additional user consent before being performed. Additional details will be specified in the section for each operation. -Note that this API differs slightly from CIP-30 Full API in that it drops an endpoint which is not required (`getExtensions`) and removes the option for pagination. - -The removal of pagination follows the same [reasons](https://github.com/klntsky/CIPs/blob/klntsky/query-layer-cip/CIP-XXXX/README.md#pagination) pointed out in CIP-0139. In summary: pagination, while desirable, introduces some complications with the consistency of the returned results. We decide to drop it to keep the implementation as simple as possible, but welcome future CIPs to address this. +In this CIP we define a semantic versioning (SemVer) scheme that will be used by the connection API. Extensions defined in other CIPs (e.g. [CIP-XXX | Own data wallet](link)) must follow the same versioning schema. -##### GetNetworkId +While the CIP is in preparation, the version shall be set to `0.0.0`. The moment this CIP is merged the version shall be set to `1.0.0`, and all implementations should consider that the current version. Any changes to the connection API should come in form of PRs to this CIP. -``` -{ - "operation": "getNetworkId", - "request": {}, - "response": { "type": "number" }, - "errors": [ - { "$ref": "#/appendix/APIError" } - ] -} -``` +| API | Version | +| --- | --- | +| Version-Connection-API | 0.0.0 | -Returns the network id of the currently connected account. 0 is testnet and 1 is mainnet but other networks can possibly be returned by wallets. Those other network ID values are not governed by this document. This result will stay the same unless the connected account has changed. -##### GetUtxos +### Appendix -``` -{ - "operation": "getUtxos", - "request": { - "type": "object", - "properties": { - "amount": { "$ref": "#/cip-116/Value" } - } - }, - "response": { - "type": "array", - "items": { - "$ref": "#/cip-116/TransactionUnspentOutput" - } - }, - "errors": [ - { "$ref": "#/appendix/APIError" } - ] -} -``` +This appendix contains additional schemas for types that are used in the APIs. -If amount is not supplied, this shall return a list of all UTXOs controlled by the wallet. If amount is present, this request shall be limited to just the UTXOs that are required to reach the combined ADA/multiasset value target specified in amount, and if this cannot be attained, an `APIError` with error code `NotSatisfiable` (and optionally an info string) must be returned. +#### Connection API Data Types -##### GetCollateral +##### Extensions ``` { - "operation": "getCollateral", - "request": { - "type": "object", - "properties": { - "amount": { "type": "number" } - }, - "required": ["amount"] - }, - "response": { - "type": "array", - "items": { - "$ref": "#/cip-116/TransactionUnspentOutput" + "type": "object", + "title": "Extensions", + "properties": { + "extensions": { + "type": "array", + "items": { + { + "type": "object", + "title": "Extension", + "properties": { + "cip": { + "type": "number" + }, + "version: { + "$ref": "#/appendix/SemVer" + } + }, + "required": ["cip"], + } + } } }, - "errors": [ - { "$ref": "#/appendix/APIError" } - ] -} -``` - -The operation takes an amount parameter. (NOTE: some wallets may be ignoring the amount parameter, in which case it might be possible to call the function without it, but this behavior is not recommended!). Reasons why the amount parameter is required: - -- DApps must be motivated to understand what they are doing with the collateral, in case they decide to handle it manually. - -- Depending on the specific wallet implementation, requesting more collateral than necessarily might worsen the user experience with that dapp, requiring the wallet to make explicit wallet reorganisation when it is not necessary and can be avoided. - -- If dApps don't understand how much collateral they actually need to make their transactions work - they are placing more user funds than necessary in risk. - -So requiring the amount parameter would be a by-spec behavior for a wallet. Not requiring it is possible, but not specified, so dApps should not rely on that and the behavior is not recommended. - -This shall return a list of one or more UTXOs controlled by the wallet that are required to reach AT LEAST the combined ADA value target specified in amount AND the best suitable to be used as collateral inputs for transactions with plutus script inputs (pure ADA-only utxos). If this cannot be attained, an `APIError` with code `NotSatisfiable` and an explanation of the blocking problem shall be returned. NOTE: wallets are free to return utxos that add up to a greater total ADA value than requested in the amount parameter, but wallets must never return any result where utxos would sum up to a smaller total ADA value, instead in a case like that an error must be returned. - -The main point is to allow the wallet to encapsulate all the logic required to handle, maintain, and create (possibly on-demand) the UTXOs suitable for collateral inputs. For example, whenever attempting to create a plutus-input transaction the dapp might encounter a case when the set of all user UTXOs don't have any pure entries at all, which are required for the collateral, in which case the dapp itself is forced to try and handle the creation of the suitable entries by itself. If a wallet implements this function it allows the dapp to not care whether the suitable utxos exist among all utxos, or whether they have been stored in a separate address chain (see #104), or whether they have to be created at the moment on-demand - the wallet guarantees that the dapp will receive enough utxos to cover the requested amount, or get an error in case it is technically impossible to get collateral in the wallet (e.g. user does not have enough ADA at all). - - -##### GetBalance - -``` -{ - "operation": "getBalance", - "request": {}, - "response": { "$ref": "#/cip-116/Value" }, - "errors": [ - { "$ref": "#/appendix/APIError" } - ] -} -``` - -Returns the total balance available of the wallet. This is the same as summing the results of api.getUtxos(), but it is both useful to dApps and likely already maintained by the implementing wallet in a more efficient manner so it has been included in the API as well. - - -##### GetUsedAddresses - -``` -{ - "operation": "getUsedAddresses", - "request": {}, - "response": { - "type": "array", - "items": { "$ref": "#/cip-116/Address" } - }, - "errors": [ - { "$ref": "#/appendix/APIError" } - ] -} -``` - -Returns a list of all used (included in some on-chain transaction) addresses controlled by the wallet. - -##### GetUnusedAddresses - -``` -{ - "operation": "getUnusedAddresses", - "request": {}, - "response": { - "type": "array", - "items": { "$ref": "#/cip-116/Address" } - }, - "errors": [ - { "$ref": "#/appendix/APIError" } - ] -} -``` - -Returns a list of unused addresses controlled by the wallet. - -##### GetChangeAddress - -``` -{ - "operation": "getChangeAddress", - "request": {}, - "response": { "$ref": "#/cip-116/Address" }, - "errors": [ - { "$ref": "#/appendix/APIError" } - ] -} -``` - -Returns an address owned by the wallet that should be used as a change address to return leftover assets during transaction creation back to the connected wallet. This can be used as a generic receive address as well. - -##### GetRewardAddresses - -``` -{ - "operation": "getRewardAddresses", - "request": {}, - "response": { - "type": "array", - "items": { "$ref": "#/cip-116/RewardAddress" } - }, - "errors": [ - { "$ref": "#/appendix/APIError" } - ] + "required": ["extensions"], } ``` -Returns the reward addresses owned by the wallet. This can return multiple addresses e.g. CIP-0018. - -##### SignTx +An extension is an object with a "cip" field that describes a CIP number extending the API, and an optional version specified according to SemVer. For example: ``` -{ - "operation": "signTx", - "request": { - "type": "object", - "properties": { - "tx": { "$ref": "#/cip-116/Transaction" }, - "partialSign": { "type": "boolean" } - }, - "required": ["tx"] - }, - "response": { "$ref": "#/cip-116/TransactionWitnessSet" }, - "errors": [ - { "$ref": "#/appendix/APIError" }, - { "$ref": "#/appendix/TxSignError" } - ] -} +{ "cip": 30 } ``` -Requests that a user sign the unsigned portions of the supplied transaction. The wallet MUST ask the user for permission, and if given, try to sign the supplied transaction. If partialSign is true, the wallet only tries to sign what it can. If partialSign is false, or not supplied, and the wallet could not sign the entire transaction, `TxSignError` shall be returned with a `ProofGeneration` error code. Likewise if the user declined in either case it shall return the same error with a `UserDeclined` error code. - -Only the portions of the witness set that were signed as a result of this call are returned to encourage dApps to verify the contents returned by this endpoint while building the final transaction. - -##### SignData +##### SemVer ``` { - "operation": "signData", - "request": { - "type": "object", - "properties": { - "addr": { "$ref": "#/cip-116/Address" }, - "payload": { "$ref": "#/cip-116/ByteString" } + "type": "object", + "title": "SemVer", + "properties": { + "major": { + "title": "Major", + "type": "number", }, - "required": ["addr", "payload"] - }, - "response": { "$ref": "#/appendix/DataSignature" }, - "errors": [ - { "$ref": "#/appendix/APIError" }, - { "$ref": "#/appendix/DataSignError" } - ] -} -``` - -This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/README.md) for standardization/safety reasons. It allows the dApp to request the user to sign a payload conforming to said spec. The user's consent MUST be requested and the message to sign shown to the user. The payment key from `addr` will be used for base, enterprise and pointer addresses to determine the EdDSA25519 key used. The staking key will be used for reward addresses. This key will be used to sign the `COSE_Sign1`'s `Sig_structure` with the following headers set: - -- `alg` (1) - must be set to EdDSA (-8) -- `kid` (4) - Optional, if present must be set to the same value as in the COSE_key specified below. It is recommended to be set to the same value as in the "address" header. -- `address` - must be set to the raw binary bytes of the address as per the binary spec - -The payload is not hashed and no `external_aad` is used. - -If the payment key for `addr` is not a P2Pk address then `DataSignError` will be returned with error code `AddressNotPK`. `ProofGeneration` error code shall be returned if the wallet cannot generate a signature (i.e. the wallet does not own the requested payment private key), and `UserDeclined` will be returned if the user refuses the request. The return shall be a `DataSignature` with `signature` set to the hex-encoded bytes of the `COSE_Sign1` object specified above and `key` shall be the hex-encoded bytes of a `COSE_Key` structure with the following headers set: - -- `kty` (1) - must be set to `OKP` (1) -- `kid` (2) - Optional, if present must be set to the same value as in the `COSE_Sign1` specified above. -- `alg` (3) - must be set to `EdDSA` (-8) -- `crv` (-1) - must be set to `Ed25519` (6) -- `x` (-2) - must be set to the public key bytes of the key used to sign the `Sig_structure` - - -##### SubmitTx - -``` -{ - "operation": "submitTx", - "request": { - "type": "object", - "properties": { - "tx": { "$ref": "#/cip-116/Transaction" } + "minor": { + "title": "Minor", + "type": "number", }, - "required": ["tx"] + "patch": { + "title": "Patch", + "type": "number", + } }, - "response": { "$ref": "#/cip-116/TransactionHash" }, - "errors": [ - { "$ref": "#/appendix/APIError" }, - { "$ref": "#/appendix/TxSendError" } - ] + "required": ["major", "minor", "patch"], } ``` -As wallets should already have this ability, we allow dApps to request that a transaction be sent through it. If the wallet accepts the transaction and tries to send it, it shall return the transaction id for the dApp to track. The wallet is free to return the `TxSendError` with error code `Refused` if they do not wish to send it, or `Failure` if there was an error in sending it (e.g. preliminary checks failed on signatures). - - -#### CIP-139 - -This section defines the API for the `Query Layer API` as defined in CIP-139. Enabling this extension, alongside the `cip-30` extension, would give you a full-data wallet. - -##### Utxos - -###### Asset - -``` -{ - "operation": "getUtxosByAsset", - "request": { - "type": "object", - "properties": { - "asset_name": { - "$ref": "#/cip-116/AssetName" - }, - "minting_policy_hash": { - "$ref": "#/cip-116/ScriptHash" - } - }, - "required": [ - "asset_name", - "minting_policy_hash" - ] - }, - "response": { - "type": "object", - "properties": { - "utxos": { - "type": "array", - "items": { - "$ref": "#/cip-116/TransactionUnspentOutput" - } - } - }, - "required": [ - "utxos" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` +#### Errors -Get all UTxOs that contain some of the specified asset. +This section lists the possible errors the wallet connector may return. Each error is specified by an error code, and an optional info string describing the cause of the error. Below each error we list names for all the error codes, and a brief description of when they should be used. Other than when the spec dictates the use of a specific error code, wallets can choose the error code they deem more applicable to the situation. Wallets can also extend these errors with additional codes should they feel the need to. -###### Transaction Hash +##### APIError ``` { - "operation": "getUtxosByTransactionHash", - "request": { - "$ref": "#/cip-139/TransactionHash" - }, - "response": { - "type": "object", - "properties": { - "utxos": { - "type": "array", - "items": { - "$ref": "#/cip-116/TransactionUnspentOutput" - } - } + "type": "object", + "title": "APIError", + "properties": { + "code": { + "type": "number", + "title": "APIErrorCode" + "enum": [-1, -2, -3, -4, -5] }, - "required": [ - "utxos" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" + "info": { + "type": "string" } - ] -} -``` - -Get all UTxOs produced by the transaction. - -###### Address - -``` -{ - "operation": "getUtxosByAddress", - "request": { - "$ref": "#/cip-116/Address" }, - "response": { - "type": "object", - "properties": { - "utxos": { - "type": "array", - "items": { - "$ref": "#/cip-116/TransactionUnspentOutput" - } - } - }, - "required": [ - "utxos" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all UTxOs present at the address. - -###### Payment Credential - -``` -{ - "operation": "getUtxosByPaymentCredential", - "request": { - "$ref": "#/cip-116/Credential" - }, - "response": { - "type": "object", - "properties": { - "utxos": { - "type": "array", - "items": { - "$ref": "#/cip-116/TransactionUnspentOutput" - } - } - }, - "required": [ - "utxos" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all UTxOs present at the addresses which use the payment credential. - -###### Stake Credential - -``` -{ - "operation": "getUtxosByStakeCredential", - "request": { - "$ref": "#/cip-116/RewardAddress" - }, - "response": { - "type": "object", - "properties": { - "utxos": { - "type": "array", - "items": { - "$ref": "#/cip-116/TransactionUnspentOutput" - } - } - }, - "required": [ - "utxos" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all UTxOs present at the addresses which use the stake credential. - -##### Block - -###### Number - -``` -{ - "operation": "getBlockByNumber", - "request": { - "$ref": "#/cip-139/UInt64" - }, - "response": { - "$ref": "#/cip-116/Block" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the block with the supplied block number. - -###### Hash - -``` -{ - "operation": "getBlockByHash", - "request": { - "$ref": "#/cip-116/BlockHash" - }, - "response": { - "$ref": "#/cip-116/Block" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the block with the supplied block hash. - -##### Transaction - -###### Hash - -``` -{ - "operation": "getTransactionByHash", - "request": { - "$ref": "#/cip-139/TransactionHash" - }, - "response": { - "$ref": "#/cip-116/Transaction" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the transaction with the supplied transaction hash. - -###### Block Number - -``` -{ - "operation": "getTransactionByBlockNumber", - "request": { - "$ref": "#/cip-139/UInt64" - }, - "response": { - "type": "object", - "properties": { - "transactions": { - "type": "array", - "items": { - "$ref": "#/cip-116/Transaction" - } - } - }, - "required": [ - "transactions" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all transactions contained in the block with the supplied block number []. - -###### Block Hash - -``` -{ - "operation": "getTransactionByBlockHash", - "request": { - "$ref": "#/cip-116/BlockHash" - }, - "response": { - "type": "object", - "properties": { - "transactions": { - "type": "array", - "items": { - "$ref": "#/cip-116/Transaction" - } - } - }, - "required": [ - "transactions" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all transactions contained in the block with the supplied block hash. - -##### Datum - -###### Hash - -``` -{ - "operation": "getDatumByHash", - "request": { - "$ref": "#/cip-116/DataHash" - }, - "response": { - "$ref": "#/cip-116/PlutusData" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the datum that hashes to the supplied data hash. - -##### Plutus Script - -###### Hash - -``` -{ - "operation": "getPlutusScriptByHash", - "request": { - "$ref": "#/cip-116/ScriptHash" - }, - "response": { - "$ref": "#/cip-116/PlutusScript" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the plutus script that hashes to the supplied script hash. - -##### Native Script - -###### Hash - -``` -{ - "operation": "getNativeScriptByHash", - "request": { - "$ref": "#/cip-116/ScriptHash" - }, - "response": { - "$ref": "#/cip-116/NativeScript" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the native script that hashes to the supplied script hash. - -##### Metadata - -###### Transaction Hash - -``` -{ - "operation": "getMetadataByTransactionHash", - "request": { - "$ref": "#/cip-139/TransactionHash" - }, - "response": { - "$ref": "#/cip-116/TransactionMetadatum" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the metadata present on the transaction with the supplied transaction hash. - -##### Protocol Parameters - -###### Latest - -``` -{ - "operation": "getProtocolParametersByLatest", - "request": {}, - "response": { - "$ref": "#/cip-139/ProtocolParams" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the latest protocol parameters. - -###### Epoch - -``` -{ - "operation": "getProtocolParametersByEpoch", - "request": { - "$ref": "#/cip-139/UInt32" - }, - "response": { - "$ref": "#/cip-139/ProtocolParams" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the protocol parameters at the supplied epoch number. - -##### Votes - -###### Cc Id - -``` -{ - "operation": "getVotesByCcId", - "request": { - "$ref": "#/cip-139/CCHotId" - }, - "response": { - "type": "object", - "properties": { - "votes": { - "type": "array", - "items": { - "$ref": "#/cip-139/VoteInfo" - } - } - }, - "required": [ - "votes" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Votes cast by the supplied cc credential. - -###### Spo Id - -``` -{ - "operation": "getVotesBySpoId", - "request": { - "$ref": "#/cip-139/PoolPubKeyHash" - }, - "response": { - "type": "object", - "properties": { - "votes": { - "type": "array", - "items": { - "$ref": "#/cip-139/VoteInfo" - } - } - }, - "required": [ - "votes" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Votes cast by the supplied stake pool operator. - -###### Drep Id - -``` -{ - "operation": "getVotesByDrepId", - "request": { - "$ref": "#/cip-139/DRepId" - }, - "response": { - "type": "object", - "properties": { - "votes": { - "type": "array", - "items": { - "$ref": "#/cip-139/VoteInfo" - } - } - }, - "required": [ - "votes" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Votes cast by the supplied DRep. - -###### Proposal Id - -``` -{ - "operation": "getVotesByProposalId", - "request": { - "$ref": "#/cip-139/ProposalId" - }, - "response": { - "type": "object", - "properties": { - "votes": { - "type": "array", - "items": { - "$ref": "#/cip-139/VoteInfo" - } - } - }, - "required": [ - "votes" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Votes cast on the supplied proposal. - -##### Drep - -###### All - -``` -{ - "operation": "getAllDreps", - "request": {}, - "response": { - "type": "object", - "properties": { - "dreps": { - "type": "array", - "items": { - "$ref": "#/cip-139/DRepInfo" - } - } - }, - "required": [ - "dreps" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all the known DReps. - -###### Id - -``` -{ - "operation": "getDrepById", - "request": { - "$ref": "#/cip-139/DRepId" - }, - "response": { - "$ref": "#/cip-139/DRepInfo" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get a specific DRep by id. - -###### Stake Credential - -``` -{ - "operation": "getDrepByStakeCredential", - "request": { - "$ref": "#/cip-116/RewardAddress" - }, - "response": { - "$ref": "#/cip-139/DRepInfo" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the DRep that the stake credential has delegated to. - -##### Committee Member - -###### All - -``` -{ - "operation": "getAllCommitteeMembers", - "request": {}, - "response": { - "type": "object", - "properties": { - "cc_members": { - "type": "array", - "items": { - "$ref": "#/cip-139/CCMember" - } - } - }, - "required": [ - "cc_members" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all known committee members. - -###### Id - -``` -{ - "operation": "getCommitteeMemberById", - "request": { - "$ref": "#/cip-139/CCHotId" - }, - "response": { - "$ref": "#/cip-139/CCMember" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get a specific Committee member by id. - -##### Pool - -###### All - -``` -{ - "operation": "getAllPools", - "request": {}, - "response": { - "type": "object", - "properties": { - "pools": { - "type": "array", - "items": { - "$ref": "#/cip-139/Pool" - } - } - }, - "required": [ - "pools" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all known stake pools. - -###### Id - -``` -{ - "operation": "getPoolById", - "request": { - "$ref": "#/cip-139/PoolPubKeyHash" - }, - "response": { - "$ref": "#/cip-139/Pool" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get a specific stake pool by id. - -##### Proposal - -###### All - -``` -{ - "operation": "getAllProposals", - "request": {}, - "response": { - "type": "object", - "properties": { - "proposals": { - "type": "array", - "items": { - "$ref": "#/cip-139/Proposal" - } - } - }, - "required": [ - "proposals" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get all known proposals. - -###### Id - -``` -{ - "operation": "getProposalById", - "request": { - "$ref": "#/cip-139/ProposalId" - }, - "response": { - "$ref": "#/cip-139/Proposal" - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get a specific proposal by id. - -##### Era - -###### Summary - -``` -{ - "operation": "getEraBySummary", - "request": {}, - "response": { - "type": "object", - "properties": { - "summary": { - "type": "array", - "items": { - "$ref": "#/cip-139/EraSummary" - } - } - }, - "required": [ - "summary" - ] - }, - "errors": [ - { - "$ref": "#/appendix/APIError" - } - ] -} -``` - -Get the start and end of each era along with parameters that can vary between hard forks. - - -### Versioning - -In this CIP we are defining two different APIs: the connection API for wallets, and the CIP-30 *[maybe this should have another name to prevent confusion?]* extension which enables an own-data wallet. These two are separate components, below there is a table with separate entries for the versions of the connection API and CIP-30 Extension respectively. - -While the CIP is in preparation, these versions shall be set to `0.0.0`. The moment this CIP is merged the versions shall be set to `1.0.0`, and all implementations should consider that the current version. Any changes to either API should come in form of PRs to this CIP. - -| API | Version | -| --- | --- | -| Version-Connection-API | 0.0.0 | -| Version-CIP-30-Extension | 0.0.0 | - - -### Appendix - -This appendix contains additional schemas for types that are used in the APIs. - -#### Connection API Data Types - -##### Extensions - -``` -{ - "type": "object", - "title": "Extensions", - "properties": { - "extensions": { - "type": "array", - "items": { - { - "type": "object", - "title": "Extension", - "properties": { - "cip": { - "type": "number" - }, - "version: { - "$ref": "#/appendix/SemVer" - } - }, - "required": ["cip"], - } - } - } - }, - "required": ["extensions"], -} -``` - -An extension is an object with a "cip" field that describes a CIP number extending the API, and an optional version specified according to SemVer. For example: - -``` -{ "cip": 30 } -``` - - -##### DataSignature - -``` -{ - "type": "object", - "title": "DataSignature", - "properties": { - "signature": { - "title": "Ed25519Signature", - "type": "string", - "format": "hex", - "pattern": "^([0-9a-f][0-9a-f]){64}$" - }, - "key": { - "title": "Ed25519PublicKey", - "type": "string", - "format": "hex", - "pattern": "^([0-9a-f][0-9a-f]){32}$" - } - }, - "required": ["signature", "key"], -} -``` - -An object representing some data that has been signed. It contains 2 fields: `signature` which contains the signed data, and `key` which contains the derived Ed25519 PubKey used to sign the data. - -##### SemVer - -``` -{ - "type": "object", - "title": "SemVer", - "properties": { - "major": { - "title": "Major", - "type": "number", - }, - "minor": { - "title": "Minor", - "type": "number", - }, - "patch": { - "title": "Patch", - "type": "number", - } - }, - "required": ["major", "minor", "patch"], -} -``` - -#### Errors - -This section lists the possible errors the wallet connector may return. Each error is specified by an error code, and an optional info string describing the cause of the error. Below each error we list names for all the error codes, and a brief description of when they should be used. Other than when the spec dictates the use of a specific error code, wallets can choose the error code they deem more applicable to the situation. Wallets can also extend these errors with additional codes should they feel the need to. - -##### APIError - -``` -{ - "type": "object", - "title": "APIError", - "properties": { - "code": { - "type": "number", - "title": "APIErrorCode" - "enum": [-1, -2, -3, -4, -5] - }, - "info": { - "type": "string" - } - }, - "required": ["code"], + "required": ["code"], } ``` @@ -1461,85 +288,12 @@ This section lists the possible errors the wallet connector may return. Each err - `AccountChange`: (-4) The account has changed. The dApp should call wallet.enable() to reestablish connection to the new account. The wallet should not ask for confirmation as the user was the one who initiated the account change in the first place. - `NotSatisfiable`: (-5) The request is structurally correct, but the wallet can not satisfy it for some reason. -##### DataSignError - -``` -{ - "type": "object", - "title": "DataSignError", - "properties": { - "code": { - "type": "number", - "title": "DataSignErrorCode" - "enum": [1, 2, 3] - }, - "info": { - "type": "string" - } - }, - "required": ["code"], -} -``` - -- `ProofGeneration`: (1) Wallet could not sign the data (e.g. does not have the secret key associated with the address). -- `AddressNotPK`: (2) Address was not a P2PK address and thus had no SK associated with it. -- `UserDeclined`: (3) User declined to sign the data. - -##### TxSendError - -``` -{ - "type": "object", - "title": "TxSendError", - "properties": { - "code": { - "type": "number", - "title": "TxSendErrorCode" - "enum": [1, 2] - }, - "info": { - "type": "string" - } - }, - "required": ["code"], -} -``` - -- `Refused`: (1) Wallet refuses to send the tx (could be rate limiting). -- `Failure`: (2) Wallet could not send the tx. - -##### TxSignError - -``` -{ - "type": "object", - "title": "TxSignError", - "properties": { - "code": { - "type": "number", - "title": "TxSignErrorCode" - "enum": [1, 2] - }, - "info": { - "type": "string" - } - }, - "required": ["code"], -} -``` - -- `ProofGeneration`: (1) User has accepted the transaction sign, but the wallet was unable to sign the transaction (e.g. not having some of the private keys). -- `UserDeclined`: (2) User declined to sign the transaction. - #### Transport specific connectors -While this CIP attempts to define an API in a transport agnostic way, implementations will be forced to pick a specific transport. In the spec we have not given specifics on how to -namespace and generally structure the api in an implementation. This is both because details depend on the underlying transport that is chosen to implement the API, but also because -we wanted to make backwards compatibility with the original CIP-30 proposal as easy as possible. +While this CIP attempts to define an API in a transport agnostic way, implementations will be forced to pick a specific transport. In the spec we have not given specifics on how to namespace and generally structure the api in an implementation. This is both because details depend on the underlying transport that is chosen to implement the API, but also because we wanted to make backwards compatibility with the original CIP-30 proposal as easy as possible. -Each transport specific implementation will make a choice on how to namespace access to the operations. In the following we give a description of how this should work for an implementation -using an injected javascript object. Support for different transports can be added to this CIP in form of PRs. +Each transport specific implementation will make a choice on how to namespace access to the operations. In the following we give a description of how this should work for an implementation using an injected javascript object. Support for different transports can be added to this CIP in form of PRs. ##### Injected Javascript Object @@ -1563,34 +317,25 @@ api.cip123.endpoint2() Given this definition, we can take an existing CIP-30 compliant wallet, and make it compatible with this CIP with a wrapper. -This wrapper will be relatively small, but must still take care in unifying the differences between this CIP and CIP-30. There is a list of some notable differences to keep in mind: +This wrapper will be relatively small, but must still take care in unifying the differences between this CIP and the connection api from CIP-30. There is a list of some notable differences to keep in mind: - JSON is used instead of CBOR. The wrapper must take care of translating arguments and results. -- This API has no pagination, while CIP-30 generally does. The wrapper can either implement pagination locally, or error and inform the user if they request it. -- In the original CIP-30, the `api` object returned has, on the top-level, the methods that we expect on `api.cip30`. The wrapper must take care to translate calls appropriately. - CIP-30 allows for a situation where the user requests some extensions in the enable call, but despite the wallet not supporting those extensions, the `enable` call succeeds. This makes it so the dApps always have to check what extensions were actually enabled. In this CIP we don't allow that, so the wrapper must take care of calling `api.getExtension` after `cardano.{walletName}.enable` to check all required extensions are enabled, if that's not the case then throw an error. -- CIP-30 endpoints will return `null` in some situations where the request is correct, but not satisfiable. In this CIP we introduce an error code specifically for that. The wrapper will need to check some results for `null` and throw an appropriate error. - Add an `api.apiVersion` method that returns the version for the connector -Implementing this wrapper is out of scope of this CIP, -but we welcome any effort in this direction, as it would make transitioning to this CIP easier for most wallets. +Implementing this wrapper is out of scope of this CIP, but we welcome any effort in this direction, as it would make transitioning to this CIP easier for most wallets. ## Rationale: how does this CIP achieve its goals? -The goal of this CIP is to define the standard for a new wallet connector. This connector improves on CIP-30, both by fixing some of the shortcomings that -have been identified over time, and by extending its capabilities to be able to perform more queries. +The goal of this CIP is to define the standard for a new wallet connector. This connector improves on CIP-30 by defining an independent connection API and giving dApp developers a finer-grained choice on which functionalities to enable via the extension mechanism. +The goal is to be able to clearly differentiate and communicate the type of wallet that is needed, following the distinction made in the [wallet role](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md#4-work-within-the-role-of-wallet) section of CPS-10. -We split the contributions of this CIP in two categories: +There are two CIPs that are connected with this one: -- Improve CIP-30 - - Introducing a transport agnostic way to define the behavior of these APIs - - Separating the connection API from the different extension APIs the wallet can offer - - Using JSON for Cardano domain types instead of CBOR - - Making versioning explicit and adding support for specifying versions when enabling an extension +- [CIP-XXX | Own data wallet](link) which defines an extension for an [own-data wallet](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md#own-data-wallets) which is equivalent to what CIP-30 offers today -- Universal Query Layer extension - - Adding a query layer extension API to enable a full data wallet +- [CIP-139 | Universal Query Layer](https://github.com/cardano-foundation/CIPs/pull/869) which defines an extension for a [full-data wallet](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md#full-data-wallets) which allows the wallet to track blockchain data that is outside of the user's scope ## Path to Active @@ -1602,7 +347,6 @@ We split the contributions of this CIP in two categories: ### Implementation Plan -- [ ] This CIP depends on CIP-139 to be active, in particular wallets need to support the queries required by the `cip-139` extension. - [ ] Implement a wrapper that takes a CIP-30 compatible API and transforms it to be compatible with CIP-XXXX. ## Copyright From de2aa8b95b8c1d2264f19c67d3eb1bb8f11ebf67 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Thu, 6 Feb 2025 11:01:46 +0100 Subject: [PATCH 23/25] Update CIP-0144/README.md --- CIP-0144/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index faaac58ce9..9c210ee6f6 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -333,7 +333,7 @@ The goal is to be able to clearly differentiate and communicate the type of wall There are two CIPs that are connected with this one: -- [CIP-XXX | Own data wallet](link) which defines an extension for an [own-data wallet](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md#own-data-wallets) which is equivalent to what CIP-30 offers today +- [CIP-XXX | Own data wallet](https://github.com/cardano-foundation/CIPs/pull/986) which defines an extension for an [own-data wallet](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md#own-data-wallets) which is equivalent to what CIP-30 offers today - [CIP-139 | Universal Query Layer](https://github.com/cardano-foundation/CIPs/pull/869) which defines an extension for a [full-data wallet](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md#full-data-wallets) which allows the wallet to track blockchain data that is outside of the user's scope From cfac3b78fbe9a10cd8a8657ea265a3f3de0cc815 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Thu, 6 Feb 2025 11:01:58 +0100 Subject: [PATCH 24/25] Update CIP-0144/README.md --- CIP-0144/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index 9c210ee6f6..c712ceb6bc 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -182,7 +182,7 @@ Returns the API version for the wallet connection API. This must correspond to t ### Versioning -In this CIP we define a semantic versioning (SemVer) scheme that will be used by the connection API. Extensions defined in other CIPs (e.g. [CIP-XXX | Own data wallet](link)) must follow the same versioning schema. +In this CIP we define a semantic versioning (SemVer) scheme that will be used by the connection API. Extensions defined in other CIPs (e.g. [CIP-XXX | Own data wallet](https://github.com/cardano-foundation/CIPs/pull/986)) must follow the same versioning schema. While the CIP is in preparation, the version shall be set to `0.0.0`. The moment this CIP is merged the version shall be set to `1.0.0`, and all implementations should consider that the current version. Any changes to the connection API should come in form of PRs to this CIP. From a25a34b9cbcfd1bfa684c4fcd2300d396a490b21 Mon Sep 17 00:00:00 2001 From: Giovanni Garufi Date: Wed, 5 Feb 2025 14:00:17 +0100 Subject: [PATCH 25/25] Keep only wallet connection API --- CIP-0144/README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/CIP-0144/README.md b/CIP-0144/README.md index faaac58ce9..ae4579d674 100644 --- a/CIP-0144/README.md +++ b/CIP-0144/README.md @@ -18,7 +18,7 @@ Solution-To: CPS-0010 CIP-30 is the standard interface of communication between wallets and dApps. While this CIP has been instrumental in the development of dApps for Cardano, it also has some shortcomings that have been observed across several implementations. -[CPS-0010](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md) outlines some shortcomings in CIP-30. In this CIP we aid to address some of the issues pointed out by CPS-10: splitting up the connection API, from the functionality provided by the [full API](https://cips.cardano.org/cip/CIP-30#full-api), defining the API in a transport agnostic way and defining a versioning mechanism for the connection API and it's extensions. +[CPS-0010](https://github.com/cardano-foundation/CIPs/blob/master/CPS-0010/README.md) outlines the shortcomings of CIP-30. In this CIP we aim to address some of the issues pointed out by CPS-10: splitting up the connection API from the functionality provided by the [full API](https://cips.cardano.org/cip/CIP-30#full-api), defining the API in a transport agnostic way and defining a versioning mechanism for the connection API and its extensions. ## Motivation: why is this CIP necessary? @@ -30,7 +30,7 @@ CIP-30 is a universally accepted web-based wallet standard for Cardano. It provi ### Use of CBOR representations -CIP-30 standard uses CBOR encoding for all data passed from the wallet, e.g. addresses and UTxOs. Interpreting this data within the app requires CBOR decoding functionality that is tedious to implement manually, and so users resort to using cardano-serialization-lib or its close alternative, cardano-multiplatform-lib, which both require loading a WebAssembly blob of >1M in size. +In addition to the points described in CPS-10, the CIP-30 standard uses CBOR encoding for all data passed from the wallet, e.g. addresses and UTxOs. Interpreting this data within the app requires CBOR decoding functionality that is tedious to implement manually, and so users resort to using cardano-serialization-lib or its close alternative, cardano-multiplatform-lib, which both require loading a WebAssembly blob of >1M in size. For comparison, to start a new Web3 app on Ethereum there is no need to use a library for data serialization. It’s possible to interact with a provider object that is given by the wallet directly, although there are libraries to further simplify this. Using CBOR looks unnecessary for most dApps, given that JSON is a de-facto standard for web data serialization. @@ -45,6 +45,8 @@ The goal of this CIP is to provide a better alternative to CIP-30, providing a b - Add versioning support to the extension API - Define the API in a transport agnostic way +### Transport agnostic operations + In its current state, CIP-30 defines it API through a specific transport layer, namely an injected Javascript object. In this CIP we want to be able to define an API without committing to a specific transport layer. Implementors of this API can choose to support this API through several transports such as: HTTP, an injected Javascript object, JSON-RPC etc. Furthermore, we want to use JSON-schema to clearly define the types that each method, or operation, expects to receive or returns. @@ -70,7 +72,7 @@ We do not add an explicit scope to operation names, we do however encourage tran We will reference several JSON schemas throughout the document, these are: -- [CIP-116 | Standard JSON encoding for Domain Types](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. *[Maybe we should only reference the latest era and update the CIP in the future? our current definition requires to be perpetually backward compatible with old ledger types]* +- [CIP-116 | Standard JSON encoding for Domain Types](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0116) which provides a JSON encoding of Cardano ledger types. Note that this CIP defines a schema for each ledger era. When referring to a type from this schema we refer to an `anyOf` of all the schemas in which that type is defined. - [appendix](#appendix) in which we define schemas for types required by the connection API and the error types We will use an identifier in the anchor to refer to the schema where each type is defined. For example, if we want to reference the `Transaction` type, as defined in CIP-116 we will use the following schema reference `{ "$ref": "#/cip-116/Transaction" }`. @@ -81,7 +83,7 @@ For each operation we will provide some details on how the implementation should ### Connection API -The role of the connection API is to provide generic information about the wallet and to allow the user to opt into the functionalities that they want the wallet to provide. +The role of the connection API is to provide generic information about the wallet and to allow the user to opt into the functionalities (or extensions) that they want the wallet to provide. ##### Enable @@ -178,7 +180,7 @@ A URI image (e.g. data URI base64 or other) for img src for the wallet which can } ``` -Returns the API version for the wallet connection API. This must correspond to the value of `Version-Connection-API` specified in this document, appropriately transformed into a `SemVer` object. +Returns the API version for the wallet connection API. This must correspond to the value of `Connection-API` specified in this document, appropriately transformed into a `SemVer` object. ### Versioning @@ -188,7 +190,7 @@ While the CIP is in preparation, the version shall be set to `0.0.0`. The moment | API | Version | | --- | --- | -| Version-Connection-API | 0.0.0 | +| Connection-API | 0.0.0 | ### Appendix @@ -347,7 +349,7 @@ There are two CIPs that are connected with this one: ### Implementation Plan -- [ ] Implement a wrapper that takes a CIP-30 compatible API and transforms it to be compatible with CIP-XXXX. +- [ ] Implement a wrapper that takes a CIP-30 compatible API and transforms it to be compatible with CIP-0144. ## Copyright