-
Notifications
You must be signed in to change notification settings - Fork 323
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 | Events API #151
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,7 +73,6 @@ APIErrorCode { | |
InvalidRequest: -1, | ||
InternalError: -2, | ||
Refused: -3, | ||
AccountChange: -4, | ||
} | ||
APIError { | ||
code: APIErrorCode, | ||
|
@@ -84,7 +83,6 @@ 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 | ||
|
||
|
@@ -247,6 +245,30 @@ 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these events be exposed as an enum or constants as well? Similarly to how errors are |
||
|
||
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: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's best to emit Regarding the method/naming:
This leaves us with the following options:
Also, I suggest documenting that wallets will automatically unsubscribe all event listeners when disconnected (so dApps know they don't have to do that). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
👍 for this suggestion, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
And there are quite known APIs that utilize similar pattern:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kapke imo that doesn't make sense. The reason why React and Observable does it like that is because they housekeep the event, which makes sense if you are observing the values. In React, for example, you can only (unconditionally) call |
||
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be useful to have an event on // cardano.{walletName}.name: String
// key is the "walletName" here
type NewWallet = { apiVersion: string; name: string; key: string; icon: string; }
cardano.on('wallet-connected', (newWallet: NewWallet => void); alongside with:
|
||
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, when removing the dApp from the whitelist, implementation should make sure to emit the event to the page only if the page origin (host) matches the removed host. App developers should only face |
||
|
||
### account_changed | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could treat account change as disconnect and connect - one thing less to handle for dApps. Wallets would have to ensure that wallet key is unique for each account. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would argue that form the app perspective, the user is still "connected", just with different data. An account-change event would be enough to let developers know that the UI should be updated. Also thinking of a disconnect/connect perspective, devs would show/hide |
||
|
||
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is extremely weird and confusing to me along with the rest of the network-id handling in the spec. Shouldn't the dapp be the one that can dictate the connector which network it works on? Simple example, imagine a dex dapp that displays on its main page the listing of active offers existing on the chain from other users. Now to do that the dapp must know which offers to select from its database to display them. Imagine I am a developer of that dapp and I have two versions of the dapp one for the mainnet network and one for the testnet network as a dev/test version. Now on the mainnet version of the dapp I am obviously only listing the mainnet offers from the mainnet chain. And then suddenly I get an event that the user has connected or switched to a testnet account. What am I supposed to do in this situation? Redirect the user to a completely different version of the dapp that lists stuff from the testnet? What if I don't have this version publicly available? Or what if my design it to only request the connection on the latest step when the user already selected which offer they want to purchase, and then suddenly I am presented with the fact that the user account is not on the same network as the offer they have just selected? This adds incredible awkwardness to the entire communication and puts the dapps into an awful position of having to deal with the situation when the user can select the network the dapp have not been expecting, while ideally it would be encapsulated in the wallet itself. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
|
||
|
||
# Implementations | ||
|
||
[nami-wallet](https://github.com/Berry-Pool/nami-wallet/blob/master/src/pages/Content/injected.js) |
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.
Do we want to treat changing accounts as still a single session with a single
api
object that will just suddenly switch from which account they are pulling data from? That was the current state of the events API before. On one and it'd be easier to handle account switches, but on the other it might make gotchas for dApps if they don't listen to events well and forget data from a previous account. If we go the other way then account changes/disconnects would be basically handled the same (with different events emitted/error codes when trying to use the oldapi
object) but with the difference that wallets should not re-ask for user permission if theapi
object invalidation was due to an account change, but would if it was due to a disconnect (depending on how the wallet implements their whitelist I guess).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.
Imo having events would be much easier to handle. I could just subscribe to account/network change, and act accordingly (refresh the API, and get all needed data as balance, assets....). This is what I was doing for Nami and it worked really nice.
Right now with ccvault wallet following CIP-0030, I cant subscribe. And what happens is that API returns the 'account changed' error when trying to do something if I change the account with the dApp openned and with old state. I have to manage this anyways, but it is harder, as I need to add protections in every API call to handle this error (that should not be an error imo. Changing account or network is a normal behaviour from users).
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.
@josemmrocha
In the spec so far in this PR, if we remove this error code, could the situations where you would have had to add protections potentially be a source of bugs in dApps if they're starting to mix up data between the old and new account? I made this comment just trying to find a good balance between the dev experience but also in reducing potential for confusion/bugs in dApps using this API.
What about in-progress queries (especially ones requiring user input like signing)? Should those get rejected (which error code?) or still be allowed to complete as normal?
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.
I think this is exactly what this error should be for.