Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

KIP-0030: SpireKey dApp <> Wallet Connection #59

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions kip-0030.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
---
KIP: "0030"
Title: Kadena Spirekey Connect
Author: Andy Tang @EnoF
Status: Draft
Type: Standard
Category: Interface
Created: 2024-01-22
---

# Abstract

This document describes the proposal to provide an alternative way for
decentralized applications (dApps) to connect with wallets by using existing and
well-known Web2 conventions. The goal of this proposal is to improve the end
user experience when users are interacting with Web3 applications and wallets.

# Motivation

There are several ways to connect a decentralized application to a wallet to
enable users to sign transactions. However, the solutions currently available do
not provide a seamless experience for users or application developers.

In Web2 applications, there are well-established techniques to provide
authentications and authorization over multiple domains. One well-known and
widely-used approach in Web2 applications involves the use of the OAuth
protocol. By following this approach in Web3, applications and wallets can
provide a familiar user experience and offer a lower barrier for entry in the
registration process.

In implementing this proposal, wallets could serve as the new decentralized hub
for authentication and authorization services that are currently provided by
centralized services like Google, Twitter, and Facebook. With this solution,
wallets can reduce the friction for users to interact with decentralized
applications and increase user adoption of new services.

# Specifications

Wallets and applications communicate with the end user's browser using `https`.
All of the information between the wallet and the applcation is relayed using
the end user's browser. This specification covers the following main
communication points of interest:

- Notifications
- Connections
- Signing

In this specification, `typescript` is used to describe the data structures
expected in the communication between the wallet and the decentralized
applications. Note that if you want to use different languages, you can do so,
as long as the data that is sent to the application is in the format accepted by
the `postMessage` listeners.

## Notifications

To provide a seamless experience for the user, the wallet must provide a page to
be embedded in the application in the form of an iframe. This iframe is used to
indicate to the user that the wallet is processing a request. The wallet can use
this iframe to display a loading indicator in the style of the wallet. The
iFrame is expected to be hosted on the wallet's domain on the path
`/embedded/notification`.

The SDK can provide the notification frame for pending transactions for the
wallet to handle. This notification frame is provided by the hash parameter
`accounts`. The wallet can make use of the `txQueue` field in the `Account`
object to determine which transactions are pending and handle them accordingly.

## Connect

The application must provide a button to connect to the Wallet. The SpireKey SDK
displays a notification when another window has activity. This notification
allows the wallet to be opened in a new window and and ask the user to connect
to the application. The wallet should open on the path using the `/connect`
endpoint.

The application can provide additional parameters to the wallet by adding them
to the URL in the form of hash parameters. The parameters can be used to provide
additional context to the wallet about the environment in which the application
expects to operate. The parameters are: `chainId` and `networkId`.

The wallet is responsible for connecting existing accounts or helping the user
to create a new account. How the user is guided through this process is up to
the wallet.

After the user has connected a new account or selected an existing account, the
wallet should emit a `postMessage` event on the `window` of the wallet. In the
message, the wallet should include the following information:

```ts
type ConnectEventPayload = {
source: "kadena-spirekey";
name: "connected";
payload: Account;
};
```

If the user cancels the connection process, the wallet should close the window
and emit an event with the following information:

```ts
type CanceledConnectEventPayload = {
source: "kadena-spirekey";
name: "canceled:connect";
payload?: void;
};
```

## Sign

The application must provide a button to sign a transaction. The SpireKey SDK
displays a notification when another window has activity. This notification
allows the wallet to open a new window and ask the user to sign the transaction.
The wallet should open on the path using the `/sign` endpoint.

The wallet is responsible for displaying the transaction to the user and asking
for the user's approval. How the user is guided through this process is up to
the wallet.

The application should send a list of transactions to the wallet and,
optionally, a list of accounts that need to have fungibles avaible for the
transaction. The wallet can use this information to help the user send the funds
to the requested chain.

The application should send this information to the wallet in the form of hash
parameters. The parameters are: `transactions` and `accounts`.

- The `transactions` parameter is expected to be a JSON encoded array of
transactions.
- The `accounts` parameter is expected to be a JSON encoded array of
`OptimalTransactionsAccount` which is a subset of an `Account`.

After the user has signed for all necessary transactions, the wallet should
submit any transactions that are needed to send the funds to the requested
chain. The TransactionDescriptors for those transactions should be included in
the `postMessage` event.

The Wallet should emit the `postMessage` event on the `window` of the wallet
with the following information:

```ts
type SignEventPayload = {
source: "kadena-spirekey";
name: "signed";
payload: {
accounts: Account[];
txs: Record<string, { sig: string; pubKey: string }[]>;
};
};
```

If the user cancels the signing process, the wallet should close the window and
emit an event with the following information:

```ts
type CanceledSignEventPayload = {
source: "kadena-spirekey";
name: "canceled:sign";
payload?: void;
};
```

## Type references

### ConnectEventPayload

```ts
type ConnectEventPayload = {
source: "kadena-spirekey";
name: "connected";
payload: Account;
};
```

### Account

```ts
import type { ChainId, ITransactionDescriptor } from "@kadena/client";

export type QueuedTx = ITransactionDescriptor;

export type OptimalTransactionsAccount = Pick<
Account,
"chainIds" | "accountName" | "networkId" | "requestedFungibles"
>;
export type Account = {
alias: string;
accountName: string;
minApprovals: number;
minRegistrationApprovals: number;
balance: string;
devices: Device[];
guard?: Guard;
keyset?: Keyset;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this guard significantly different from the keyset? It would be good to explain the difference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right I haven't written about it, the difference being that the Keyset is the keyset currently registered on the defined keyset, and the guard being the create-ref-guard of that keyset definition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update the supporting text around it. 👍

networkId: string;
chainIds: ChainId[];
txQueue: QueuedTx[];
requestedFungibles?: RequestedFungible[];
};

export type Device = {
domain: string;
color: string;
deviceType: string;
["credential-id"]: string;
guard: Keyset;
pendingRegistrationTxs?: ITransactionDescriptor[];
name?: string;
};

export type Guard = RefKeyset | Keyset;
type RefKeyset = {
keysetref: {
ns: string;
ksn: string;
};
};
type Keyset = {
keys: string[];
pred: string;
};

export type RequestedFungible = {
fungible: string;
amount: number;
target?: ChainId;
};
```