-
Notifications
You must be signed in to change notification settings - Fork 317
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CIP-0030 | Dapp-Connector #88
Merged
crptmppt
merged 15 commits into
cardano-foundation:master
from
rooooooooob:cip-dapp-connector
Nov 17, 2021
+252
−0
Merged
Changes from 14 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
9a5f0d9
CIP-Dapp-Connector
rooooooooob 3cbc121
Update get_utxos() definition
rooooooooob 7072b2d
Minor requested changes
rooooooooob d63230a
Initial wording for multi-wallet support + versioning
rooooooooob db41945
Switch to lowerCamelCase names for methods in the API to better fit J…
rooooooooob b473884
redo tx signing endpoints
rooooooooob 0b2488a
API renaming + tentatively use CIP-0030 as CIP number
rooooooooob fa4e7da
Apply suggestions from code review
rooooooooob 0eba4d4
add reward address endpoint
rooooooooob ce242ec
getNetworkId API + start of events section
rooooooooob 59ffb32
wallet.version -> wallet.apiVersion
rooooooooob a34e86b
Connector final changes
rooooooooob 667849d
move CIP-0030 to correct directory/filename
rooooooooob d4d67bb
rename CIP-0030/CIP-0030.md -> CIP-0030/README.md
rooooooooob a22e4f7
CIP-0030: last minute changes (responding to @KtorZ's remarks)
rooooooooob File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
--- | ||
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 | ||
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 | ||
|
||
## Version | ||
|
||
The API specified in this document will count as version 0.1.0 for version-checking purposes below. | ||
|
||
## Data Types | ||
|
||
### Bytes | ||
|
||
A hex-encoded string of the corresponding bytes. | ||
|
||
### cbor\<T> | ||
|
||
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-MA CDDL: | ||
```cddl | ||
transaction_unspent_output = [ | ||
input: transaction_input, | ||
output: transaction_output, | ||
] | ||
``` | ||
then we define | ||
``` | ||
type TransactionUnspentOutput = cbor<transaction_unspent_output> | ||
``` | ||
|
||
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 | ||
|
||
``` | ||
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. 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 | ||
|
||
### APIError | ||
|
||
``` | ||
APIErrorCode { | ||
InvalidRequest: -1, | ||
InternalError: -2, | ||
Refused: -3, | ||
AccountChange: 4, | ||
} | ||
APIError { | ||
code: APIErrorCode, | ||
info: string | ||
} | ||
``` | ||
|
||
* 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 | ||
|
||
``` | ||
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. | ||
|
||
### 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 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.enable(): Promise\<API> | ||
|
||
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\<bool> | ||
|
||
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 | ||
|
||
The version number of the API that the wallet supports. | ||
|
||
|
||
### wallet.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 | ||
|
||
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. | ||
|
||
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\<number> | ||
|
||
Errors: `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. | ||
|
||
### api.getUtxos(amount: cbor\<value> = undefined, paginate: Paginate = undefined): Promise\<TransactionUnspentOutput[] | 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`. | ||
|
||
### api.getBalance(): Promise\<cbor\<value>> | ||
|
||
Errors: `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. | ||
|
||
### api.getUsedAddresses(paginate: Paginate = undefined): Promise\<cbor\<address>[]> | ||
|
||
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.getUnusedAddresses(): Promise\<cbor\<address>[]> | ||
|
||
Errors: `APIError` | ||
|
||
Returns a list of unused addresses controlled by the wallet. | ||
|
||
### api.getChangeAddress(): Promise\<cbor\<address>> | ||
|
||
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\<cbor\<address>[]> | ||
|
||
Errors: `APIError` | ||
|
||
Returns the reward addresses owned by the wallet. This can return multiple addresses e.g. CIP-0018. | ||
|
||
### api.signTx(tx: cbor\<transaction>, partialSign: bool = false): Promise\<cbor\<transaction_witness_set>> | ||
|
||
Errors: `APIError`, `TxSignError` | ||
|
||
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\<address>, sigStructure: cbor\<Sig_structure>): Promise\<Bytes> | ||
|
||
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.submitTx(tx: cbor\<transaction>): Promise\<hash32> | ||
|
||
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 | ||
|
||
[nami-wallet](https://github.com/Berry-Pool/nami-wallet/blob/master/src/pages/Content/injected.js) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently implementing this.
Was the - in front of 1,2,3 intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MarcelKlammer Yes it's intended so that they are distinct from the non-negative error codes specific to certain calls. However, that should be -4. I just fixed that in a final commit just now.