From 9a5f0d953fea82327bd085aa9aa65a3b470778a7 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Fri, 30 Apr 2021 00:28:23 -0500 Subject: [PATCH 01/15] CIP-Dapp-Connector Initial version. --- CIP-DappConnector/CIP-dapp-connector.md | 210 ++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 CIP-DappConnector/CIP-dapp-connector.md diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md new file mode 100644 index 0000000000..7b7ea023a3 --- /dev/null +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -0,0 +1,210 @@ +--- +CIP: ? +Title: Cardano dApp-Wallet Web Bridge +Authors: rooooooooob +Status: Draft +Type: Standards +Created: 2021-04-29 +License: CC-BY-4.0 +--- + +# Abstract + +This documents describes a webpage-based communication bridge allowing webpages (i.e. dApps) to interface with Cardano wallets. This is done via injected javascript code into webpages. This specification defines the manner that such code is to be accessed by the webpage/dApp, as well as defining the API for dApps to communicate with the user's wallet. This document currently concerns the Shelley-Mary era but will have a second version once Plutus is supported. This specification is intended to cover similar use cases as web3 for Ethereum or [EIP-0012](https://github.com/ergoplatform/eips/pull/23) for Ergo. The design of this spec was based on the latter. + + +# Motivation + +In order to facilitate future dApp development, we will need a way for dApps to communicate with the user's wallet. While Cardano does not yet support smart contracts, there are still various use cases for this, such as NFT management. This will also lay the groundwork for an updated version of the spec once the Alonzo hardfork is released which can extend it to allow for Plutus support. + + + +# Specification + +## Data Types + +### Bytes + +A hex-encoded string of the corresponding bytes. + +### cbor\ + +A hex-encoded string representing [CBOR](https://tools.ietf.org/html/rfc7049) corresponding to `T` defined via [CDDL](https://tools.ietf.org/html/rfc8610) either inside of the [Shelley Mary binary spec](https://github.com/input-output-hk/cardano-ledger-specs/blob/0738804155245062f05e2f355fadd1d16f04cd56/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl) or, if not present there, from the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md). +This representation was chosen when possible as it is consistent across the Cardano ecosystem and widely used by other tools, such as [cardano-serialization-lib](https://github.com/Emurgo/cardano-serialization-lib), which has support to encode every type in the binary spec as CBOR bytes. + +### Paginate + +``` +type Paginate = {| + page: number, + limit: number, +|}; +``` +Used to specify optional pagination for some API calls. Limits results to {limit} each page, and uses a 0-indexing {page} to refer to which of those pages of {limit} items each. + + +## Error Types + +### APIError + +``` +APIErrorCode { + InvalidRequest: -1, + InternalError: -2, + Refused: -3, +} +APIError { + code: APIErrorCode, + info: string +} +``` + +### DataSignError + +``` +DataSignErrorCode { + ProofGeneration: 1, + AddressNotPK: 2, + UserDeclined: 3, + InvalidFormat: 4, +} +type DataSignError = { + code: DataSignErrorCode, + info: String +} +``` + +* ProofGeneration - Wallet could not sign the data (e.g. does not have the secret key associated with the address) +* AddressNotPK - Address was not a P2PK address and thus had no SK associated with it. +* UserDeclined - User declined to sign the data +* InvalidFormat - If a wallet enforces data format requirements, this error signifies that the data did not conform to valid formats. + +* InvalidRequest - Inputs do not conform to this spec or are otherwise invalid. +* InternalError - An error occurred during execution of this API call. +* Refused - The request was refused due to lack of access - e.g. wallet disconnects. + +### PaginateError + +``` +type PaginateError = {| + maxSize: number, +|}; +``` +{maxSize} is the maximum size for pagination and if the dApp tries to request pages outside of this boundary this error is thrown. + +### TxSendError + +``` +TxSendErrorCode = { + Refused: 1, + Failure: 2, +} +type TxSendError = { + code: TxSendErrorCode, + info: String +} +``` + +* Refused - Wallet refuses to send the tx (could be rate limiting) +* Failure - Wallet could not send the tx + +### TxSignError + +``` +TxSignErrorCode = { + ProofGeneration: 1, + UserDeclined: 2, +} +type TxSignError = { + code: TxSignErrorCode, + info: String +} +``` + +* ProofGeneration - 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 - User declined to sign the transaction + + + +## Initial API + +In order to initiate communication from webpages to a user's Cardano wallet, the wallet must provide the following javascript functions to the webpage. These would likely be done via code injection into the webpage. The API is split into two stages to maintain the user's privacy, as the user will have to consent to `cardano_request_read_access()` in order for the dApp to read any information pertaining to the user's wallet. + +### cardano_request_read_access(): Promise\ + +Errors: 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 full API (`cardano` object) must be exposed to the webpage. 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 do nothing and simply return true. + +### cardano_check_read_access(): Promise\ + +Errors: APIError + +Returns true if the full API (`cardano` object) was injected and the dApp has access to the user's wallet, and false otherwise. + + + + +## Full API + +Upon successful connection via `cardano_request_read_access()`, a javascript object named `cardano` is injected with the following methods. All read-only methods (all but the signing functionality) should not require any as the user has already consented to the dApp reading information about the wallet's state when they agreed to `cardano_request_read_access()`. The remaining methods `cardano.sign_tx()`, `cardano.sign_tx_input()`, `cardano.sign_data()` must request the user's consent in an informative way for each and every API call in order to maintain security. + +The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. + +### cardano.get_utxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ | undefined> + +Errors: `APIError`, `PaginateError` + +If `amount` is `undefined`, this shall return a list of all UTXOs (unspent transaction outputs) controlled by the wallet. If `amount` is not `undefined`, 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, `undefined` shall be returned. The results can be further paginated by `paginate` if it is not `undefined`. + +### cardano.get_balance(): Promise\> + +Errors: `APIError` + +Returns the total balance available of the wallet. This is the same as summing the results of `cardano.get_utxos()`, 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. + +### cardano.get_used_addresses(paginate: Paginate = undefined): Promise\<\[]> + +Errors: `APIError` + +Returns a list of all used (included in some on-chain transaction) addresses controlled by the wallet. The results can be further paginated by `paginate` if it is not `undefined`. + +### cardano.get_unused_addresses(): Promise\<\[]> + +Errors: `APIError` + +Returns a list of unused addresses controlled by the wallet. + +### cardano.get_change_address(): Promise\<\> + +Errors: `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. + +### cardano.sign_tx(tx: cbor\, metadata: cbor\ = undefined): Promise\> + +Errors: `APIError`, `TxSignError` + +Requests that a user sign the supplied transaction body. The wallet should ask the user for permission, and if given, try to sign the supplied body and return a signed transaction. If the wallet could not sign the transaction, `TxSignError` shall be returned with the `ProofGeneration` code. Likewise if the user declined it shall return the `UserDeclined` code. + +### cardano.sign_tx_input(tx: cbor\, index: number): Promise\> + +Errors: `APIError`, `TxSignError` + +Provides lower-level ability for signing that produces the witnesses for just a single input in a transaction. This exists in case dApps need to construct a transaction to satisfy certain properties and the user might only own some of the inputs. The wallet should ask user permission for signing similar to `cardano.sign_tx_input()` and errors are handled in the same way. + +### cardano.sign_data(addr: cbor\
, sig_structure: cbor\): Promise\ + +Errors: `APIError`, `DataSignError` + +This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md) for standardization/safety reasons. It allows the dApp to request the user to sign data conforming to said spec. The user's consent should be requested and the details of `sig_structure` shown to them in an informative way. The Please refer to the CIP-0008 spec for details on how to construct the sig structure. + +### cardano.submit_tx(tx: cbor\): Promise\ + +Errors: `APIError`, `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 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). + +# Implementations + +TODO: link to Yoroi's implementation once available From 3cbc1211ad310976c33303611afdec45128116b3 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Thu, 10 Jun 2021 18:52:17 -0500 Subject: [PATCH 02/15] Update get_utxos() definition 1) having just transaction_output is not helpful for tx creation so we add in a type that also contains the input for it. 2) It should have been an array returned, this was a mistake. --- CIP-DappConnector/CIP-dapp-connector.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index 7b7ea023a3..a3e024ecf8 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -32,6 +32,22 @@ A hex-encoded string of the corresponding bytes. A hex-encoded string representing [CBOR](https://tools.ietf.org/html/rfc7049) corresponding to `T` defined via [CDDL](https://tools.ietf.org/html/rfc8610) either inside of the [Shelley Mary binary spec](https://github.com/input-output-hk/cardano-ledger-specs/blob/0738804155245062f05e2f355fadd1d16f04cd56/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl) or, if not present there, from the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md). This representation was chosen when possible as it is consistent across the Cardano ecosystem and widely used by other tools, such as [cardano-serialization-lib](https://github.com/Emurgo/cardano-serialization-lib), which has support to encode every type in the binary spec as CBOR bytes. +### TransactionUnspentOutput + +If we have CBOR specified by the following CDDL referencing the Shelley-Mara CDDL: +```cddl +transaction_unspent_output = [ + input: transaction_input, + output: transaction_output, +] +``` +then we define +``` +type TransactionUnspentOutput = cbor +``` + +This allows us to use the output for constructing new transactions using it as an output as the `transaction_output` in the Shelley Mary CDDL does not contain enough information on its own to spend it. + ### Paginate ``` @@ -151,7 +167,7 @@ Upon successful connection via `cardano_request_read_access()`, a javascript obj The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. -### cardano.get_utxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ | undefined> +### cardano.get_utxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ Errors: `APIError`, `PaginateError` From 7072b2df38bf749d7b9349821693c2f62242bcbc Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Tue, 13 Jul 2021 02:09:57 -0500 Subject: [PATCH 03/15] Minor requested changes --- CIP-DappConnector/CIP-dapp-connector.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index a3e024ecf8..64c671f291 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -75,6 +75,10 @@ APIError { } ``` +* InvalidRequest - Inputs do not conform to this spec or are otherwise invalid. +* InternalError - An error occurred during execution of this API call. +* Refused - The request was refused due to lack of access - e.g. wallet disconnects. + ### DataSignError ``` @@ -95,10 +99,6 @@ type DataSignError = { * UserDeclined - User declined to sign the data * InvalidFormat - If a wallet enforces data format requirements, this error signifies that the data did not conform to valid formats. -* InvalidRequest - Inputs do not conform to this spec or are otherwise invalid. -* InternalError - An error occurred during execution of this API call. -* Refused - The request was refused due to lack of access - e.g. wallet disconnects. - ### PaginateError ``` @@ -163,7 +163,7 @@ Returns true if the full API (`cardano` object) was injected and the dApp has ac ## Full API -Upon successful connection via `cardano_request_read_access()`, a javascript object named `cardano` is injected with the following methods. All read-only methods (all but the signing functionality) should not require any as the user has already consented to the dApp reading information about the wallet's state when they agreed to `cardano_request_read_access()`. The remaining methods `cardano.sign_tx()`, `cardano.sign_tx_input()`, `cardano.sign_data()` must request the user's consent in an informative way for each and every API call in order to maintain security. +Upon successful connection via `cardano_request_read_access()`, a javascript object named `cardano` is injected 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_request_read_access()`. The remaining methods `cardano.sign_tx()`, `cardano.sign_tx_input()`, `cardano.sign_data()` must request the user's consent in an informative way for each and every API call in order to maintain security. The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. @@ -179,19 +179,19 @@ Errors: `APIError` Returns the total balance available of the wallet. This is the same as summing the results of `cardano.get_utxos()`, 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. -### cardano.get_used_addresses(paginate: Paginate = undefined): Promise\<\[]> +### cardano.get_used_addresses(paginate: Paginate = undefined): Promise\[]> Errors: `APIError` Returns a list of all used (included in some on-chain transaction) addresses controlled by the wallet. The results can be further paginated by `paginate` if it is not `undefined`. -### cardano.get_unused_addresses(): Promise\<\[]> +### cardano.get_unused_addresses(): Promise\[]> Errors: `APIError` Returns a list of unused addresses controlled by the wallet. -### cardano.get_change_address(): Promise\<\> +### cardano.get_change_address(): Promise\> Errors: `APIError` From d63230aec260c289f98514c39eb1818cc0b94985 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Tue, 3 Aug 2021 21:58:55 -0500 Subject: [PATCH 04/15] Initial wording for multi-wallet support + versioning --- CIP-DappConnector/CIP-dapp-connector.md | 50 ++++++++++++++++--------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index 64c671f291..f67b946f55 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -21,6 +21,10 @@ In order to facilitate future dApp development, we will need a way for dApps to # Specification +## Version + +The API specified in this document will count as version 0.1.0 for version-checking purposes below. + ## Data Types ### Bytes @@ -144,78 +148,90 @@ type TxSignError = { ## Initial API -In order to initiate communication from webpages to a user's Cardano wallet, the wallet must provide the following javascript functions to the webpage. These would likely be done via code injection into the webpage. The API is split into two stages to maintain the user's privacy, as the user will have to consent to `cardano_request_read_access()` in order for the dApp to read any information pertaining to the user's wallet. +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.wallet_name.request_read_access()` in order for the dApp to read any information pertaining to the user's wallet. + +### wallet.request_read_access(): Promise\ + +Errors: 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 full API will be returned to 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, and instead just return the `API` object. -### cardano_request_read_access(): Promise\ +### wallet.check_read_access(): Promise\ Errors: 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 full API (`cardano` object) must be exposed to the webpage. 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 do nothing and simply return true. +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. If this function returns true, then any subsequent calls to `wallet.request_read_access()` during the current session should succeed and return the `API` object. -### cardano_check_read_access(): Promise\ +### wallet.version(): String Errors: APIError -Returns true if the full API (`cardano` object) was injected and the dApp has access to the user's wallet, and false otherwise. +Returns the version number of the API that the wallet supports. + + +### wallet.name(): String + +Errors: APIError +Returns 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 connect with. ## Full API -Upon successful connection via `cardano_request_read_access()`, a javascript object named `cardano` is injected 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_request_read_access()`. The remaining methods `cardano.sign_tx()`, `cardano.sign_tx_input()`, `cardano.sign_data()` must request the user's consent in an informative way for each and every API call in order to maintain security. +Upon successful connection via `wallet.request_read_access()`, 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 `wallet.request_read_access()`. The remaining methods `api.sign_tx()`, `api.sign_tx_input()`, `api.sign_data()` must request the user's consent in an informative way for each and every API call in order to maintain security. The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. -### cardano.get_utxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ +### api.get_utxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ Errors: `APIError`, `PaginateError` If `amount` is `undefined`, this shall return a list of all UTXOs (unspent transaction outputs) controlled by the wallet. If `amount` is not `undefined`, 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, `undefined` shall be returned. The results can be further paginated by `paginate` if it is not `undefined`. -### cardano.get_balance(): Promise\> +### api.get_balance(): Promise\> Errors: `APIError` -Returns the total balance available of the wallet. This is the same as summing the results of `cardano.get_utxos()`, 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. +Returns the total balance available of the wallet. This is the same as summing the results of `api.get_utxos()`, 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. -### cardano.get_used_addresses(paginate: Paginate = undefined): Promise\[]> +### api.get_used_addresses(paginate: Paginate = undefined): Promise\[]> Errors: `APIError` Returns a list of all used (included in some on-chain transaction) addresses controlled by the wallet. The results can be further paginated by `paginate` if it is not `undefined`. -### cardano.get_unused_addresses(): Promise\[]> +### api.get_unused_addresses(): Promise\[]> Errors: `APIError` Returns a list of unused addresses controlled by the wallet. -### cardano.get_change_address(): Promise\> +### api.get_change_address(): Promise\> Errors: `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. -### cardano.sign_tx(tx: cbor\, metadata: cbor\ = undefined): Promise\> +### api.sign_tx(tx: cbor\, metadata: cbor\ = undefined): Promise\> Errors: `APIError`, `TxSignError` Requests that a user sign the supplied transaction body. The wallet should ask the user for permission, and if given, try to sign the supplied body and return a signed transaction. If the wallet could not sign the transaction, `TxSignError` shall be returned with the `ProofGeneration` code. Likewise if the user declined it shall return the `UserDeclined` code. -### cardano.sign_tx_input(tx: cbor\, index: number): Promise\> +### api.sign_tx_input(tx: cbor\, index: number): Promise\> Errors: `APIError`, `TxSignError` -Provides lower-level ability for signing that produces the witnesses for just a single input in a transaction. This exists in case dApps need to construct a transaction to satisfy certain properties and the user might only own some of the inputs. The wallet should ask user permission for signing similar to `cardano.sign_tx_input()` and errors are handled in the same way. +Provides lower-level ability for signing that produces the witnesses for just a single input in a transaction. This exists in case dApps need to construct a transaction to satisfy certain properties and the user might only own some of the inputs. The wallet should ask user permission for signing similar to `api.sign_tx_input()` and errors are handled in the same way. -### cardano.sign_data(addr: cbor\
, sig_structure: cbor\): Promise\ +### api.sign_data(addr: cbor\
, sig_structure: cbor\): Promise\ Errors: `APIError`, `DataSignError` This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md) for standardization/safety reasons. It allows the dApp to request the user to sign data conforming to said spec. The user's consent should be requested and the details of `sig_structure` shown to them in an informative way. The Please refer to the CIP-0008 spec for details on how to construct the sig structure. -### cardano.submit_tx(tx: cbor\): Promise\ +### api.submit_tx(tx: cbor\): Promise\ Errors: `APIError`, `TxSendError` From db4194516a5a43ac74d4a38f7c0f24335d04cf95 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Tue, 3 Aug 2021 22:32:31 -0500 Subject: [PATCH 05/15] Switch to lowerCamelCase names for methods in the API to better fit JS standards --- CIP-DappConnector/CIP-dapp-connector.md | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index f67b946f55..b79d931bd8 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -148,19 +148,19 @@ type TxSignError = { ## Initial API -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.wallet_name.request_read_access()` in order for the dApp to read any information pertaining to the user's wallet. +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.requestReadAccess()` in order for the dApp to read any information pertaining to the user's wallet. -### wallet.request_read_access(): Promise\ +### wallet.requestReadAccess(): Promise\ Errors: 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 full API will be returned to 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, and instead just return the `API` object. -### wallet.check_read_access(): Promise\ +### wallet.checkReadAccess(): Promise\ Errors: 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. If this function returns true, then any subsequent calls to `wallet.request_read_access()` during the current session should succeed and return the `API` object. +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. If this function returns true, then any subsequent calls to `wallet.requestReadAccess()` during the current session should succeed and return the `API` object. ### wallet.version(): String @@ -179,59 +179,59 @@ Returns a name for the wallet which can be used inside of the dApp for the purpo ## Full API -Upon successful connection via `wallet.request_read_access()`, 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 `wallet.request_read_access()`. The remaining methods `api.sign_tx()`, `api.sign_tx_input()`, `api.sign_data()` must request the user's consent in an informative way for each and every API call in order to maintain security. +Upon successful connection via `wallet.requestReadAccess()`, 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 `wallet.requestReadAccess()`. The remaining methods `api.signTx()`, `api.signTxInput()`, `api.signData()` must request the user's consent in an informative way for each and every API call in order to maintain security. The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. -### api.get_utxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ +### api.getUtxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ Errors: `APIError`, `PaginateError` If `amount` is `undefined`, this shall return a list of all UTXOs (unspent transaction outputs) controlled by the wallet. If `amount` is not `undefined`, 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, `undefined` shall be returned. The results can be further paginated by `paginate` if it is not `undefined`. -### api.get_balance(): Promise\> +### api.getBalance(): Promise\> Errors: `APIError` -Returns the total balance available of the wallet. This is the same as summing the results of `api.get_utxos()`, 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. +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. -### api.get_used_addresses(paginate: Paginate = undefined): Promise\[]> +### api.getUsedAddresses(paginate: Paginate = undefined): Promise\[]> Errors: `APIError` Returns a list of all used (included in some on-chain transaction) addresses controlled by the wallet. The results can be further paginated by `paginate` if it is not `undefined`. -### api.get_unused_addresses(): Promise\[]> +### api.getUnusedAddresses(): Promise\[]> Errors: `APIError` Returns a list of unused addresses controlled by the wallet. -### api.get_change_address(): Promise\> +### api.getChangeAddress(): Promise\> Errors: `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. -### api.sign_tx(tx: cbor\, metadata: cbor\ = undefined): Promise\> +### api.signTx(tx: cbor\, metadata: cbor\ = undefined): Promise\> Errors: `APIError`, `TxSignError` Requests that a user sign the supplied transaction body. The wallet should ask the user for permission, and if given, try to sign the supplied body and return a signed transaction. If the wallet could not sign the transaction, `TxSignError` shall be returned with the `ProofGeneration` code. Likewise if the user declined it shall return the `UserDeclined` code. -### api.sign_tx_input(tx: cbor\, index: number): Promise\> +### api.signTxInput(tx: cbor\, index: number): Promise\> Errors: `APIError`, `TxSignError` -Provides lower-level ability for signing that produces the witnesses for just a single input in a transaction. This exists in case dApps need to construct a transaction to satisfy certain properties and the user might only own some of the inputs. The wallet should ask user permission for signing similar to `api.sign_tx_input()` and errors are handled in the same way. +Provides lower-level ability for signing that produces the witnesses for just a single input in a transaction. This exists in case dApps need to construct a transaction to satisfy certain properties and the user might only own some of the inputs. The wallet should ask user permission for signing similar to `api.signTxInput()` and errors are handled in the same way. -### api.sign_data(addr: cbor\
, sig_structure: cbor\): Promise\ +### api.signData(addr: cbor\
, sigStructure: cbor\): Promise\ Errors: `APIError`, `DataSignError` This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md) for standardization/safety reasons. It allows the dApp to request the user to sign data conforming to said spec. The user's consent should be requested and the details of `sig_structure` shown to them in an informative way. The Please refer to the CIP-0008 spec for details on how to construct the sig structure. -### api.submit_tx(tx: cbor\): Promise\ +### api.submitTx(tx: cbor\): Promise\ Errors: `APIError`, `TxSendError` From b473884c9d208ed085414fb51fb339d09f4443e2 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Tue, 3 Aug 2021 23:27:54 -0500 Subject: [PATCH 06/15] redo tx signing endpoints --- CIP-DappConnector/CIP-dapp-connector.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index b79d931bd8..ca6483cda4 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -179,7 +179,7 @@ Returns a name for the wallet which can be used inside of the dApp for the purpo ## Full API -Upon successful connection via `wallet.requestReadAccess()`, 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 `wallet.requestReadAccess()`. The remaining methods `api.signTx()`, `api.signTxInput()`, `api.signData()` must request the user's consent in an informative way for each and every API call in order to maintain security. +Upon successful connection via `wallet.requestReadAccess()`, 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 `wallet.requestReadAccess()`. The remaining methods `api.signTx()` and `api.signData()` must request the user's consent in an informative way for each and every API call in order to maintain security. The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. @@ -213,17 +213,11 @@ Errors: `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. -### api.signTx(tx: cbor\, metadata: cbor\ = undefined): Promise\> +### api.signTx(tx: cbor\, partialSign: bool = false): Promise\> Errors: `APIError`, `TxSignError` -Requests that a user sign the supplied transaction body. The wallet should ask the user for permission, and if given, try to sign the supplied body and return a signed transaction. If the wallet could not sign the transaction, `TxSignError` shall be returned with the `ProofGeneration` code. Likewise if the user declined it shall return the `UserDeclined` code. - -### api.signTxInput(tx: cbor\, index: number): Promise\> - -Errors: `APIError`, `TxSignError` - -Provides lower-level ability for signing that produces the witnesses for just a single input in a transaction. This exists in case dApps need to construct a transaction to satisfy certain properties and the user might only own some of the inputs. The wallet should ask user permission for signing similar to `api.signTxInput()` and errors are handled in the same way. +Requests that a user sign the unsigned portions of the supplied transaction. The wallet should ask the user for permission, and if given, try to sign the supplied body and return a signed transaction. If `partialSign` is true, the wallet only tries to sign what it can. If `partialSign` is false and the wallet could not sign the entire transaction, `TxSignError` shall be returned with the `ProofGeneration` code. Likewise if the user declined in either case it shall return the `UserDeclined` 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. ### api.signData(addr: cbor\
, sigStructure: cbor\): Promise\ From 0b2488ad68d3a6486a2a0737265f337012a4b468 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Wed, 25 Aug 2021 21:46:31 -0500 Subject: [PATCH 07/15] API renaming + tentatively use CIP-0030 as CIP number --- CIP-DappConnector/CIP-dapp-connector.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index ca6483cda4..12b4b80e87 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -1,5 +1,5 @@ --- -CIP: ? +CIP: 30 Title: Cardano dApp-Wallet Web Bridge Authors: rooooooooob Status: Draft @@ -148,28 +148,28 @@ type TxSignError = { ## Initial API -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.requestReadAccess()` in order for the dApp to read any information pertaining to the user's wallet. +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. -### wallet.requestReadAccess(): Promise\ +### wallet.enable(): Promise\ Errors: 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 full API will be returned to 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, and instead just return the `API` object. -### wallet.checkReadAccess(): Promise\ +### wallet.isEnabled(): Promise\ Errors: 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. If this function returns true, then any subsequent calls to `wallet.requestReadAccess()` during the current session should succeed and return the `API` object. +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. If this function returns true, then any subsequent calls to `wallet.enable()` during the current session should succeed and return the `API` object. -### wallet.version(): String +### wallet.version: String Errors: APIError Returns the version number of the API that the wallet supports. -### wallet.name(): String +### wallet.name: String Errors: APIError @@ -179,7 +179,7 @@ Returns a name for the wallet which can be used inside of the dApp for the purpo ## Full API -Upon successful connection via `wallet.requestReadAccess()`, 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 `wallet.requestReadAccess()`. The remaining methods `api.signTx()` and `api.signData()` must request the user's consent in an informative way for each and every API call in order to maintain security. +Upon successful connection via `wallet.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 `wallet.enable()`. The remaining methods `api.signTx()` and `api.signData()` must request the user's consent in an informative way for each and every API call in order to maintain security. The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. From fa4e7da9eed308de152fdec4716fad6442746976 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Thu, 26 Aug 2021 00:06:07 -0500 Subject: [PATCH 08/15] Apply suggestions from code review Shelley Mary -> Shelley Multiasset in referencing the CDDL file Co-authored-by: Rhys Bartels-Waller --- CIP-DappConnector/CIP-dapp-connector.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index 12b4b80e87..fa8629838b 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -33,12 +33,12 @@ A hex-encoded string of the corresponding bytes. ### cbor\ -A hex-encoded string representing [CBOR](https://tools.ietf.org/html/rfc7049) corresponding to `T` defined via [CDDL](https://tools.ietf.org/html/rfc8610) either inside of the [Shelley Mary binary spec](https://github.com/input-output-hk/cardano-ledger-specs/blob/0738804155245062f05e2f355fadd1d16f04cd56/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl) or, if not present there, from the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md). +A hex-encoded string representing [CBOR](https://tools.ietf.org/html/rfc7049) corresponding to `T` defined via [CDDL](https://tools.ietf.org/html/rfc8610) either inside of the [Shelley Mult-asset binary spec](https://github.com/input-output-hk/cardano-ledger-specs/blob/0738804155245062f05e2f355fadd1d16f04cd56/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl) or, if not present there, from the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md). This representation was chosen when possible as it is consistent across the Cardano ecosystem and widely used by other tools, such as [cardano-serialization-lib](https://github.com/Emurgo/cardano-serialization-lib), which has support to encode every type in the binary spec as CBOR bytes. ### TransactionUnspentOutput -If we have CBOR specified by the following CDDL referencing the Shelley-Mara CDDL: +If we have CBOR specified by the following CDDL referencing the Shelley-MA CDDL: ```cddl transaction_unspent_output = [ input: transaction_input, @@ -50,7 +50,7 @@ then we define type TransactionUnspentOutput = cbor ``` -This allows us to use the output for constructing new transactions using it as an output as the `transaction_output` in the Shelley Mary CDDL does not contain enough information on its own to spend it. +This allows us to use the output for constructing new transactions using it as an output as the `transaction_output` in the Shelley Multi-asset CDDL does not contain enough information on its own to spend it. ### Paginate From 0eba4d45556ff62af4d1bac3edb015c8ffa8875c Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Thu, 26 Aug 2021 00:27:08 -0500 Subject: [PATCH 09/15] add reward address endpoint --- CIP-DappConnector/CIP-dapp-connector.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index fa8629838b..3b4723daea 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -213,6 +213,12 @@ Errors: `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. +### api.getRewardAddresses(): Promise\[]> + +Errors: `APIError` + +Returns the reward addresses owned by the wallet. This can return multiple addresses e.g. CIP-0018. + ### api.signTx(tx: cbor\, partialSign: bool = false): Promise\> Errors: `APIError`, `TxSignError` From ce242ec42f805b6a7cdc9678cde05d115659695b Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Tue, 31 Aug 2021 21:01:39 -0500 Subject: [PATCH 10/15] getNetworkId API + start of events section --- CIP-DappConnector/CIP-dapp-connector.md | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index 3b4723daea..8ecb6d1c55 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -183,6 +183,12 @@ Upon successful connection via `wallet.enable()`, a javascript object we will re The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. +### api.getNetworkId(): Promise\ + +Errors: `APIError` + +Returns the network id of the currently connected account. 0 is testnet and 1 is mainnet. This result will stay the same unless an `account_changed` event has been emitted. + ### api.getUtxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ Errors: `APIError`, `PaginateError` @@ -237,6 +243,27 @@ Errors: `APIError`, `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 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). +## Events + +In addition to the API methods that are actively called, the connector also must emit the following events. All methods events are required to be implemented. + +TODO: event emission method? Possible methods: + +1) Emitted event via `window.addEventListener(eventName , e => void)` +2) Emitted message via `window.postMessage({eventName: string}, ...)` +3) Some kind of callback registration i.e. `wallet.onDisconnect(() => void)` or `wallet.onEvent(eventName => void)` +4) A combination of the two (event/message but with callback on `wallet` object as well +5) Other? + +### wallet_disconnected + +Emitted when the user disconnects (not just changes) their current account from the page. This means that all `api` methods will return with an `APIError.Refused` error and a new `api` object must be obtained from `wallet.enable()` to continue to interact with the user's wallet. + +### account_changed + +Emitted when the user changes accounts (i.e. different root key pair and/or network id). The same `api` object will continue to work but will now return results based on the new account. After this event is received dApps should check `api.getNetworkId()` as changing accounts can also change the network. + + # Implementations TODO: link to Yoroi's implementation once available From 59ffb321aabd7f7e1bcf26257be4622a84fbb2be Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Wed, 20 Oct 2021 15:46:12 -0500 Subject: [PATCH 11/15] wallet.version -> wallet.apiVersion Co-authored-by: Rhys Bartels-Waller --- CIP-DappConnector/CIP-dapp-connector.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index 8ecb6d1c55..498e72733a 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -162,7 +162,7 @@ Errors: 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. If this function returns true, then any subsequent calls to `wallet.enable()` during the current session should succeed and return the `API` object. -### wallet.version: String +### wallet.apiVersion: String Errors: APIError From a34e86b8c6cdc7fd9adf21380fa08583d5dc7565 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Thu, 21 Oct 2021 00:00:23 -0500 Subject: [PATCH 12/15] Connector final changes * wallet.icon property added * wallet properties have APIError removed as they are not functions * added comments-URI * clarified limitation on pagination * removed events API (to be added later) so we can merge this * APIErrorCode.AccountChange added to make up for lack of events API * clarify the ability for other networks besides 0/1 on `api.getNetworkId()` * link to nami-wallet implementation --- CIP-DappConnector/CIP-dapp-connector.md | 39 +++++++------------------ 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-DappConnector/CIP-dapp-connector.md index 498e72733a..dd2ab22334 100644 --- a/CIP-DappConnector/CIP-dapp-connector.md +++ b/CIP-DappConnector/CIP-dapp-connector.md @@ -2,6 +2,7 @@ CIP: 30 Title: Cardano dApp-Wallet Web Bridge Authors: rooooooooob +Comments-URI: https://github.com/cardano-foundation/CIPs/pull/88 Status: Draft Type: Standards Created: 2021-04-29 @@ -60,7 +61,7 @@ type Paginate = {| limit: number, |}; ``` -Used to specify optional pagination for some API calls. Limits results to {limit} each page, and uses a 0-indexing {page} to refer to which of those pages of {limit} items each. +Used to specify optional pagination for some API calls. Limits results to {limit} each page, and uses a 0-indexing {page} to refer to which of those pages of {limit} items each. dApps should be aware that if a wallet is modified between paginated calls that this will change the pagination, e.g. some results skipped or showing up multiple times but otherwise the wallet must respect the pagination order. ## Error Types @@ -72,6 +73,7 @@ APIErrorCode { InvalidRequest: -1, InternalError: -2, Refused: -3, + AccountChange: 4, } APIError { code: APIErrorCode, @@ -82,6 +84,7 @@ APIError { * InvalidRequest - Inputs do not conform to this spec or are otherwise invalid. * InternalError - An error occurred during execution of this API call. * Refused - The request was refused due to lack of access - e.g. wallet disconnects. +* AccountChange - 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. ### DataSignError @@ -164,17 +167,16 @@ Returns true if the dApp is already connected to the user's wallet, or if reques ### wallet.apiVersion: String -Errors: APIError - -Returns the version number of the API that the wallet supports. +The version number of the API that the wallet supports. ### wallet.name: String -Errors: APIError +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. -Returns 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 connect with. +### wallet.icon: String +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. ## Full API @@ -187,7 +189,7 @@ The API chosen here is for the minimum API necessary for dApp <-> Wallet interac Errors: `APIError` -Returns the network id of the currently connected account. 0 is testnet and 1 is mainnet. This result will stay the same unless an `account_changed` event has been emitted. +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. ### api.getUtxos(amount: cbor\ = undefined, paginate: Paginate = undefined): Promise\ @@ -243,27 +245,6 @@ Errors: `APIError`, `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 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). -## Events - -In addition to the API methods that are actively called, the connector also must emit the following events. All methods events are required to be implemented. - -TODO: event emission method? Possible methods: - -1) Emitted event via `window.addEventListener(eventName , e => void)` -2) Emitted message via `window.postMessage({eventName: string}, ...)` -3) Some kind of callback registration i.e. `wallet.onDisconnect(() => void)` or `wallet.onEvent(eventName => void)` -4) A combination of the two (event/message but with callback on `wallet` object as well -5) Other? - -### wallet_disconnected - -Emitted when the user disconnects (not just changes) their current account from the page. This means that all `api` methods will return with an `APIError.Refused` error and a new `api` object must be obtained from `wallet.enable()` to continue to interact with the user's wallet. - -### account_changed - -Emitted when the user changes accounts (i.e. different root key pair and/or network id). The same `api` object will continue to work but will now return results based on the new account. After this event is received dApps should check `api.getNetworkId()` as changing accounts can also change the network. - - # Implementations -TODO: link to Yoroi's implementation once available +[nami-wallet](https://github.com/Berry-Pool/nami-wallet/blob/master/src/pages/Content/injected.js) From 667849d5c1903fa7f2d702d49a72a4326539597b Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Tue, 9 Nov 2021 02:14:24 -0800 Subject: [PATCH 13/15] move CIP-0030 to correct directory/filename --- CIP-DappConnector/CIP-dapp-connector.md => CIP-0030/CIP-0030.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CIP-DappConnector/CIP-dapp-connector.md => CIP-0030/CIP-0030.md (100%) diff --git a/CIP-DappConnector/CIP-dapp-connector.md b/CIP-0030/CIP-0030.md similarity index 100% rename from CIP-DappConnector/CIP-dapp-connector.md rename to CIP-0030/CIP-0030.md From d4d67bb0a45be8acc3ca69ba40ff7b365a7bf460 Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Tue, 9 Nov 2021 02:18:37 -0800 Subject: [PATCH 14/15] rename CIP-0030/CIP-0030.md -> CIP-0030/README.md --- CIP-0030/{CIP-0030.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CIP-0030/{CIP-0030.md => README.md} (100%) diff --git a/CIP-0030/CIP-0030.md b/CIP-0030/README.md similarity index 100% rename from CIP-0030/CIP-0030.md rename to CIP-0030/README.md From a22e4f749ca63f6f9bb6d65fac536e20f404ed6b Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Thu, 11 Nov 2021 21:04:52 -0800 Subject: [PATCH 15/15] CIP-0030: last minute changes (responding to @KtorZ's remarks) --- CIP-0030/README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/CIP-0030/README.md b/CIP-0030/README.md index dd2ab22334..e706d1ab07 100644 --- a/CIP-0030/README.md +++ b/CIP-0030/README.md @@ -73,7 +73,7 @@ APIErrorCode { InvalidRequest: -1, InternalError: -2, Refused: -3, - AccountChange: 4, + AccountChange: -4, } APIError { code: APIErrorCode, @@ -151,37 +151,37 @@ type TxSignError = { ## Initial API -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. +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. -### wallet.enable(): Promise\ +### cardano.{walletName}.enable(): Promise\ Errors: 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 full API will be returned to 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, and instead just return the `API` object. -### wallet.isEnabled(): Promise\ +### cardano.{walletName}.isEnabled(): Promise\ Errors: 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. If this function returns true, then any subsequent calls to `wallet.enable()` during the current session should succeed and return the `API` object. -### wallet.apiVersion: String +### cardano.{walletName}.apiVersion: String The version number of the API that the wallet supports. -### wallet.name: String +### cardano.{walletName}.name: String 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. -### wallet.icon: String +### cardano.{walletName}.icon: String 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. ## Full API -Upon successful connection via `wallet.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 `wallet.enable()`. The remaining methods `api.signTx()` and `api.signData()` must request the user's consent in an informative way for each and every API call in order to maintain security. +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()` and `api.signData()` must request the user's consent in an informative way for each and every API call in order to maintain security. The API chosen here is for the minimum API necessary for dApp <-> Wallet interactions without convenience functions that don't strictly need the wallet's state to work. The API here is for now also only designed for Shelley's Mary hardfork and thus has NFT support. When Alonzo is released with Plutus support this API will have to be extended. @@ -237,6 +237,8 @@ Requests that a user sign the unsigned portions of the supplied transaction. The Errors: `APIError`, `DataSignError` +This endpoint is due to be updated/finalized soon, see [discussion in the initial PR](https://github.com/cardano-foundation/CIPs/pull/88#issuecomment-954436243). + This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md) for standardization/safety reasons. It allows the dApp to request the user to sign data conforming to said spec. The user's consent should be requested and the details of `sig_structure` shown to them in an informative way. The Please refer to the CIP-0008 spec for details on how to construct the sig structure. ### api.submitTx(tx: cbor\): Promise\