Skip to content

Commit 6a30802

Browse files
committed
feat(connect): add wallet client docs
1 parent b868505 commit 6a30802

File tree

5 files changed

+264
-17
lines changed

5 files changed

+264
-17
lines changed
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
# Wallet Client [One API to rull them all.]
2+
3+
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.
4+
5+
## Client properties
6+
7+
- `network`: Network type. `devnet` or `mainnet`.
8+
- `account`: Account object compatible with `toAccount` format. `string` or `Account` object. If not provided, the client will use the last injected wallet.
9+
- `providerSource`: Provider source. `klesia` (JSON-RPC account), `window.mina` (last injected wallet), `string` (slug of specific browser wallet). Default is `window.mina`.
10+
11+
## Initialize client
12+
13+
```ts twoslash
14+
import { createWalletClient } from '@mina-js/connect'
15+
16+
const client = createWalletClient({ network: "devnet" });
17+
```
18+
19+
## Querying the data
20+
21+
### From injected wallet
22+
23+
Query from the last injected wallet (using `window.mina`):
24+
25+
```ts twoslash
26+
import { toAccount } from "@mina-js/accounts";
27+
import { createWalletClient } from '@mina-js/connect'
28+
29+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
30+
const client = createWalletClient({ account, network: "devnet" });
31+
32+
const balance = await client.getBalance();
33+
```
34+
35+
Query from a specific browser wallet (using slug of a specific injected wallet):
36+
37+
```ts twoslash
38+
import { toAccount } from "@mina-js/accounts";
39+
import { createWalletClient } from '@mina-js/connect'
40+
41+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
42+
const client = createWalletClient({
43+
account,
44+
network: "devnet",
45+
providerSource: 'pallad'
46+
});
47+
48+
const balance = await client.getBalance();
49+
```
50+
51+
### From Klesia JSON-RPC
52+
53+
Query data from our [Klesia JSON-RPC](/klesia):
54+
55+
```ts twoslash
56+
import { toAccount } from "@mina-js/accounts";
57+
import { createWalletClient } from '@mina-js/connect'
58+
59+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
60+
const client = createWalletClient({
61+
account,
62+
network: "devnet",
63+
providerSource: 'klesia'
64+
});
65+
66+
const balance = await client.getBalance();
67+
```
68+
69+
## Wallet queries
70+
71+
### Get balance
72+
73+
Query current wallet's balance.
74+
75+
```ts twoslash
76+
import { toAccount } from "@mina-js/accounts";
77+
import { createWalletClient } from '@mina-js/connect'
78+
79+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
80+
const client = createWalletClient({ account, network: "devnet" });
81+
82+
const balance = await client.getBalance();
83+
```
84+
85+
### Get accounts
86+
87+
Query wallet addresses of an injected wallet.
88+
89+
```ts twoslash
90+
import { toAccount } from "@mina-js/accounts";
91+
import { createWalletClient } from '@mina-js/connect'
92+
93+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
94+
const client = createWalletClient({ account, network: "devnet" });
95+
96+
const balance = await client.getAccounts();
97+
```
98+
99+
### Get transaction count
100+
101+
Query the number of transactions of a wallet (used as nonce).
102+
103+
```ts twoslash
104+
import { toAccount } from "@mina-js/accounts";
105+
import { createWalletClient } from '@mina-js/connect'
106+
107+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
108+
const client = createWalletClient({ account, network: "devnet" });
109+
110+
const transactionCount = await client.getTransactionCount();
111+
```
112+
113+
### Get chain ID
114+
115+
Query the chain ID of the network.
116+
117+
```ts twoslash
118+
import { toAccount } from "@mina-js/accounts";
119+
import { createWalletClient } from '@mina-js/connect'
120+
121+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
122+
const client = createWalletClient({ account, network: "devnet" });
123+
124+
const chainId = await client.getChainId();
125+
```
126+
127+
### Get estimated fees
128+
129+
Query the estimated fees of a transaction.
130+
131+
```ts twoslash
132+
import { toAccount } from "@mina-js/accounts";
133+
import { createWalletClient } from '@mina-js/connect'
134+
135+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
136+
const client = createWalletClient({ account, network: "devnet" });
137+
138+
const fees = await client.estimateFees();
139+
```
140+
141+
## Wallet commands
142+
143+
If you provide a local wallet, Wallet Client will sign with it, otherwise, it will use the injected wallet.
144+
145+
### Sign a message
146+
147+
Sign a message with either the injected wallet or a local wallet.
148+
149+
```ts twoslash
150+
import { toAccount } from "@mina-js/accounts";
151+
import { createWalletClient } from '@mina-js/connect';
152+
153+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
154+
const client = createWalletClient({ network: "devnet" });
155+
156+
const signature = await client.signMessage({ message: 'Hello World' })
157+
```
158+
159+
### Sign a transaction
160+
161+
Sign a transaction with either the injected wallet or a local wallet.
162+
163+
```ts twoslash
164+
import { toAccount } from "@mina-js/accounts";
165+
import { createWalletClient } from '@mina-js/connect';
166+
167+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
168+
const client = createWalletClient({ account, network: "devnet" });
169+
170+
const signature = await client.signTransaction({
171+
transaction: {
172+
nonce: 1n,
173+
from: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5",
174+
to: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5",
175+
amount: 3000000000n,
176+
fee: 100000000n,
177+
}
178+
})
179+
```
180+
181+
### Sign fields
182+
183+
Sign fields of a transaction with either the injected wallet or a local wallet.
184+
185+
```ts twoslash
186+
import { toAccount } from "@mina-js/accounts";
187+
import { createWalletClient } from '@mina-js/connect';
188+
189+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
190+
const client = createWalletClient({ account, network: "devnet" });
191+
192+
const signature = await client.signFields({
193+
fields: [1n, 2n, 3n]
194+
})
195+
```
196+
197+
### Create a nullifier
198+
199+
Create a nullifier with either the injected wallet or a local wallet.
200+
201+
```ts twoslash
202+
import { toAccount } from "@mina-js/accounts";
203+
import { createWalletClient } from '@mina-js/connect';
204+
205+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
206+
const client = createWalletClient({ account, network: "devnet" });
207+
208+
const nullifier = await client.createNullifier({
209+
message: [1n, 2n, 3n]
210+
});
211+
```
212+
213+
### Prepare a transaction request
214+
215+
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.
216+
217+
```ts twoslash
218+
import { toAccount } from "@mina-js/accounts";
219+
import { createWalletClient } from '@mina-js/connect';
220+
221+
const account = toAccount('B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5');
222+
const client = createWalletClient({ account, network: "devnet" });
223+
224+
const transactionRequest = await client.prepareTransactionRequest({
225+
from: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5",
226+
to: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5",
227+
amount: 3000000000n,
228+
})
229+
```

