Skip to content

Commit

Permalink
feat(connect): add wallet client docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mrcnk committed Sep 22, 2024
1 parent b868505 commit 6a30802
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 17 deletions.
229 changes: 229 additions & 0 deletions apps/docs/src/pages/connect/wallet-client.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
# Wallet Client [One API to rull them all.]

If you missed a Wallet Client from Viem, you can use MinaJS's Wallet Client to interact with Mina wallets. It's a one API that wraps over various wallet types and connectivities.

## Client properties

- `network`: Network type. `devnet` or `mainnet`.
- `account`: Account object compatible with `toAccount` format. `string` or `Account` object. If not provided, the client will use the last injected wallet.
- `providerSource`: Provider source. `klesia` (JSON-RPC account), `window.mina` (last injected wallet), `string` (slug of specific browser wallet). Default is `window.mina`.

## Initialize client

```ts twoslash
import { createWalletClient } from '@mina-js/connect'

const client = createWalletClient({ network: "devnet" });
```

## Querying the data

### From injected wallet

Query from the last injected wallet (using `window.mina`):

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect'

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const balance = await client.getBalance();
```

Query from a specific browser wallet (using slug of a specific injected wallet):

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect'

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({
account,
network: "devnet",
providerSource: 'pallad'
});

const balance = await client.getBalance();
```

### From Klesia JSON-RPC

Query data from our [Klesia JSON-RPC](/klesia):

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect'

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({
account,
network: "devnet",
providerSource: 'klesia'
});

const balance = await client.getBalance();
```

## Wallet queries

### Get balance

Query current wallet's balance.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect'

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const balance = await client.getBalance();
```

### Get accounts

Query wallet addresses of an injected wallet.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect'

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const balance = await client.getAccounts();
```

### Get transaction count

Query the number of transactions of a wallet (used as nonce).

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect'

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const transactionCount = await client.getTransactionCount();
```

### Get chain ID

Query the chain ID of the network.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect'

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const chainId = await client.getChainId();
```

### Get estimated fees

Query the estimated fees of a transaction.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect'

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const fees = await client.estimateFees();
```

## Wallet commands

If you provide a local wallet, Wallet Client will sign with it, otherwise, it will use the injected wallet.

### Sign a message

Sign a message with either the injected wallet or a local wallet.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect';

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ network: "devnet" });

const signature = await client.signMessage({ message: 'Hello World' })
```

### Sign a transaction

Sign a transaction with either the injected wallet or a local wallet.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect';

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const signature = await client.signTransaction({
transaction: {
nonce: 1n,
from: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5",
to: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5",
amount: 3000000000n,
fee: 100000000n,
}
})
```

### Sign fields

Sign fields of a transaction with either the injected wallet or a local wallet.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect';

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const signature = await client.signFields({
fields: [1n, 2n, 3n]
})
```

### Create a nullifier

Create a nullifier with either the injected wallet or a local wallet.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect';

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const nullifier = await client.createNullifier({
message: [1n, 2n, 3n]
});
```

### Prepare a transaction request

There is a helper method to prepare a transaction request that lacks either nonce or fee. This will fetch the correct nonce for you and estimate a `medium` fee that ensures the transaction is included in the next block.

```ts twoslash
import { toAccount } from "@mina-js/accounts";
import { createWalletClient } from '@mina-js/connect';

const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
const client = createWalletClient({ account, network: "devnet" });

const transactionRequest = await client.prepareTransactionRequest({
from: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5",
to: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5",
amount: 3000000000n,
})
```
3 changes: 3 additions & 0 deletions apps/docs/vocs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { remarkMermaid } from "@theguild/remark-mermaid";
import { defineConfig } from "vocs";

