@bootnodedev/canton-connect 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -9
- package/dist/{CantonConnectProvider-CJ1yWGXz.js → CantonConnectProvider-M9GvvKOx.js} +33 -62
- package/dist/index.d.ts +42 -42
- package/dist/index.js +46 -45
- package/dist/testing/index.d.ts +11 -11
- package/dist/testing/index.js +11 -12
- package/dist/{types-CmnMRMoG.d.ts → types-BgMSHglV.d.ts} +50 -47
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -44,15 +44,16 @@ switching only once those gaps close. Until then, the machine earns its cost.
|
|
|
44
44
|
|
|
45
45
|
## Status
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Published to npm as `@bootnodedev/canton-connect`. Also consumed by `dapp/frontend` in this repo,
|
|
48
|
+
which links the local folder while its version satisfies the declared range.
|
|
48
49
|
|
|
49
50
|
## Install
|
|
50
51
|
|
|
51
52
|
Peers a consumer installs beside it: `@canton-network/dapp-sdk`, `@canton-network/core-types`,
|
|
52
|
-
`react` 19 and `@walletconnect/sign-client`. The last is
|
|
53
|
-
it statically at the top of its bundle (checked on 1.5.1), so it has to
|
|
54
|
-
you set `walletConnectProjectId`. Only the session is lazy:
|
|
55
|
-
starts, not at import.
|
|
53
|
+
`react` 19 and `@walletconnect/sign-client`. The last is required here, though `dapp-sdk` marks it
|
|
54
|
+
optional: `dapp-sdk` imports it statically at the top of its bundle (checked on 1.5.1), so it has to
|
|
55
|
+
be present whether or not you set `walletConnectProjectId`. Only the session is lazy:
|
|
56
|
+
`SignClient.init()` runs when a pairing starts, not at import.
|
|
56
57
|
|
|
57
58
|
## Usage
|
|
58
59
|
|
|
@@ -60,7 +61,7 @@ starts, not at import.
|
|
|
60
61
|
import {
|
|
61
62
|
CantonConnectProvider,
|
|
62
63
|
useConnect,
|
|
63
|
-
|
|
64
|
+
useAccount,
|
|
64
65
|
useWalletStatus,
|
|
65
66
|
useSignMessage,
|
|
66
67
|
useExecute,
|
|
@@ -77,7 +78,7 @@ function App() {
|
|
|
77
78
|
|
|
78
79
|
function Dapp() {
|
|
79
80
|
const { connect, isPending, isConnected, error } = useConnect()
|
|
80
|
-
const {
|
|
81
|
+
const { account } = useAccount()
|
|
81
82
|
const { isLocked } = useWalletStatus()
|
|
82
83
|
const { signMessage } = useSignMessage()
|
|
83
84
|
const { execute } = useExecute()
|
|
@@ -98,7 +99,7 @@ function Dapp() {
|
|
|
98
99
|
return <p>Wallet locked. Unlock it to continue.</p>
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
// ... your dApp:
|
|
102
|
+
// ... your dApp: account.partyId, signMessage(text), execute(params), ledgerApi(params)
|
|
102
103
|
}
|
|
103
104
|
```
|
|
104
105
|
|
|
@@ -113,7 +114,7 @@ reports it is not authenticated; that is `isLocked`, and it happens after a succ
|
|
|
113
114
|
reference gateway also refuses `signMessage` for a local party; `usePartyType().readPartyType()`
|
|
114
115
|
tells local from external when you ask. The SDK's status carries one `isConnected` flag, so a lock
|
|
115
116
|
and a wallet-side disconnect look the same
|
|
116
|
-
here. `useLedger().isReady` covers both, and `
|
|
117
|
+
here. `useLedger().isReady` covers both, and `useAccount().account` is `undefined` for the duration:
|
|
117
118
|
gate session content on the party, and use `isLocked` only to explain why it went away.
|
|
118
119
|
|
|
119
120
|
### Connecting through a Wallet Gateway
|
|
@@ -2,7 +2,6 @@ import { DappSDK, WalletConnectAdapter } from "@canton-network/dapp-sdk";
|
|
|
2
2
|
import { createContext, useCallback, useContext, useEffect, useMemo } from "react";
|
|
3
3
|
import { assign, enqueueActions, fromCallback, fromPromise, setup, waitFor } from "xstate";
|
|
4
4
|
import { useActorRef } from "@xstate/react";
|
|
5
|
-
import { WALLET_DISABLED_REASON } from "@canton-network/core-types";
|
|
6
5
|
import { jsx } from "react/jsx-runtime";
|
|
7
6
|
//#region src/CantonConnectProvider/adapters.ts
|
|
8
7
|
/** Builds the extra adapters for the SDK: WalletConnect when configured, plus any passed in. */
|
|
@@ -68,10 +67,18 @@ var ConnectCancelledError = class extends Error {
|
|
|
68
67
|
this.name = "ConnectCancelledError";
|
|
69
68
|
}
|
|
70
69
|
};
|
|
71
|
-
/**
|
|
72
|
-
const
|
|
70
|
+
/** Reads the text off a rejection: `message` as JSON-RPC sends it, `details` as the SDK does. */
|
|
71
|
+
const textOf = (cause) => {
|
|
72
|
+
if (typeof cause !== "object" || cause === null) return;
|
|
73
|
+
for (const key of ["message", "details"]) {
|
|
74
|
+
const value = cause[key];
|
|
75
|
+
if (typeof value === "string" && value !== "") return value;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
73
78
|
/**
|
|
74
|
-
* Hands `cause` back as an `Error`, wrapping what a wallet answered with
|
|
79
|
+
* Hands `cause` back as an `Error`, wrapping what a wallet answered with. Nothing a wallet refuses
|
|
80
|
+
* arrives as an `Error`: the window transport rejects with the bare JSON-RPC object, and the SDK's
|
|
81
|
+
* own controller with a `{ status, error, details }` of its own, so both are read here.
|
|
75
82
|
*
|
|
76
83
|
* @example
|
|
77
84
|
* const error = toError(await sdk.signMessage(params).catch((cause: unknown) => cause))
|
|
@@ -79,7 +86,7 @@ const hasMessage = (cause) => typeof cause === "object" && cause !== null && "me
|
|
|
79
86
|
*/
|
|
80
87
|
const toError = (cause) => {
|
|
81
88
|
if (cause instanceof Error) return cause;
|
|
82
|
-
return new Error(
|
|
89
|
+
return new Error(textOf(cause) ?? String(cause), { cause });
|
|
83
90
|
};
|
|
84
91
|
/** Classifies what `sdk.connect()` threw, so the cancel path is decided once. */
|
|
85
92
|
const toConnectError = (cause) => {
|
|
@@ -102,41 +109,15 @@ const useConnectBridge = (actorRef) => {
|
|
|
102
109
|
}, [actorRef]);
|
|
103
110
|
};
|
|
104
111
|
//#endregion
|
|
105
|
-
//#region src/walletAccount.ts
|
|
106
|
-
/** Whether one raw account entry still has ledger rights to act as a party. */
|
|
107
|
-
const isUsable = (account) => {
|
|
108
|
-
if (account.status === "initialized" || account.status === "removed") return false;
|
|
109
|
-
if (account.disabled === true) return account.reason === WALLET_DISABLED_REASON.NO_SIGNING_PROVIDER_MATCHED;
|
|
110
|
-
return true;
|
|
111
|
-
};
|
|
112
|
-
/** Filters a raw account list down to the ones still usable as a party. */
|
|
113
|
-
const selectUsableAccounts = (accounts) => accounts.filter(isUsable);
|
|
114
|
-
/** Picks the account flagged `primary`, falling back to the first if none is. */
|
|
115
|
-
const selectPrimaryAccount = (accounts) => accounts.find((a) => a.primary) ?? accounts[0];
|
|
116
|
-
/** Maps one raw account entry to the public `Party` shape the hooks expose. */
|
|
117
|
-
const toParty = (account, fallbackNetworkId) => ({
|
|
118
|
-
partyId: account.partyId,
|
|
119
|
-
networkId: account.networkId ?? fallbackNetworkId,
|
|
120
|
-
namespace: account.namespace,
|
|
121
|
-
signingProviderId: account.signingProviderId,
|
|
122
|
-
...account.hint === void 0 ? {} : { name: account.hint },
|
|
123
|
-
...account.publicKey === void 0 ? {} : { publicKey: account.publicKey }
|
|
124
|
-
});
|
|
125
|
-
//#endregion
|
|
126
112
|
//#region src/machine/accountsActors.ts
|
|
127
|
-
/**
|
|
128
|
-
const
|
|
129
|
-
const primary = selectPrimaryAccount(selectUsableAccounts(accounts));
|
|
130
|
-
return { party: primary === void 0 ? void 0 : toParty(primary, networkId) };
|
|
131
|
-
};
|
|
132
|
-
/** Reads the wallet's account list once and resolves the primary usable party. */
|
|
133
|
-
const readAccounts = fromPromise(async ({ input: { sdk, networkId } }) => toWalletAccounts(await sdk.listAccounts(), networkId));
|
|
113
|
+
/** Reads the wallet's account list once and resolves the one it flags primary. */
|
|
114
|
+
const readPrimaryAccount = fromPromise(async ({ input: { sdk } }) => (await sdk.listAccounts()).find((account) => account.primary));
|
|
134
115
|
/** Forwards the wallet's own account-change pushes into the machine as `accounts.changed`. */
|
|
135
|
-
const accountsEvents = fromCallback(({ sendBack, input: { sdk
|
|
116
|
+
const accountsEvents = fromCallback(({ sendBack, input: { sdk } }) => {
|
|
136
117
|
const listener = (accounts) => {
|
|
137
118
|
sendBack({
|
|
138
119
|
type: "accounts.changed",
|
|
139
|
-
|
|
120
|
+
account: accounts.find((one) => one.primary)
|
|
140
121
|
});
|
|
141
122
|
};
|
|
142
123
|
sdk.onAccountsChanged(listener).catch(() => {});
|
|
@@ -147,17 +128,17 @@ const accountsEvents = fromCallback(({ sendBack, input: { sdk, networkId } }) =>
|
|
|
147
128
|
//#endregion
|
|
148
129
|
//#region src/machine/accountsMachine.ts
|
|
149
130
|
/**
|
|
150
|
-
* Reads the connected
|
|
131
|
+
* Reads the connected account once, then follows the wallet's own `accounts.changed` pushes.
|
|
151
132
|
* Invoked as `connectionMachine`'s `accounts` child while a session is authenticated.
|
|
152
133
|
*/
|
|
153
134
|
const accountsMachine = setup({
|
|
154
135
|
actors: {
|
|
155
|
-
|
|
136
|
+
readPrimaryAccount,
|
|
156
137
|
accountsEvents
|
|
157
138
|
},
|
|
158
139
|
actions: {
|
|
159
|
-
|
|
160
|
-
|
|
140
|
+
applyAccount: assign((_, params) => ({
|
|
141
|
+
account: params.account,
|
|
161
142
|
error: void 0
|
|
162
143
|
})),
|
|
163
144
|
assignError: assign((_, params) => ({ error: params.error }))
|
|
@@ -170,37 +151,31 @@ const accountsMachine = setup({
|
|
|
170
151
|
}).createMachine({
|
|
171
152
|
context: ({ input }) => ({
|
|
172
153
|
...input,
|
|
173
|
-
|
|
154
|
+
account: void 0,
|
|
174
155
|
error: void 0
|
|
175
156
|
}),
|
|
176
157
|
id: "accounts",
|
|
177
158
|
initial: "reading",
|
|
178
159
|
invoke: {
|
|
179
160
|
src: "accountsEvents",
|
|
180
|
-
input: ({ context: { sdk
|
|
181
|
-
sdk,
|
|
182
|
-
networkId
|
|
183
|
-
})
|
|
161
|
+
input: ({ context: { sdk } }) => ({ sdk })
|
|
184
162
|
},
|
|
185
163
|
on: { "accounts.changed": {
|
|
186
164
|
target: ".ready",
|
|
187
165
|
actions: {
|
|
188
|
-
type: "
|
|
189
|
-
params: ({ event: {
|
|
166
|
+
type: "applyAccount",
|
|
167
|
+
params: ({ event: { account } }) => ({ account })
|
|
190
168
|
}
|
|
191
169
|
} },
|
|
192
170
|
states: {
|
|
193
171
|
reading: { invoke: {
|
|
194
|
-
src: "
|
|
195
|
-
input: ({ context: { sdk
|
|
196
|
-
sdk,
|
|
197
|
-
networkId
|
|
198
|
-
}),
|
|
172
|
+
src: "readPrimaryAccount",
|
|
173
|
+
input: ({ context: { sdk } }) => ({ sdk }),
|
|
199
174
|
onDone: {
|
|
200
175
|
target: "ready",
|
|
201
176
|
actions: {
|
|
202
|
-
type: "
|
|
203
|
-
params: ({ event: { output } }) => ({
|
|
177
|
+
type: "applyAccount",
|
|
178
|
+
params: ({ event: { output } }) => ({ account: output })
|
|
204
179
|
}
|
|
205
180
|
},
|
|
206
181
|
onError: {
|
|
@@ -528,7 +503,7 @@ const connectionMachine = setup({
|
|
|
528
503
|
...input,
|
|
529
504
|
sdk: input.createSdk(),
|
|
530
505
|
lastConnectError: void 0,
|
|
531
|
-
|
|
506
|
+
account: void 0
|
|
532
507
|
}),
|
|
533
508
|
id: "connection",
|
|
534
509
|
initial: "idle",
|
|
@@ -568,19 +543,16 @@ const connectionMachine = setup({
|
|
|
568
543
|
states: {
|
|
569
544
|
authenticated: {
|
|
570
545
|
initial: "reading",
|
|
571
|
-
exit: assign({
|
|
546
|
+
exit: assign({ account: void 0 }),
|
|
572
547
|
invoke: {
|
|
573
548
|
src: "accounts",
|
|
574
549
|
id: "accounts",
|
|
575
|
-
input: ({ context }) => ({
|
|
576
|
-
sdk: context.sdk,
|
|
577
|
-
networkId: context.networkId
|
|
578
|
-
}),
|
|
550
|
+
input: ({ context }) => ({ sdk: context.sdk }),
|
|
579
551
|
onSnapshot: [{
|
|
580
552
|
guard: ({ event }) => event.snapshot.matches("ready"),
|
|
581
553
|
target: ".ready",
|
|
582
554
|
actions: assign(({ event }) => ({
|
|
583
|
-
|
|
555
|
+
account: event.snapshot.context.account,
|
|
584
556
|
lastConnectError: void 0
|
|
585
557
|
}))
|
|
586
558
|
}, {
|
|
@@ -746,8 +718,7 @@ const CantonConnectProvider = ({ config, children }) => {
|
|
|
746
718
|
const actorRef = useConnectionActor({
|
|
747
719
|
createSdk: () => new DappSDK({ walletPicker: config.walletPicker }),
|
|
748
720
|
initOptions: { additionalAdapters },
|
|
749
|
-
guardPicker: config.walletPicker === void 0
|
|
750
|
-
networkId
|
|
721
|
+
guardPicker: config.walletPicker === void 0
|
|
751
722
|
});
|
|
752
723
|
const resetConnectError = useCallback(() => actorRef.send({ type: "connectError.reset" }), [actorRef]);
|
|
753
724
|
const cancelConnect = useCallback(() => actorRef.send({ type: "connect.cancel" }), [actorRef]);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as ConnectionSubscription, c as TxStatusSnapshot, i as ConnectionStatus, l as ConnectionInput, n as CantonConnectConfig, o as DappSdkMethods, r as CantonConnectContextValue, s as PartyType, t as Account, u as InitOptions } from "./types-BgMSHglV.js";
|
|
2
2
|
import { LedgerApiParams, PrepareExecuteParams, ProviderAdapter } from "@canton-network/dapp-sdk";
|
|
3
3
|
import { JSX, ReactNode } from "react";
|
|
4
4
|
//#region src/CantonConnectProvider/index.d.ts
|
|
@@ -15,7 +15,7 @@ import { JSX, ReactNode } from "react";
|
|
|
15
15
|
*
|
|
16
16
|
* @category Hooks
|
|
17
17
|
*/
|
|
18
|
-
declare const useCantonConnectContext: () => CantonConnectContextValue;
|
|
18
|
+
export declare const useCantonConnectContext: () => CantonConnectContextValue;
|
|
19
19
|
/**
|
|
20
20
|
* Props for {@link CantonConnectProvider}. `config` is read once, when the connection actor is
|
|
21
21
|
* created: a `walletPicker` or `additionalAdapters` swapped later reaches `config` on the context,
|
|
@@ -43,7 +43,7 @@ interface CantonConnectProviderProps {
|
|
|
43
43
|
*
|
|
44
44
|
* @category Components
|
|
45
45
|
*/
|
|
46
|
-
declare const CantonConnectProvider: ({ config, children }: CantonConnectProviderProps) => JSX.Element;
|
|
46
|
+
export declare const CantonConnectProvider: ({ config, children }: CantonConnectProviderProps) => JSX.Element;
|
|
47
47
|
//#endregion
|
|
48
48
|
//#region src/connectError.d.ts
|
|
49
49
|
/**
|
|
@@ -56,10 +56,36 @@ declare const CantonConnectProvider: ({ config, children }: CantonConnectProvide
|
|
|
56
56
|
*
|
|
57
57
|
* @category Errors
|
|
58
58
|
*/
|
|
59
|
-
declare class ConnectCancelledError extends Error {
|
|
59
|
+
export declare class ConnectCancelledError extends Error {
|
|
60
60
|
constructor(cause?: unknown);
|
|
61
61
|
}
|
|
62
62
|
//#endregion
|
|
63
|
+
//#region src/hooks/useAccount.d.ts
|
|
64
|
+
/**
|
|
65
|
+
* Return shape of {@link useAccount}. `account` is the one the wallet flags primary, never
|
|
66
|
+
* substituted, and it changes under a live session.
|
|
67
|
+
*
|
|
68
|
+
* @category Hooks
|
|
69
|
+
*/
|
|
70
|
+
interface UseAccountResult {
|
|
71
|
+
account: Account | undefined;
|
|
72
|
+
status: ConnectionStatus;
|
|
73
|
+
isConnected: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The connected account and status, as the wallet reports it. `account` is `undefined` until a
|
|
77
|
+
* connect succeeds, and again whenever a restored session is locked.
|
|
78
|
+
*
|
|
79
|
+
* @throws with no {@link CantonConnectProvider} above it.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* const { account, isConnected } = useAccount()
|
|
83
|
+
* isConnected && <span>{account?.hint}</span>
|
|
84
|
+
*
|
|
85
|
+
* @category Hooks
|
|
86
|
+
*/
|
|
87
|
+
export declare const useAccount: () => UseAccountResult;
|
|
88
|
+
//#endregion
|
|
63
89
|
//#region src/hooks/useConnect.d.ts
|
|
64
90
|
/**
|
|
65
91
|
* Return shape of {@link useConnect}.
|
|
@@ -80,7 +106,7 @@ interface UseConnectResult {
|
|
|
80
106
|
/**
|
|
81
107
|
* Connects the wallet and reports that transition. `connect` takes no argument: the picker chooses
|
|
82
108
|
* the wallet, so there is no mode to pass. Gate a pending face on `isPending` and
|
|
83
|
-
* session-dependent content on `
|
|
109
|
+
* session-dependent content on `useAccount().account`, not on `isConnected`.
|
|
84
110
|
*
|
|
85
111
|
* @throws with no {@link CantonConnectProvider} above it, as every hook here does.
|
|
86
112
|
*
|
|
@@ -92,7 +118,7 @@ interface UseConnectResult {
|
|
|
92
118
|
*
|
|
93
119
|
* @category Hooks
|
|
94
120
|
*/
|
|
95
|
-
declare const useConnect: () => UseConnectResult;
|
|
121
|
+
export declare const useConnect: () => UseConnectResult;
|
|
96
122
|
//#endregion
|
|
97
123
|
//#region src/hooks/useDisconnect.d.ts
|
|
98
124
|
/**
|
|
@@ -118,7 +144,7 @@ interface UseDisconnectResult {
|
|
|
118
144
|
*
|
|
119
145
|
* @category Hooks
|
|
120
146
|
*/
|
|
121
|
-
declare const useDisconnect: () => UseDisconnectResult;
|
|
147
|
+
export declare const useDisconnect: () => UseDisconnectResult;
|
|
122
148
|
//#endregion
|
|
123
149
|
//#region src/hooks/useExecute.d.ts
|
|
124
150
|
/**
|
|
@@ -137,7 +163,7 @@ interface UseExecuteResult {
|
|
|
137
163
|
}
|
|
138
164
|
/**
|
|
139
165
|
* Submits ledger commands and tracks the transaction in `lastTx`, fed by the SDK's `txChanged`
|
|
140
|
-
* event. `actAs` defaults to the party `
|
|
166
|
+
* event. `actAs` defaults to the party `useAccount` reports, so a submit acts as the party the UI
|
|
141
167
|
* shows rather than the wallet's own primary.
|
|
142
168
|
*
|
|
143
169
|
* @throws with no {@link CantonConnectProvider} above it, and from `execute` where nothing is
|
|
@@ -150,7 +176,7 @@ interface UseExecuteResult {
|
|
|
150
176
|
*
|
|
151
177
|
* @category Hooks
|
|
152
178
|
*/
|
|
153
|
-
declare const useExecute: () => UseExecuteResult;
|
|
179
|
+
export declare const useExecute: () => UseExecuteResult;
|
|
154
180
|
//#endregion
|
|
155
181
|
//#region src/hooks/useLedger.d.ts
|
|
156
182
|
/**
|
|
@@ -180,33 +206,7 @@ interface UseLedgerResult {
|
|
|
180
206
|
*
|
|
181
207
|
* @category Hooks
|
|
182
208
|
*/
|
|
183
|
-
declare const useLedger: () => UseLedgerResult;
|
|
184
|
-
//#endregion
|
|
185
|
-
//#region src/hooks/useParty.d.ts
|
|
186
|
-
/**
|
|
187
|
-
* Return shape of {@link useParty}. `party` is the primary among the accounts that can act on the
|
|
188
|
-
* ledger, so it need not be the one the wallet flags primary, and it changes under a live session.
|
|
189
|
-
*
|
|
190
|
-
* @category Hooks
|
|
191
|
-
*/
|
|
192
|
-
interface UsePartyResult {
|
|
193
|
-
party: Party | undefined;
|
|
194
|
-
status: ConnectionStatus;
|
|
195
|
-
isConnected: boolean;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* The connected account and status. `party` is `undefined` until a connect succeeds, and again
|
|
199
|
-
* whenever a restored session is locked.
|
|
200
|
-
*
|
|
201
|
-
* @throws with no {@link CantonConnectProvider} above it.
|
|
202
|
-
*
|
|
203
|
-
* @example
|
|
204
|
-
* const { party, isConnected } = useParty()
|
|
205
|
-
* isConnected && <span>{party?.partyId}</span>
|
|
206
|
-
*
|
|
207
|
-
* @category Hooks
|
|
208
|
-
*/
|
|
209
|
-
declare const useParty: () => UsePartyResult;
|
|
209
|
+
export declare const useLedger: () => UseLedgerResult;
|
|
210
210
|
//#endregion
|
|
211
211
|
//#region src/hooks/usePartyType.d.ts
|
|
212
212
|
/**
|
|
@@ -236,7 +236,7 @@ interface UsePartyTypeResult {
|
|
|
236
236
|
*
|
|
237
237
|
* @category Hooks
|
|
238
238
|
*/
|
|
239
|
-
declare const usePartyType: () => UsePartyTypeResult;
|
|
239
|
+
export declare const usePartyType: () => UsePartyTypeResult;
|
|
240
240
|
//#endregion
|
|
241
241
|
//#region src/hooks/useSignMessage.d.ts
|
|
242
242
|
/**
|
|
@@ -264,7 +264,7 @@ interface UseSignMessageResult {
|
|
|
264
264
|
*
|
|
265
265
|
* @category Hooks
|
|
266
266
|
*/
|
|
267
|
-
declare const useSignMessage: () => UseSignMessageResult;
|
|
267
|
+
export declare const useSignMessage: () => UseSignMessageResult;
|
|
268
268
|
//#endregion
|
|
269
269
|
//#region src/hooks/useWalletStatus.d.ts
|
|
270
270
|
/**
|
|
@@ -292,7 +292,7 @@ interface UseWalletStatusResult {
|
|
|
292
292
|
*
|
|
293
293
|
* @category Hooks
|
|
294
294
|
*/
|
|
295
|
-
declare const useWalletStatus: () => UseWalletStatusResult;
|
|
295
|
+
export declare const useWalletStatus: () => UseWalletStatusResult;
|
|
296
296
|
//#endregion
|
|
297
297
|
//#region src/mock/mockAdapter.d.ts
|
|
298
298
|
/**
|
|
@@ -309,7 +309,7 @@ interface MockAccount {
|
|
|
309
309
|
/**
|
|
310
310
|
* Wiring for {@link createMockAdapter}. `id` defaults to `'mock'`, which is the provider id
|
|
311
311
|
* `createAutoPicker('mock')` matches; `accounts` defaults to one generated account and treats the
|
|
312
|
-
* first entry as primary;
|
|
312
|
+
* first entry as primary; `networkId` defaults to `canton:local`.
|
|
313
313
|
*
|
|
314
314
|
* @example
|
|
315
315
|
* const options: CreateMockAdapterOptions = { id: 'mock', accounts: [{ partyId }] }
|
|
@@ -341,6 +341,6 @@ interface MockAdapter extends ProviderAdapter {
|
|
|
341
341
|
*
|
|
342
342
|
* @category Utilities
|
|
343
343
|
*/
|
|
344
|
-
declare const createMockAdapter: (options?: CreateMockAdapterOptions) => MockAdapter;
|
|
344
|
+
export declare const createMockAdapter: (options?: CreateMockAdapterOptions) => MockAdapter;
|
|
345
345
|
//#endregion
|
|
346
|
-
export {
|
|
346
|
+
export type { Account, CantonConnectConfig, CantonConnectContextValue, CantonConnectProviderProps, ConnectionInput, ConnectionStatus, ConnectionSubscription, CreateMockAdapterOptions, DappSdkMethods, InitOptions, LedgerApiParams, MockAccount, MockAdapter, PartyType, PrepareExecuteParams, TxStatusSnapshot, UseAccountResult, UseConnectResult, UseDisconnectResult, UseExecuteResult, UseLedgerResult, UsePartyTypeResult, UseSignMessageResult, UseWalletStatusResult };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,35 @@
|
|
|
1
|
-
import { a as toConnectionStatus, c as toError, n as CantonConnectProvider, o as ConnectCancelledError, r as useCantonConnectContext, s as toConnectError } from "./CantonConnectProvider-
|
|
1
|
+
import { a as toConnectionStatus, c as toError, n as CantonConnectProvider, o as ConnectCancelledError, r as useCantonConnectContext, s as toConnectError } from "./CantonConnectProvider-M9GvvKOx.js";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { useSelector } from "@xstate/react";
|
|
4
|
+
//#region src/hooks/useAccount.ts
|
|
5
|
+
/**
|
|
6
|
+
* The connected account and status, as the wallet reports it. `account` is `undefined` until a
|
|
7
|
+
* connect succeeds, and again whenever a restored session is locked.
|
|
8
|
+
*
|
|
9
|
+
* @throws with no {@link CantonConnectProvider} above it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const { account, isConnected } = useAccount()
|
|
13
|
+
* isConnected && <span>{account?.hint}</span>
|
|
14
|
+
*
|
|
15
|
+
* @category Hooks
|
|
16
|
+
*/
|
|
17
|
+
const useAccount = () => {
|
|
18
|
+
const { connection } = useCantonConnectContext();
|
|
19
|
+
const account = useSelector(connection, (snapshot) => snapshot.context.account);
|
|
20
|
+
const status = useSelector(connection, toConnectionStatus);
|
|
21
|
+
return {
|
|
22
|
+
account,
|
|
23
|
+
status,
|
|
24
|
+
isConnected: status === "connected"
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
4
28
|
//#region src/hooks/useConnect.ts
|
|
5
29
|
/**
|
|
6
30
|
* Connects the wallet and reports that transition. `connect` takes no argument: the picker chooses
|
|
7
31
|
* the wallet, so there is no mode to pass. Gate a pending face on `isPending` and
|
|
8
|
-
* session-dependent content on `
|
|
32
|
+
* session-dependent content on `useAccount().account`, not on `isConnected`.
|
|
9
33
|
*
|
|
10
34
|
* @throws with no {@link CantonConnectProvider} above it, as every hook here does.
|
|
11
35
|
*
|
|
@@ -92,9 +116,9 @@ const assertUsable = (status, isLocked) => {
|
|
|
92
116
|
if (status !== "connected") throw new Error("wallet is not connected - call useConnect().connect() first");
|
|
93
117
|
if (isLocked) throw new Error("wallet is locked - unlock it in the wallet");
|
|
94
118
|
};
|
|
95
|
-
/** Throws when the session reports no
|
|
119
|
+
/** Throws when the session reports no account, which a connected one can. */
|
|
96
120
|
function assertPartyId(partyId) {
|
|
97
|
-
if (partyId === void 0) throw new Error("wallet reports no
|
|
121
|
+
if (partyId === void 0) throw new Error("wallet reports no primary account - select or add one in the wallet");
|
|
98
122
|
}
|
|
99
123
|
/**
|
|
100
124
|
* Selects the session and wraps one SDK call with the connect, lock and party guards plus the
|
|
@@ -103,7 +127,7 @@ function assertPartyId(partyId) {
|
|
|
103
127
|
const useWalletCall = () => {
|
|
104
128
|
const { connection } = useCantonConnectContext();
|
|
105
129
|
const sdk = useSelector(connection, (snapshot) => snapshot.context.sdk);
|
|
106
|
-
const partyId = useSelector(connection, (snapshot) => snapshot.context.
|
|
130
|
+
const partyId = useSelector(connection, (snapshot) => snapshot.context.account?.partyId);
|
|
107
131
|
const status = useSelector(connection, toConnectionStatus);
|
|
108
132
|
const isLocked = useSelector(connection, (snapshot) => snapshot.hasTag("unauthenticated"));
|
|
109
133
|
const [state, setState] = useState(IDLE);
|
|
@@ -153,7 +177,7 @@ const withActAs = (params, partyId) => params.actAs === void 0 ? {
|
|
|
153
177
|
} : params;
|
|
154
178
|
/**
|
|
155
179
|
* Submits ledger commands and tracks the transaction in `lastTx`, fed by the SDK's `txChanged`
|
|
156
|
-
* event. `actAs` defaults to the party `
|
|
180
|
+
* event. `actAs` defaults to the party `useAccount` reports, so a submit acts as the party the UI
|
|
157
181
|
* shows rather than the wallet's own primary.
|
|
158
182
|
*
|
|
159
183
|
* @throws with no {@link CantonConnectProvider} above it, and from `execute` where nothing is
|
|
@@ -211,30 +235,6 @@ const useLedger = () => {
|
|
|
211
235
|
};
|
|
212
236
|
};
|
|
213
237
|
//#endregion
|
|
214
|
-
//#region src/hooks/useParty.ts
|
|
215
|
-
/**
|
|
216
|
-
* The connected account and status. `party` is `undefined` until a connect succeeds, and again
|
|
217
|
-
* whenever a restored session is locked.
|
|
218
|
-
*
|
|
219
|
-
* @throws with no {@link CantonConnectProvider} above it.
|
|
220
|
-
*
|
|
221
|
-
* @example
|
|
222
|
-
* const { party, isConnected } = useParty()
|
|
223
|
-
* isConnected && <span>{party?.partyId}</span>
|
|
224
|
-
*
|
|
225
|
-
* @category Hooks
|
|
226
|
-
*/
|
|
227
|
-
const useParty = () => {
|
|
228
|
-
const { connection } = useCantonConnectContext();
|
|
229
|
-
const party = useSelector(connection, (snapshot) => snapshot.context.party);
|
|
230
|
-
const status = useSelector(connection, toConnectionStatus);
|
|
231
|
-
return {
|
|
232
|
-
party,
|
|
233
|
-
status,
|
|
234
|
-
isConnected: status === "connected"
|
|
235
|
-
};
|
|
236
|
-
};
|
|
237
|
-
//#endregion
|
|
238
238
|
//#region src/hooks/usePartyType.ts
|
|
239
239
|
const namespaceOf = (id) => /::(.+)$/.exec(id)?.[1];
|
|
240
240
|
const readParticipantNamespace = async (sdk) => {
|
|
@@ -265,20 +265,20 @@ const readParticipantNamespace = async (sdk) => {
|
|
|
265
265
|
*/
|
|
266
266
|
const usePartyType = () => {
|
|
267
267
|
const { connection, sdk, status, isLocked } = useWalletCall();
|
|
268
|
-
const
|
|
268
|
+
const account = useSelector(connection, (snapshot) => snapshot.context.account);
|
|
269
269
|
return {
|
|
270
270
|
readPartyType: useCallback(async () => {
|
|
271
271
|
assertUsable(status, isLocked);
|
|
272
|
-
if (
|
|
272
|
+
if (account === void 0) throw new Error("wallet reports no primary account - select or add one in the wallet");
|
|
273
273
|
const participantNamespace = await readParticipantNamespace(sdk);
|
|
274
|
-
return
|
|
274
|
+
return account.namespace === participantNamespace ? "local" : "external";
|
|
275
275
|
}, [
|
|
276
|
+
account,
|
|
276
277
|
isLocked,
|
|
277
|
-
party,
|
|
278
278
|
sdk,
|
|
279
279
|
status
|
|
280
280
|
]),
|
|
281
|
-
isReady: status === "connected" && !isLocked &&
|
|
281
|
+
isReady: status === "connected" && !isLocked && account !== void 0
|
|
282
282
|
};
|
|
283
283
|
};
|
|
284
284
|
//#endregion
|
|
@@ -341,21 +341,22 @@ const useWalletStatus = () => {
|
|
|
341
341
|
const DEFAULT_PROVIDER_ID = "mock";
|
|
342
342
|
const DEFAULT_NAME = "Mock Wallet";
|
|
343
343
|
const DEFAULT_DESCRIPTION = "Mock wallet for dev and tests — no real signing, never a live wallet";
|
|
344
|
-
const
|
|
344
|
+
const MOCK_ACCOUNT_STATUS = "allocated";
|
|
345
345
|
const MOCK_SIGNING_PROVIDER_ID = "mock";
|
|
346
346
|
const MOCK_PUBLIC_KEY = "mock-public-key";
|
|
347
|
+
const MOCK_NETWORK_ID = "canton:local";
|
|
347
348
|
/** The single mock account `createMockAdapter` reports when the caller supplies none. */
|
|
348
349
|
const defaultAccounts = (providerId) => [{ partyId: `${providerId}::1220abcd` }];
|
|
349
|
-
/** Shapes one `MockAccount` into the `
|
|
350
|
-
const
|
|
350
|
+
/** Shapes one `MockAccount` into the `Account` the mock adapter's `listAccounts` returns. */
|
|
351
|
+
const toAccount = (account, primary, networkId) => ({
|
|
351
352
|
primary,
|
|
352
353
|
partyId: account.partyId,
|
|
353
|
-
status:
|
|
354
|
+
status: MOCK_ACCOUNT_STATUS,
|
|
354
355
|
hint: account.name ?? account.partyId,
|
|
355
356
|
publicKey: account.publicKey ?? MOCK_PUBLIC_KEY,
|
|
356
357
|
namespace: account.partyId.split("::")[1] ?? account.partyId,
|
|
357
|
-
|
|
358
|
-
|
|
358
|
+
networkId: networkId ?? MOCK_NETWORK_ID,
|
|
359
|
+
signingProviderId: MOCK_SIGNING_PROVIDER_ID
|
|
359
360
|
});
|
|
360
361
|
/**
|
|
361
362
|
* The adapter `createMockAdapter` returns: it announces itself like an installed wallet and
|
|
@@ -365,13 +366,13 @@ var MockProviderAdapter = class {
|
|
|
365
366
|
providerId;
|
|
366
367
|
name = DEFAULT_NAME;
|
|
367
368
|
type = "browser";
|
|
368
|
-
|
|
369
|
+
accounts;
|
|
369
370
|
connected = false;
|
|
370
371
|
listenerMap = {};
|
|
371
372
|
constructor(options) {
|
|
372
373
|
this.providerId = options.id ?? DEFAULT_PROVIDER_ID;
|
|
373
374
|
const accounts = options.accounts ?? defaultAccounts(this.providerId);
|
|
374
|
-
this.
|
|
375
|
+
this.accounts = accounts.map((account, index) => toAccount(account, index === 0, options.networkId));
|
|
375
376
|
}
|
|
376
377
|
getInfo() {
|
|
377
378
|
return {
|
|
@@ -410,7 +411,7 @@ var MockProviderAdapter = class {
|
|
|
410
411
|
isNetworkConnected: true
|
|
411
412
|
}
|
|
412
413
|
}),
|
|
413
|
-
listAccounts: () => this.
|
|
414
|
+
listAccounts: () => this.accounts
|
|
414
415
|
};
|
|
415
416
|
async request(args) {
|
|
416
417
|
const handler = this.handlers[args.method];
|
|
@@ -445,4 +446,4 @@ var MockProviderAdapter = class {
|
|
|
445
446
|
*/
|
|
446
447
|
const createMockAdapter = (options = {}) => new MockProviderAdapter(options);
|
|
447
448
|
//#endregion
|
|
448
|
-
export { CantonConnectProvider, ConnectCancelledError, createMockAdapter, useCantonConnectContext, useConnect, useDisconnect, useExecute, useLedger,
|
|
449
|
+
export { CantonConnectProvider, ConnectCancelledError, createMockAdapter, useAccount, useCantonConnectContext, useConnect, useDisconnect, useExecute, useLedger, usePartyType, useSignMessage, useWalletStatus };
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as ConnectionStatus, o as DappSdkMethods, t as Account } from "../types-BgMSHglV.js";
|
|
2
2
|
import { WalletPickerFn } from "@canton-network/dapp-sdk";
|
|
3
3
|
import { JSX, ReactNode } from "react";
|
|
4
4
|
//#region src/testing/autoPicker.d.ts
|
|
@@ -14,23 +14,23 @@ import { JSX, ReactNode } from "react";
|
|
|
14
14
|
*
|
|
15
15
|
* @category Utilities
|
|
16
16
|
*/
|
|
17
|
-
declare const createAutoPicker: (pick?: string) => WalletPickerFn;
|
|
17
|
+
export declare const createAutoPicker: (pick?: string) => WalletPickerFn;
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/testing/fakeSession.d.ts
|
|
20
20
|
/**
|
|
21
|
-
* Props for {@link FakeSessionProvider}. `status` starts the session mid-flight and `
|
|
21
|
+
* Props for {@link FakeSessionProvider}. `status` starts the session mid-flight and `account` is
|
|
22
22
|
* what a connect resolves to; `readingAccounts` reaches the pending face over a live session, and
|
|
23
23
|
* `sdk` drives a hook's own pending, error and `reset()`, never what a wallet returns.
|
|
24
24
|
*
|
|
25
25
|
* @category Components
|
|
26
26
|
*/
|
|
27
27
|
interface FakeSessionProviderProps {
|
|
28
|
+
account?: Account;
|
|
28
29
|
children: ReactNode;
|
|
29
30
|
connectError?: Error;
|
|
30
31
|
isLocked?: boolean;
|
|
31
|
-
party?: Party;
|
|
32
32
|
readingAccounts?: boolean;
|
|
33
|
-
sdk?: Partial<
|
|
33
|
+
sdk?: Partial<DappSdkMethods>;
|
|
34
34
|
status?: ConnectionStatus;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
@@ -43,19 +43,19 @@ interface FakeSessionProviderProps {
|
|
|
43
43
|
*
|
|
44
44
|
* @example
|
|
45
45
|
* render(
|
|
46
|
-
* <FakeSessionProvider status="connected"
|
|
46
|
+
* <FakeSessionProvider status="connected" account={account}>
|
|
47
47
|
* <ConnectButton />
|
|
48
48
|
* </FakeSessionProvider>,
|
|
49
49
|
* )
|
|
50
50
|
*
|
|
51
51
|
* @category Components
|
|
52
52
|
*/
|
|
53
|
-
declare const FakeSessionProvider: ({ children, connectError, isLocked,
|
|
53
|
+
export declare const FakeSessionProvider: ({ account, children, connectError, isLocked, readingAccounts, sdk, status: initialStatus }: FakeSessionProviderProps) => JSX.Element;
|
|
54
54
|
//#endregion
|
|
55
55
|
//#region src/testing/fakeWallet.d.ts
|
|
56
56
|
/**
|
|
57
57
|
* One account the fake wallet reports from `listAccounts`. Mark exactly one `primary`: that is the
|
|
58
|
-
* entry
|
|
58
|
+
* entry the session reports.
|
|
59
59
|
*
|
|
60
60
|
* @category Utilities
|
|
61
61
|
*/
|
|
@@ -109,7 +109,7 @@ interface FakeWallet {
|
|
|
109
109
|
*
|
|
110
110
|
* @category Utilities
|
|
111
111
|
*/
|
|
112
|
-
declare const createFakeWallet: (options: FakeWalletOptions) => FakeWallet;
|
|
112
|
+
export declare const createFakeWallet: (options: FakeWalletOptions) => FakeWallet;
|
|
113
113
|
//#endregion
|
|
114
114
|
//#region src/testing/pause.d.ts
|
|
115
115
|
/**
|
|
@@ -122,6 +122,6 @@ declare const createFakeWallet: (options: FakeWalletOptions) => FakeWallet;
|
|
|
122
122
|
*
|
|
123
123
|
* @category Utilities
|
|
124
124
|
*/
|
|
125
|
-
declare const pause: (ms: number) => Promise<unknown>;
|
|
125
|
+
export declare const pause: (ms: number) => Promise<unknown>;
|
|
126
126
|
//#endregion
|
|
127
|
-
export {
|
|
127
|
+
export type { FakeSessionProviderProps, FakeWallet, FakeWalletAccount, FakeWalletOptions };
|
package/dist/testing/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { i as connectionMachine, t as CantonConnectContext } from "../CantonConnectProvider-
|
|
1
|
+
import { i as connectionMachine, t as CantonConnectContext } from "../CantonConnectProvider-M9GvvKOx.js";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { createActor } from "xstate";
|
|
4
|
-
import { CANTON_ANNOUNCE_PROVIDER_EVENT, CANTON_REQUEST_PROVIDER_EVENT, WalletEvent } from "@canton-network/core-types";
|
|
5
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { CANTON_ANNOUNCE_PROVIDER_EVENT, CANTON_REQUEST_PROVIDER_EVENT, WalletEvent } from "@canton-network/core-types";
|
|
6
6
|
//#region src/testing/autoPicker.ts
|
|
7
7
|
/**
|
|
8
8
|
* A `walletPicker` that selects with no UI, for tests and headless dev flows: the entry whose
|
|
@@ -23,9 +23,9 @@ const createAutoPicker = (pick) => async (entries) => {
|
|
|
23
23
|
};
|
|
24
24
|
//#endregion
|
|
25
25
|
//#region src/testing/connectionInput.ts
|
|
26
|
-
/** A `
|
|
26
|
+
/** A `DappSdkMethods` method stand-in that returns a promise which never settles. */
|
|
27
27
|
const pending = () => new Promise(() => {});
|
|
28
|
-
/** Every `
|
|
28
|
+
/** Every `DappSdkMethods` method left hanging, so a test only stubs the ones its path reaches. */
|
|
29
29
|
const unstubbed = {
|
|
30
30
|
connect: pending,
|
|
31
31
|
disconnect: pending,
|
|
@@ -43,7 +43,7 @@ const unstubbed = {
|
|
|
43
43
|
status: pending
|
|
44
44
|
};
|
|
45
45
|
/**
|
|
46
|
-
* Machine input for a test actor, over a double satisfying the `
|
|
46
|
+
* Machine input for a test actor, over a double satisfying the `DappSdkMethods` the machine types.
|
|
47
47
|
* Whatever the double leaves out never settles, and every `createSdk()` hands back a fresh object,
|
|
48
48
|
* as `new DappSDK` does — so a retirement changes `context.sdk` here too.
|
|
49
49
|
*
|
|
@@ -57,7 +57,6 @@ const connectionInput = (sdk = {}, overrides = {}) => ({
|
|
|
57
57
|
}),
|
|
58
58
|
initOptions: {},
|
|
59
59
|
guardPicker: false,
|
|
60
|
-
networkId: "canton:local",
|
|
61
60
|
...overrides
|
|
62
61
|
});
|
|
63
62
|
//#endregion
|
|
@@ -77,7 +76,7 @@ const toStateValue = ({ isLocked, readingAccounts, status }) => {
|
|
|
77
76
|
return { session: { authenticated: readingAccounts ? "reading" : "ready" } };
|
|
78
77
|
};
|
|
79
78
|
/** Starts a real `connectionMachine` actor rehydrated at the given `SessionShape`. */
|
|
80
|
-
const startSession = (shape,
|
|
79
|
+
const startSession = (shape, account, connectError, sdk) => {
|
|
81
80
|
const input = connectionInput({}, { createSdk: () => sdk });
|
|
82
81
|
const snapshot = connectionMachine.resolveState({
|
|
83
82
|
value: toStateValue(shape),
|
|
@@ -85,7 +84,7 @@ const startSession = (shape, party, connectError, sdk) => {
|
|
|
85
84
|
...input,
|
|
86
85
|
sdk,
|
|
87
86
|
lastConnectError: connectError,
|
|
88
|
-
|
|
87
|
+
account: shape.status === "connected" ? account : void 0
|
|
89
88
|
}
|
|
90
89
|
});
|
|
91
90
|
return createActor(connectionMachine, {
|
|
@@ -103,23 +102,23 @@ const startSession = (shape, party, connectError, sdk) => {
|
|
|
103
102
|
*
|
|
104
103
|
* @example
|
|
105
104
|
* render(
|
|
106
|
-
* <FakeSessionProvider status="connected"
|
|
105
|
+
* <FakeSessionProvider status="connected" account={account}>
|
|
107
106
|
* <ConnectButton />
|
|
108
107
|
* </FakeSessionProvider>,
|
|
109
108
|
* )
|
|
110
109
|
*
|
|
111
110
|
* @category Components
|
|
112
111
|
*/
|
|
113
|
-
const FakeSessionProvider = ({ children, connectError, isLocked = false,
|
|
112
|
+
const FakeSessionProvider = ({ account, children, connectError, isLocked = false, readingAccounts = false, sdk = NO_SDK, status: initialStatus = "disconnected" }) => {
|
|
114
113
|
const [status, setStatus] = useState(initialStatus);
|
|
115
114
|
const connection = useMemo(() => startSession({
|
|
116
115
|
isLocked,
|
|
117
116
|
readingAccounts,
|
|
118
117
|
status
|
|
119
|
-
},
|
|
118
|
+
}, account, connectError, refusingSdk(sdk)), [
|
|
119
|
+
account,
|
|
120
120
|
connectError,
|
|
121
121
|
isLocked,
|
|
122
|
-
party,
|
|
123
122
|
readingAccounts,
|
|
124
123
|
sdk,
|
|
125
124
|
status
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DappSDK, ProviderAdapter, StatusEvent, TxChangedEvent, WalletPickerFn } from "@canton-network/dapp-sdk";
|
|
1
|
+
import { DappSDK, ProviderAdapter, StatusEvent, TxChangedEvent, Wallet, WalletPickerFn } from "@canton-network/dapp-sdk";
|
|
2
2
|
import { ActorRefFrom } from "xstate";
|
|
3
3
|
//#region src/machine/connectionActors.d.ts
|
|
4
4
|
/**
|
|
@@ -36,17 +36,10 @@ type WalletEventsInput = {
|
|
|
36
36
|
sdk: Pick<DappSDK, 'onStatusChanged' | 'removeOnStatusChanged'>;
|
|
37
37
|
};
|
|
38
38
|
//#endregion
|
|
39
|
-
//#region src/machine/accountsMachine.d.ts
|
|
40
|
-
/** The result of an account read, initial or pushed: the party found, or none. */
|
|
41
|
-
type WalletAccounts = {
|
|
42
|
-
party: Party | undefined;
|
|
43
|
-
};
|
|
44
|
-
//#endregion
|
|
45
39
|
//#region src/machine/accountsActors.d.ts
|
|
46
|
-
/** Input shared by `
|
|
40
|
+
/** Input shared by `readPrimaryAccount` and `accountsEvents`: the sdk slice they call. */
|
|
47
41
|
type AccountsInput = {
|
|
48
42
|
sdk: Pick<DappSDK, 'listAccounts' | 'onAccountsChanged' | 'removeOnAccountsChanged'>;
|
|
49
|
-
networkId: string;
|
|
50
43
|
};
|
|
51
44
|
//#endregion
|
|
52
45
|
//#region src/machine/connectionMachine.d.ts
|
|
@@ -62,22 +55,21 @@ type WalletStatusUpdate = Pick<StatusEvent, 'connection'>;
|
|
|
62
55
|
* import { connectionMachine } from '#src/machine/connectionMachine'
|
|
63
56
|
*
|
|
64
57
|
* const createSdk = () => new DappSDK({})
|
|
65
|
-
* const input = { createSdk, initOptions: {}, guardPicker: true
|
|
58
|
+
* const input = { createSdk, initOptions: {}, guardPicker: true }
|
|
66
59
|
* createActor(connectionMachine, { input })
|
|
67
60
|
*
|
|
68
61
|
* @category Types
|
|
69
62
|
*/
|
|
70
63
|
type ConnectionInput = {
|
|
71
|
-
createSdk: () =>
|
|
64
|
+
createSdk: () => DappSdkMethods;
|
|
72
65
|
initOptions: InitOptions;
|
|
73
66
|
guardPicker: boolean;
|
|
74
|
-
networkId: string;
|
|
75
67
|
};
|
|
76
|
-
/** What the machine carries beyond its input: the sdk it drives, the last failure, the
|
|
68
|
+
/** What the machine carries beyond its input: the sdk it drives, the last failure, the account. */
|
|
77
69
|
type ConnectionContext = ConnectionInput & {
|
|
78
|
-
sdk:
|
|
70
|
+
sdk: DappSdkMethods;
|
|
79
71
|
lastConnectError: unknown;
|
|
80
|
-
|
|
72
|
+
account: Account | undefined;
|
|
81
73
|
};
|
|
82
74
|
/**
|
|
83
75
|
* The lifecycle itself: what a connect, a restore, a lock and a disconnect mean, and the tags the
|
|
@@ -101,25 +93,26 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
|
|
|
101
93
|
status: WalletStatusUpdate;
|
|
102
94
|
}, {
|
|
103
95
|
[x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<WalletStatusUpdate, ConnectInput, import("xstate").EventObject> | import("xstate").PromiseActorLogic<null, DisconnectInput, import("xstate").EventObject> | import("xstate").PromiseActorLogic<void, InitInput, import("xstate").EventObject> | import("xstate").PromiseActorLogic<WalletStatusUpdate, RestoreInput, import("xstate").EventObject> | import("xstate").CallbackActorLogic<import("xstate").EventObject, WalletEventsInput, import("xstate").EventObject>> | undefined;
|
|
104
|
-
accounts?: import("xstate").ActorRefFromLogic<import("xstate").StateMachine<AccountsInput &
|
|
96
|
+
accounts?: import("xstate").ActorRefFromLogic<import("xstate").StateMachine<AccountsInput & {
|
|
97
|
+
account: Account | undefined;
|
|
105
98
|
error: unknown;
|
|
106
99
|
}, {
|
|
107
100
|
type: "accounts.changed";
|
|
108
|
-
|
|
101
|
+
account: Account | undefined;
|
|
109
102
|
}, {
|
|
110
|
-
[x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<
|
|
103
|
+
[x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<import("@canton-network/dapp-sdk").Wallet | undefined, AccountsInput, import("xstate").EventObject> | import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>> | undefined;
|
|
111
104
|
}, {
|
|
112
|
-
src: "
|
|
113
|
-
logic: import("xstate").PromiseActorLogic<
|
|
105
|
+
src: "readPrimaryAccount";
|
|
106
|
+
logic: import("xstate").PromiseActorLogic<import("@canton-network/dapp-sdk").Wallet | undefined, AccountsInput, import("xstate").EventObject>;
|
|
114
107
|
id: string | undefined;
|
|
115
108
|
} | {
|
|
116
109
|
src: "accountsEvents";
|
|
117
110
|
logic: import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>;
|
|
118
111
|
id: string | undefined;
|
|
119
112
|
}, {
|
|
120
|
-
type: "
|
|
113
|
+
type: "applyAccount";
|
|
121
114
|
params: {
|
|
122
|
-
|
|
115
|
+
account: Account | undefined;
|
|
123
116
|
};
|
|
124
117
|
} | {
|
|
125
118
|
type: "assignError";
|
|
@@ -133,7 +126,7 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
|
|
|
133
126
|
readonly ready: {};
|
|
134
127
|
readonly unavailable: {};
|
|
135
128
|
};
|
|
136
|
-
}>> | undefined;
|
|
129
|
+
}, import("xstate").MetaObject>> | undefined;
|
|
137
130
|
}, {
|
|
138
131
|
src: "init";
|
|
139
132
|
logic: import("xstate").PromiseActorLogic<void, InitInput, import("xstate").EventObject>;
|
|
@@ -156,25 +149,26 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
|
|
|
156
149
|
id: string | undefined;
|
|
157
150
|
} | {
|
|
158
151
|
src: "accounts";
|
|
159
|
-
logic: import("xstate").StateMachine<AccountsInput &
|
|
152
|
+
logic: import("xstate").StateMachine<AccountsInput & {
|
|
153
|
+
account: Account | undefined;
|
|
160
154
|
error: unknown;
|
|
161
155
|
}, {
|
|
162
156
|
type: "accounts.changed";
|
|
163
|
-
|
|
157
|
+
account: Account | undefined;
|
|
164
158
|
}, {
|
|
165
|
-
[x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<
|
|
159
|
+
[x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<import("@canton-network/dapp-sdk").Wallet | undefined, AccountsInput, import("xstate").EventObject> | import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>> | undefined;
|
|
166
160
|
}, {
|
|
167
|
-
src: "
|
|
168
|
-
logic: import("xstate").PromiseActorLogic<
|
|
161
|
+
src: "readPrimaryAccount";
|
|
162
|
+
logic: import("xstate").PromiseActorLogic<import("@canton-network/dapp-sdk").Wallet | undefined, AccountsInput, import("xstate").EventObject>;
|
|
169
163
|
id: string | undefined;
|
|
170
164
|
} | {
|
|
171
165
|
src: "accountsEvents";
|
|
172
166
|
logic: import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>;
|
|
173
167
|
id: string | undefined;
|
|
174
168
|
}, {
|
|
175
|
-
type: "
|
|
169
|
+
type: "applyAccount";
|
|
176
170
|
params: {
|
|
177
|
-
|
|
171
|
+
account: Account | undefined;
|
|
178
172
|
};
|
|
179
173
|
} | {
|
|
180
174
|
type: "assignError";
|
|
@@ -188,7 +182,7 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
|
|
|
188
182
|
readonly ready: {};
|
|
189
183
|
readonly unavailable: {};
|
|
190
184
|
};
|
|
191
|
-
}>;
|
|
185
|
+
}, import("xstate").MetaObject>;
|
|
192
186
|
id: "accounts";
|
|
193
187
|
}, {
|
|
194
188
|
type: "assignError";
|
|
@@ -270,7 +264,7 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
|
|
|
270
264
|
readonly initializing: {};
|
|
271
265
|
readonly disconnecting: {};
|
|
272
266
|
};
|
|
273
|
-
}>;
|
|
267
|
+
}, import("xstate").MetaObject>;
|
|
274
268
|
/**
|
|
275
269
|
* The running connection machine. Consumers reach it narrowed to {@link ConnectionSubscription},
|
|
276
270
|
* so `send` stays inside this package.
|
|
@@ -286,14 +280,14 @@ type ConnectionActorRef = ActorRefFrom<typeof connectionMachine>;
|
|
|
286
280
|
*
|
|
287
281
|
* @category Types
|
|
288
282
|
*/
|
|
289
|
-
type
|
|
283
|
+
type DappSdkMethods = Pick<DappSDK, 'init' | 'connect' | 'disconnect' | 'status' | 'listAccounts' | 'onStatusChanged' | 'removeOnStatusChanged' | 'onAccountsChanged' | 'removeOnAccountsChanged' | 'onTxChanged' | 'removeOnTxChanged' | 'ledgerApi' | 'signMessage' | 'prepareExecuteAndWait'>;
|
|
290
284
|
/**
|
|
291
285
|
* `'idle'` is "not determined yet", not "disconnected": gate a connect button on `'disconnected'`,
|
|
292
286
|
* or a returning user is turned away before the boot restore runs. `'disconnecting'` is the session
|
|
293
287
|
* tearing down; keep connect disabled until it settles, so a new connect never overlaps it.
|
|
294
288
|
*
|
|
295
289
|
* @example
|
|
296
|
-
* const { status } =
|
|
290
|
+
* const { status } = useAccount()
|
|
297
291
|
* if (status === 'idle') return null
|
|
298
292
|
* return status === 'disconnected' ? <ConnectButton /> : <App />
|
|
299
293
|
*
|
|
@@ -307,21 +301,30 @@ type ConnectionStatus = 'idle' | 'connecting' | 'connected' | 'disconnecting' |
|
|
|
307
301
|
* @category Types
|
|
308
302
|
*/
|
|
309
303
|
type PartyType = 'local' | 'external';
|
|
304
|
+
type PinnedAccount = {
|
|
305
|
+
primary: boolean;
|
|
306
|
+
partyId: string;
|
|
307
|
+
status: 'initialized' | 'allocated' | 'removed';
|
|
308
|
+
hint: string;
|
|
309
|
+
publicKey: string;
|
|
310
|
+
namespace: string;
|
|
311
|
+
networkId: string;
|
|
312
|
+
signingProviderId: string;
|
|
313
|
+
externalTxId?: string;
|
|
314
|
+
topologyTransactions?: string;
|
|
315
|
+
disabled?: boolean;
|
|
316
|
+
reason?: string;
|
|
317
|
+
};
|
|
318
|
+
type Exact<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
|
|
319
|
+
type Assert<T extends true> = T;
|
|
320
|
+
type AccountPinned = Assert<Exact<Wallet, PinnedAccount>>;
|
|
310
321
|
/**
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* `signingProviderId` come through as reported; CIP-0103 names no `signingProviderId` values.
|
|
322
|
+
* One account the connected wallet reports: a party plus its key, signing provider and network.
|
|
323
|
+
* `dapp-sdk` calls this type `Wallet`; CIP-0103's own text says account.
|
|
314
324
|
*
|
|
315
325
|
* @category Types
|
|
316
326
|
*/
|
|
317
|
-
|
|
318
|
-
partyId: string;
|
|
319
|
-
networkId: string;
|
|
320
|
-
namespace: string;
|
|
321
|
-
signingProviderId: string;
|
|
322
|
-
name?: string;
|
|
323
|
-
publicKey?: string;
|
|
324
|
-
}
|
|
327
|
+
type Account = AccountPinned extends true ? Wallet : never;
|
|
325
328
|
/**
|
|
326
329
|
* Wiring for `CantonConnectProvider`. From `appName` alone a local dev app works: `canton:local` as
|
|
327
330
|
* the network id and the WalletConnect chain id, `appName` as the description, the page origin as
|
|
@@ -376,7 +379,7 @@ interface TxStatusSnapshot {
|
|
|
376
379
|
* @example
|
|
377
380
|
* import type { ConnectionSubscription } from '#src/types'
|
|
378
381
|
*
|
|
379
|
-
* const
|
|
382
|
+
* const accountOf = (connection: ConnectionSubscription) => connection.getSnapshot().context.account
|
|
380
383
|
*
|
|
381
384
|
* @category Types
|
|
382
385
|
*/
|
|
@@ -397,4 +400,4 @@ interface CantonConnectContextValue {
|
|
|
397
400
|
resetConnectError: () => void;
|
|
398
401
|
}
|
|
399
402
|
//#endregion
|
|
400
|
-
export {
|
|
403
|
+
export { ConnectionSubscription as a, TxStatusSnapshot as c, ConnectionStatus as i, ConnectionInput as l, CantonConnectConfig as n, DappSdkMethods as o, CantonConnectContextValue as r, PartyType as s, Account as t, InitOptions as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bootnodedev/canton-connect",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "wagmi-style React hooks for connecting Canton dApps to CIP-0103 wallets",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -58,16 +58,16 @@
|
|
|
58
58
|
"@types/react": "^19.2.17",
|
|
59
59
|
"@types/react-dom": "^19.2.3",
|
|
60
60
|
"@vitejs/plugin-react": "^6.0.4",
|
|
61
|
-
"@vitest/coverage-v8": "^
|
|
61
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
62
62
|
"@walletconnect/sign-client": "^2.23.9",
|
|
63
63
|
"@walletconnect/types": "^2.23.9",
|
|
64
64
|
"jsdom": "^30.0.0",
|
|
65
65
|
"react": "^19.2.8",
|
|
66
66
|
"react-dom": "^19.2.8",
|
|
67
|
-
"tsdown": "^0.
|
|
67
|
+
"tsdown": "^0.23.0",
|
|
68
68
|
"typescript": "^5.9.3",
|
|
69
69
|
"vite": "^8.1.5",
|
|
70
|
-
"vitest": "^
|
|
70
|
+
"vitest": "^5.0.0"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"@xstate/react": "^6.1.0",
|