apps/docs/vocs.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { remarkMermaid } from "@theguild/remark-mermaid";
22
import { defineConfig } from "vocs";
33

44
export default defineConfig({
5+
ogImageUrl:
6+
"https://vocs.dev/api/og?logo=%logo&title=%title&description=%description",
57
title: "MinaJS",
68
description: "The TypeScript interface for Mina Protocol.",
79
rootDir: "src",
@@ -87,6 +89,7 @@ export default defineConfig({
8789
{ text: "Getting Started", link: "/connect/getting-started" },
8890
{ text: "Provider Discovery", link: "/connect/provider-discovery" },
8991
{ text: "Wallet Interface", link: "/connect/wallet-interface" },
92+
{ text: "Wallet Client", link: "/connect/wallet-client" },
9093
],
9194
},
9295
{

packages/connect/src/client.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { describe, expect, it } from "bun:test";
2-
import { privateKeyToAccount } from "@mina-js/accounts";
3-
import { toAccount } from "@mina-js/accounts";
2+
import { privateKeyToAccount, toAccount } from "@mina-js/accounts";
43
import { Test } from "@mina-js/shared";
54
import { createWalletClient } from "./client";
65

packages/connect/src/client.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export type WalletProviderSlug = "pallad";
1515
export type ProviderSource = "window.mina" | "klesia" | WalletProviderSlug;
1616

1717
export type CreateWalletClientProps = {
18-
account: Account;
18+
account?: Account;
1919
network: "mainnet" | "devnet";
2020
providerSource?: ProviderSource;
2121
};
@@ -40,7 +40,7 @@ export const createWalletClient = ({
4040
const klesiaClient = createClient({ network });
4141
const getAccounts = async () => {
4242
return match(providerSource)
43-
.with("klesia", () => [account.publicKey])
43+
.with("klesia", () => (account ? [account.publicKey] : []))
4444
.otherwise(async () => {
4545
const provider = getWalletProvider(providerSource);
4646
const { result } = await provider.request<"mina_accounts">({
@@ -50,23 +50,30 @@ export const createWalletClient = ({
5050
});
5151
};
5252
const getBalance = async () => {
53+
const getBalanceFromInjectedWallet = async () => {
54+
const provider = getWalletProvider(providerSource);
55+
const { result } = await provider.request<"mina_getBalance">({
56+
method: "mina_getBalance",
57+
});
58+
return result;
59+
};
60+
const getBalanceFromKlesia = async (account: Account) => {
61+
const { result } = await klesiaClient.request<"mina_getBalance">({
62+
method: "mina_getBalance",
63+
params: [account.publicKey],
64+
});
65+
return BigInt(result);
66+
};
5367
return match(providerSource)
5468
.with("klesia", async () => {
55-
const { result } = await klesiaClient.request<"mina_getBalance">({
56-
method: "mina_getBalance",
57-
params: [account.publicKey],
58-
});
59-
return BigInt(result);
69+
if (account) return getBalanceFromKlesia(account);
70+
return getBalanceFromInjectedWallet();
6071
})
61-
.otherwise(async () => {
62-
const provider = getWalletProvider(providerSource);
63-
const { result } = await provider.request<"mina_getBalance">({
64-
method: "mina_getBalance",
65-
});
66-
return result;
67-
});
72+
.otherwise(getBalanceFromInjectedWallet);
6873
};
6974
const getTransactionCount = async () => {
75+
if (!account)
76+
throw new Error("Account is required to get transaction count");
7077
const { result } = await klesiaClient.request<"mina_getTransactionCount">({
7178
method: "mina_getTransactionCount",
7279
params: [account.publicKey],
@@ -90,26 +97,34 @@ export const createWalletClient = ({
9097
});
9198
};
9299
const signTransaction: SignTransaction = async (params) => {
100+
if (!account) throw new Error("Account is required to sign transaction");
93101
if (account.type !== "local") throw new Error("Account type not supported");
94102
return account.signTransaction(params);
95103
};
96104
const signMessage: SignMessage = async (params) => {
105+
if (!account) throw new Error("Account is required to sign message");
97106
if (account.type !== "local") throw new Error("Account type not supported");
98107
return account.signMessage(params);
99108
};
100109
const signFields: SignFields = async (params) => {
110+
if (!account) throw new Error("Account is required to sign fields");
101111
if (account.type !== "local") throw new Error("Account type not supported");
102112
return account.signFields(params);
103113
};
104114
const createNullifier: CreateNullifier = async (params) => {
115+
if (!account) throw new Error("Account is required to create nullifier");
105116
if (account.type !== "local") throw new Error("Account type not supported");
106117
return account.createNullifier(params);
107118
};
108119
const estimateFees = async () => {
109120
const { result } = await klesiaClient.request<"mina_estimateFees">({
110121
method: "mina_estimateFees",
111122
});
112-
return result;
123+
return {
124+
low: BigInt(result.low),
125+
medium: BigInt(result.medium),
126+
high: BigInt(result.high),
127+
};
113128
};
114129
const prepareTransactionRequest = async (
115130
transaction: PartiallyFormedTransactionProperties,

packages/connect/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./store";
22
export * from "./events";
3+
export * from "./client";
34
export type { MinaProviderDetail } from "@mina-js/providers";

0 commit comments

Comments
 (0)