export default defineConfig({
ogImageUrl:
"https://vocs.dev/api/og?logo=%logo&title=%title&description=%description",
title: "MinaJS",
description: "The TypeScript interface for Mina Protocol.",
rootDir: "src",
Expand Down Expand Up @@ -87,6 +89,7 @@ export default defineConfig({
{ text: "Getting Started", link: "/connect/getting-started" },
{ text: "Provider Discovery", link: "/connect/provider-discovery" },
{ text: "Wallet Interface", link: "/connect/wallet-interface" },
{ text: "Wallet Client", link: "/connect/wallet-client" },
],
},
{
Expand Down
3 changes: 1 addition & 2 deletions packages/connect/src/client.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { describe, expect, it } from "bun:test";
import { privateKeyToAccount } from "@mina-js/accounts";
import { toAccount } from "@mina-js/accounts";
import { privateKeyToAccount, toAccount } from "@mina-js/accounts";
import { Test } from "@mina-js/shared";
import { createWalletClient } from "./client";

Expand Down
45 changes: 30 additions & 15 deletions packages/connect/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type WalletProviderSlug = "pallad";
export type ProviderSource = "window.mina" | "klesia" | WalletProviderSlug;

export type CreateWalletClientProps = {
account: Account;
account?: Account;
network: "mainnet" | "devnet";
providerSource?: ProviderSource;
};
Expand All @@ -40,7 +40,7 @@ export const createWalletClient = ({
const klesiaClient = createClient({ network });
const getAccounts = async () => {
return match(providerSource)
.with("klesia", () => [account.publicKey])
.with("klesia", () => (account ? [account.publicKey] : []))
.otherwise(async () => {
const provider = getWalletProvider(providerSource);
const { result } = await provider.request<"mina_accounts">({
Expand All @@ -50,23 +50,30 @@ export const createWalletClient = ({
});
};
const getBalance = async () => {
const getBalanceFromInjectedWallet = async () => {
const provider = getWalletProvider(providerSource);
const { result } = await provider.request<"mina_getBalance">({
method: "mina_getBalance",
});
return result;
};
const getBalanceFromKlesia = async (account: Account) => {
const { result } = await klesiaClient.request<"mina_getBalance">({
method: "mina_getBalance",
params: [account.publicKey],
});
return BigInt(result);
};
return match(providerSource)
.with("klesia", async () => {
const { result } = await klesiaClient.request<"mina_getBalance">({
method: "mina_getBalance",
params: [account.publicKey],
});
return BigInt(result);
if (account) return getBalanceFromKlesia(account);
return getBalanceFromInjectedWallet();
})
.otherwise(async () => {
const provider = getWalletProvider(providerSource);
const { result } = await provider.request<"mina_getBalance">({
method: "mina_getBalance",
});
return result;
});
.otherwise(getBalanceFromInjectedWallet);
};
const getTransactionCount = async () => {
if (!account)
throw new Error("Account is required to get transaction count");
const { result } = await klesiaClient.request<"mina_getTransactionCount">({
method: "mina_getTransactionCount",
params: [account.publicKey],
Expand All @@ -90,26 +97,34 @@ export const createWalletClient = ({
});
};
const signTransaction: SignTransaction = async (params) => {
if (!account) throw new Error("Account is required to sign transaction");
if (account.type !== "local") throw new Error("Account type not supported");
return account.signTransaction(params);
};
const signMessage: SignMessage = async (params) => {
if (!account) throw new Error("Account is required to sign message");
if (account.type !== "local") throw new Error("Account type not supported");
return account.signMessage(params);
};
const signFields: SignFields = async (params) => {
if (!account) throw new Error("Account is required to sign fields");
if (account.type !== "local") throw new Error("Account type not supported");
return account.signFields(params);
};
const createNullifier: CreateNullifier = async (params) => {
if (!account) throw new Error("Account is required to create nullifier");
if (account.type !== "local") throw new Error("Account type not supported");
return account.createNullifier(params);
};
const estimateFees = async () => {
const { result } = await klesiaClient.request<"mina_estimateFees">({
method: "mina_estimateFees",
});
return result;
return {
low: BigInt(result.low),
medium: BigInt(result.medium),
high: BigInt(result.high),
};
};
const prepareTransactionRequest = async (
transaction: PartiallyFormedTransactionProperties,
Expand Down
1 change: 1 addition & 0 deletions packages/connect/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./store";
export * from "./events";
export * from "./client";
export type { MinaProviderDetail } from "@mina-js/providers";

0 comments on commit 6a30802

Please sign in to comment.