@miden-sdk/miden-wallet-adapter-miden 0.16.0 → 0.16.3
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/AGENTS.md +93 -0
- package/dist/adapter.js.map +1 -1
- package/dist/conformance.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
- package/__tests__/adapter.test.ts +0 -594
- package/__tests__/conformance.test.ts +0 -131
- package/adapter.ts +0 -449
- package/conformance.ts +0 -219
- package/dist/__tests__/adapter.test.d.ts +0 -1
- package/dist/__tests__/adapter.test.js +0 -464
- package/dist/__tests__/adapter.test.js.map +0 -1
- package/dist/__tests__/conformance.test.d.ts +0 -1
- package/dist/__tests__/conformance.test.js +0 -97
- package/dist/__tests__/conformance.test.js.map +0 -1
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -8
- package/dist/vitest.config.js.map +0 -1
- package/docs/README.md +0 -20
- package/docs/classes/MidenWalletAdapter.md +0 -714
- package/docs/interfaces/MidenWallet.md +0 -506
- package/docs/interfaces/MidenWalletAdapterConfig.md +0 -13
- package/docs/interfaces/MidenWalletEvents.md +0 -55
- package/docs/interfaces/MidenWindow.md +0 -5217
- package/docs/variables/MidenWalletName.md +0 -9
- package/index.ts +0 -2
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -8
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
CONFORMANCE_BUILD,
|
|
5
|
-
MIDEN_WALLET_METHODS,
|
|
6
|
-
getBehaviorCases,
|
|
7
|
-
getSurfaceCases,
|
|
8
|
-
runConformance,
|
|
9
|
-
type ProviderLike,
|
|
10
|
-
} from "../conformance";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A provider that implements the whole interface.
|
|
14
|
-
*
|
|
15
|
-
* This is deliberately NOT the thing under test. A reference provider authored
|
|
16
|
-
* in this repo gets updated in the same commit that adds a method, so it can
|
|
17
|
-
* never catch a real provider missing one — that is exactly how `createAccount`
|
|
18
|
-
* shipped broken for six months.
|
|
19
|
-
*
|
|
20
|
-
* What is under test is the *instrument*: the tests below delete methods from
|
|
21
|
-
* this provider and assert the suite notices. If the suite cannot detect a
|
|
22
|
-
* deletion here, it cannot detect a gap in the wallet either.
|
|
23
|
-
*/
|
|
24
|
-
const completeProvider = (): ProviderLike => {
|
|
25
|
-
const provider: ProviderLike = {};
|
|
26
|
-
for (const method of MIDEN_WALLET_METHODS) {
|
|
27
|
-
provider[method] = () => Promise.resolve({});
|
|
28
|
-
}
|
|
29
|
-
return provider;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
describe("MIDEN_WALLET_METHODS", () => {
|
|
33
|
-
it("names every method the interface declares", () => {
|
|
34
|
-
// The type lock in conformance.ts is the real guard — it fails to compile
|
|
35
|
-
// if the interface drifts. This asserts the count so an accidental
|
|
36
|
-
// duplicate or deletion is visible in test output too.
|
|
37
|
-
expect(new Set(MIDEN_WALLET_METHODS).size).toBe(
|
|
38
|
-
MIDEN_WALLET_METHODS.length
|
|
39
|
-
);
|
|
40
|
-
expect(MIDEN_WALLET_METHODS).toContain("createAccount");
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("identifies itself so a mocked module cannot pass silently", () => {
|
|
44
|
-
expect(CONFORMANCE_BUILD.real).toBe(true);
|
|
45
|
-
expect(CONFORMANCE_BUILD.methodCount).toBe(MIDEN_WALLET_METHODS.length);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe("getSurfaceCases", () => {
|
|
50
|
-
it("passes a provider that implements everything", async () => {
|
|
51
|
-
const { passed, failed } = await runConformance(
|
|
52
|
-
getSurfaceCases(completeProvider())
|
|
53
|
-
);
|
|
54
|
-
expect(failed).toEqual([]);
|
|
55
|
-
expect(passed).toHaveLength(MIDEN_WALLET_METHODS.length);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// The load-bearing test. Deleting any single method must produce exactly one
|
|
59
|
-
// failure naming that method. Parameterised over all of them so a method
|
|
60
|
-
// added later is covered without anyone remembering to add a case.
|
|
61
|
-
it.each(MIDEN_WALLET_METHODS)("fails when %s is missing", async (missing) => {
|
|
62
|
-
const provider = completeProvider();
|
|
63
|
-
delete provider[missing];
|
|
64
|
-
|
|
65
|
-
const { failed } = await runConformance(getSurfaceCases(provider));
|
|
66
|
-
|
|
67
|
-
expect(failed).toHaveLength(1);
|
|
68
|
-
expect(failed[0].name).toBe(`implements ${missing}()`);
|
|
69
|
-
expect(failed[0].error).toContain(`MidenWallet.${missing} is missing`);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it("reports every gap in one run rather than stopping at the first", async () => {
|
|
73
|
-
const provider = completeProvider();
|
|
74
|
-
delete provider.createAccount;
|
|
75
|
-
delete provider.requestGuardianInfo;
|
|
76
|
-
|
|
77
|
-
const { failed } = await runConformance(getSurfaceCases(provider));
|
|
78
|
-
|
|
79
|
-
// These two are precisely the real-world gaps: createAccount is absent from
|
|
80
|
-
// all three wallet providers, requestGuardianInfo from the Tauri one.
|
|
81
|
-
expect(failed.map((f) => f.name).sort()).toEqual([
|
|
82
|
-
"implements createAccount()",
|
|
83
|
-
"implements requestGuardianInfo()",
|
|
84
|
-
]);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("rejects a non-function property, not merely an absent one", async () => {
|
|
88
|
-
const provider = completeProvider();
|
|
89
|
-
provider.signBytes = "nope";
|
|
90
|
-
|
|
91
|
-
const { failed } = await runConformance(getSurfaceCases(provider));
|
|
92
|
-
|
|
93
|
-
expect(failed).toHaveLength(1);
|
|
94
|
-
expect(failed[0].error).toContain("is a string");
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
describe("getBehaviorCases", () => {
|
|
99
|
-
it("fails a provider whose methods resolve to the wrong shape", async () => {
|
|
100
|
-
const provider = completeProvider(); // every method resolves to {}
|
|
101
|
-
const { failed } = await runConformance(getBehaviorCases(provider));
|
|
102
|
-
|
|
103
|
-
expect(failed.map((f) => f.name)).toEqual([
|
|
104
|
-
"requestAssets() resolves to { assets: [...] }",
|
|
105
|
-
"requestConsumableNotes() resolves to { consumableNotes: [...] }",
|
|
106
|
-
"requestGuardianInfo() resolves to { guardianInfo }",
|
|
107
|
-
]);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("passes a provider that returns the documented shapes", async () => {
|
|
111
|
-
const provider = completeProvider();
|
|
112
|
-
provider.requestAssets = () => Promise.resolve({ assets: [] });
|
|
113
|
-
provider.requestConsumableNotes = () =>
|
|
114
|
-
Promise.resolve({ consumableNotes: [] });
|
|
115
|
-
provider.requestGuardianInfo = () =>
|
|
116
|
-
Promise.resolve({ guardianInfo: { operator: "x" } });
|
|
117
|
-
|
|
118
|
-
const { failed } = await runConformance(getBehaviorCases(provider));
|
|
119
|
-
|
|
120
|
-
expect(failed).toEqual([]);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("surfaces a rejected call as a failure rather than escaping", async () => {
|
|
124
|
-
const provider = completeProvider();
|
|
125
|
-
provider.requestAssets = () => Promise.reject(new Error("wallet locked"));
|
|
126
|
-
|
|
127
|
-
const { failed } = await runConformance(getBehaviorCases(provider));
|
|
128
|
-
|
|
129
|
-
expect(failed[0].error).toBe("wallet locked");
|
|
130
|
-
});
|
|
131
|
-
});
|
package/adapter.ts
DELETED
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
import { Note, type NoteFilterTypes } from "@miden-sdk/miden-sdk";
|
|
2
|
-
import {
|
|
3
|
-
AllowedPrivateData,
|
|
4
|
-
BaseMessageSignerWalletAdapter,
|
|
5
|
-
EventEmitter,
|
|
6
|
-
scopePollingDetectionStrategy,
|
|
7
|
-
SignKind,
|
|
8
|
-
WalletConnectionError,
|
|
9
|
-
WalletDisconnectionError,
|
|
10
|
-
WalletName,
|
|
11
|
-
WalletNotConnectedError,
|
|
12
|
-
WalletNotReadyError,
|
|
13
|
-
WalletReadyState,
|
|
14
|
-
PrivateDataPermission,
|
|
15
|
-
WalletAdapterNetwork,
|
|
16
|
-
MidenSendTransaction,
|
|
17
|
-
MidenTransaction,
|
|
18
|
-
MidenConsumeTransaction,
|
|
19
|
-
TransactionType,
|
|
20
|
-
WalletTransactionError,
|
|
21
|
-
Asset,
|
|
22
|
-
GuardianInfo,
|
|
23
|
-
CreateAccountParams,
|
|
24
|
-
InputNoteDetails,
|
|
25
|
-
TransactionOutput,
|
|
26
|
-
WalletTransactionOutput,
|
|
27
|
-
b64ToU8,
|
|
28
|
-
} from "@miden-sdk/miden-wallet-adapter-base";
|
|
29
|
-
|
|
30
|
-
export interface MidenWalletEvents {
|
|
31
|
-
connect(...args: unknown[]): unknown;
|
|
32
|
-
disconnect(...args: unknown[]): unknown;
|
|
33
|
-
accountChange(...args: unknown[]): unknown;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface MidenWallet extends EventEmitter<MidenWalletEvents> {
|
|
37
|
-
address?: string;
|
|
38
|
-
publicKey?: Uint8Array;
|
|
39
|
-
requestSend(
|
|
40
|
-
transaction: MidenSendTransaction
|
|
41
|
-
): Promise<{ transactionId?: string }>;
|
|
42
|
-
requestConsume(
|
|
43
|
-
transaction: MidenConsumeTransaction
|
|
44
|
-
): Promise<{ transactionId?: string }>;
|
|
45
|
-
requestTransaction(
|
|
46
|
-
transaction: MidenTransaction
|
|
47
|
-
): Promise<{ transactionId?: string }>;
|
|
48
|
-
requestAssets(): Promise<{ assets: Asset[] }>;
|
|
49
|
-
requestGuardianInfo(): Promise<{ guardianInfo: GuardianInfo }>;
|
|
50
|
-
requestPrivateNotes(
|
|
51
|
-
noteFilterType: NoteFilterTypes,
|
|
52
|
-
noteIds?: string[]
|
|
53
|
-
): Promise<{
|
|
54
|
-
privateNotes: InputNoteDetails[];
|
|
55
|
-
}>;
|
|
56
|
-
waitForTransaction(
|
|
57
|
-
txId: string,
|
|
58
|
-
timeout?: number
|
|
59
|
-
): Promise<WalletTransactionOutput>;
|
|
60
|
-
signBytes(
|
|
61
|
-
message: Uint8Array,
|
|
62
|
-
kind: SignKind
|
|
63
|
-
): Promise<{ signature: Uint8Array }>;
|
|
64
|
-
importPrivateNote(note: Uint8Array): Promise<{ noteId: string }>;
|
|
65
|
-
requestConsumableNotes(): Promise<{ consumableNotes: InputNoteDetails[] }>;
|
|
66
|
-
createAccount(params?: CreateAccountParams): Promise<{ accountId: string }>;
|
|
67
|
-
connect(
|
|
68
|
-
privateDataPermission: PrivateDataPermission,
|
|
69
|
-
network: WalletAdapterNetwork,
|
|
70
|
-
allowedPrivateData?: AllowedPrivateData
|
|
71
|
-
): Promise<void>;
|
|
72
|
-
disconnect(): Promise<void>;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface MidenWindow extends Window {
|
|
76
|
-
midenWallet?: MidenWallet;
|
|
77
|
-
miden?: MidenWallet;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
declare const window: MidenWindow;
|
|
81
|
-
|
|
82
|
-
export interface MidenWalletAdapterConfig {
|
|
83
|
-
appName?: string;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export const MidenWalletName = "Bread Wallet" as WalletName<"Bread Wallet">;
|
|
87
|
-
|
|
88
|
-
export class MidenWalletAdapter extends BaseMessageSignerWalletAdapter {
|
|
89
|
-
name = MidenWalletName;
|
|
90
|
-
url =
|
|
91
|
-
"https://chromewebstore.google.com/detail/Bread/coajhopfooegmaifelglfboehacldcbo";
|
|
92
|
-
icon =
|
|
93
|
-
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjExIiBoZWlnaHQ9IjIxNCIgdmlld0JveD0iMCAwIDIxMSAyMTQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xMDcuNDQgMC4xMjE3NjJDMTIxLjk5IC0wLjkwOTY1MiAxMzQuNzMzIDQuNjc0NjMgMTQ1LjE1NyAxNC40NzYxQzE4My41NjQgLTQuNjYzMDMgMjIyLjk2NSAzNS40NDAxIDIwNi4zNTIgNzMuOTk5MUMyMDQuNzcyIDEwMy4wMDcgMjA4LjUwNyAxMzQuMzIyIDIwNi4zOTUgMTYzLjA1NUMyMDUuNjAyIDE3My43OSAyMDAuMTgyIDE4Mi4yODUgMTkxLjkzNyAxODguODRDMTc5LjgyMiAxOTguNDY1IDE1Ny41MSAyMTEuNzUxIDE0Mi4wNTcgMjEyLjc1MkMxMDEuMzk4IDIxNS4zODggNTcuOTI2NCAyMTAuNjk1IDE2Ljk2ODkgMjEyLjc1MkM2LjQxMDYzIDIxMS45NjUgMS41NzA5MyAyMDUuNTE0IDAuODA4MDQ2IDE5NS4zN0MyLjc5NzY0IDE1NS44MzUgLTEuNzYxMzMgMTEzLjg0NiAwLjgwODA0NiA3NC41OTcyQzMuMjA2NTQgMzcuODgxMyA0MC4wNTY3IC0xLjcwMzA1IDc5LjA4NTcgMTIuNjUxM0M4Ni45MDk4IDUuNTcxNzggOTYuNzk2NyAwLjg3MjQzMSAxMDcuNDQ3IDAuMTE1NjUzTDEwNy40NCAwLjEyMTc2MlpNMTE2LjcxNyAxMjguNTk3QzEzNi45NDIgMTIzLjkyMiAxNDQuMDc3IDk5LjQ3OTMgMTM2LjUyMSA4MS42NTIzQzEzMC45MDcgNjguNDAyNiAxMTcuNDc0IDYxLjgxMTMgMTAzLjYyNiA2MC44ODM3Qzc5LjI3NDkgNTkuMjU0MiA1My4xMjk1IDYyLjE0NyAyOC41ODkxIDYwLjkxNDJDMTguNzAyMiA2Mi4zNDIzIDEwLjQ1MDkgNjcuOTY5MyA4Ljc2MDMzIDc4LjI4MzRMOS4xNzUzIDE5Ny4zNzhDMTAuNTA1OCAyMDAuOTQ5IDEzLjcyODIgMjAzLjgwNSAxNy42MDk3IDIwNC4xODlDNDcuNjE4NCAyMDIuNTIzIDgwLjAwMTEgMjA2LjQwNSAxMDkuNzI5IDIwNC4yMTRDMTQ2LjI2OCAyMDEuNTIyIDE1Ny4wMDkgMTUyLjU2NCAxMjcuNDk1IDEzMy4zNjNMMTE2LjcyMyAxMjguNTk3SDExNi43MTdaIiBmaWxsPSIjRTc3NTM3Ii8+CjxwYXRoIGQ9Ik0xMTYuNzE3IDEyOC41OTdDMTM2Ljk0MiAxMjMuOTIyIDE0NC4wNzcgOTkuNDc5MyAxMzYuNTIxIDgxLjY1MjNDMTMwLjkwNyA2OC40MDI2IDExNy40NzQgNjEuODExMyAxMDMuNjI2IDYwLjg4MzdDNzkuMjc0OSA1OS4yNTQyIDUzLjEyOTUgNjIuMTQ3IDI4LjU4OTEgNjAuOTE0MkMxOC43MDIyIDYyLjM0MjMgMTAuNDUwOSA2Ny45NjkzIDguNzYwMzMgNzguMjgzNEw5LjE3NTMgMTk3LjM3OEMxMC41MDU4IDIwMC45NDkgMTMuNzI4MiAyMDMuODA1IDE3LjYwOTcgMjA0LjE4OUM0Ny42MTg0IDIwMi41MjMgODAuMDAxMSAyMDYuNDA1IDEwOS43MjkgMjA0LjIxNEMxNDYuMjY4IDIwMS41MjIgMTU3LjAwOSAxNTIuNTY0IDEyNy40OTUgMTMzLjM2M0wxMTYuNzIzIDEyOC41OTdIMTE2LjcxN1oiIGZpbGw9IiNGRkZGRkYiLz4KPC9zdmc+Cg==";
|
|
94
|
-
readonly supportedTransactionVersions = null;
|
|
95
|
-
|
|
96
|
-
private _connecting: boolean;
|
|
97
|
-
private _wallet: MidenWallet | null;
|
|
98
|
-
private _address: string | null;
|
|
99
|
-
private _publicKey: Uint8Array | null;
|
|
100
|
-
private _privateDataPermission: string;
|
|
101
|
-
private _readyState: WalletReadyState =
|
|
102
|
-
typeof window === "undefined" || typeof document === "undefined"
|
|
103
|
-
? WalletReadyState.Unsupported
|
|
104
|
-
: WalletReadyState.NotDetected;
|
|
105
|
-
|
|
106
|
-
constructor({ appName = "sample" }: MidenWalletAdapterConfig = {}) {
|
|
107
|
-
super();
|
|
108
|
-
this._connecting = false;
|
|
109
|
-
this._wallet = null;
|
|
110
|
-
this._address = null;
|
|
111
|
-
this._publicKey = null;
|
|
112
|
-
this._privateDataPermission = PrivateDataPermission.UponRequest;
|
|
113
|
-
|
|
114
|
-
if (this._readyState !== WalletReadyState.Unsupported) {
|
|
115
|
-
scopePollingDetectionStrategy(() => {
|
|
116
|
-
if (window?.midenWallet || window?.miden) {
|
|
117
|
-
this._readyState = WalletReadyState.Installed;
|
|
118
|
-
this.emit("readyStateChange", this._readyState);
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
return false;
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
get address() {
|
|
127
|
-
return this._address;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
get publicKey() {
|
|
131
|
-
return this._publicKey;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
get privateDataPermission() {
|
|
135
|
-
return this._privateDataPermission;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
get connecting() {
|
|
139
|
-
return this._connecting;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
get readyState() {
|
|
143
|
-
return this._readyState;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
set readyState(readyState) {
|
|
147
|
-
this._readyState = readyState;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* The wallet reports "success" as soon as a transaction is ACCEPTED into its
|
|
152
|
-
* queue, not when it lands on chain — so a resolved call with no `transactionId`
|
|
153
|
-
* means the transaction was never submitted. Returning that as `undefined`
|
|
154
|
-
* (the old `result.transactionId!` non-null assertion) made the dApp treat a
|
|
155
|
-
* silent drop as success. Reject instead, so the dApp can surface it and
|
|
156
|
-
* poll `waitForTransaction(txId)` for on-chain confirmation (0xMiden/wallet#314).
|
|
157
|
-
*/
|
|
158
|
-
private requireTransactionId(result: { transactionId?: string }): string {
|
|
159
|
-
if (!result?.transactionId) {
|
|
160
|
-
throw new WalletTransactionError(
|
|
161
|
-
"The wallet returned no transaction id — the transaction was not submitted"
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
return result.transactionId;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async requestSend(transaction: MidenSendTransaction): Promise<string> {
|
|
168
|
-
try {
|
|
169
|
-
const wallet = this._wallet;
|
|
170
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
171
|
-
let result: { transactionId?: string };
|
|
172
|
-
try {
|
|
173
|
-
result = await wallet.requestSend(transaction);
|
|
174
|
-
} catch (error: any) {
|
|
175
|
-
throw new WalletTransactionError(error?.message, error);
|
|
176
|
-
}
|
|
177
|
-
return this.requireTransactionId(result);
|
|
178
|
-
} catch (error: any) {
|
|
179
|
-
this.emit("error", error);
|
|
180
|
-
throw error;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async requestConsume(transaction: MidenConsumeTransaction): Promise<string> {
|
|
185
|
-
try {
|
|
186
|
-
const wallet = this._wallet;
|
|
187
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
188
|
-
let result: { transactionId?: string };
|
|
189
|
-
try {
|
|
190
|
-
result = await wallet.requestConsume(transaction);
|
|
191
|
-
} catch (error: any) {
|
|
192
|
-
throw new WalletTransactionError(error?.message, error);
|
|
193
|
-
}
|
|
194
|
-
return this.requireTransactionId(result);
|
|
195
|
-
} catch (error: any) {
|
|
196
|
-
this.emit("error", error);
|
|
197
|
-
throw error;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
async requestTransaction(transaction: MidenTransaction): Promise<string> {
|
|
202
|
-
try {
|
|
203
|
-
const wallet = this._wallet;
|
|
204
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
205
|
-
let result: { transactionId?: string };
|
|
206
|
-
try {
|
|
207
|
-
// The wallet's generalized `requestTransaction` endpoint only accepts
|
|
208
|
-
// a custom-transaction payload, so a `send`/`consume` transaction must
|
|
209
|
-
// be routed to its dedicated endpoint — otherwise the wallet rejects
|
|
210
|
-
// it with "Invalid CustomTransaction payload". Dispatching by `type`
|
|
211
|
-
// here is what lets the typed `Transaction` / `TransactionType` API
|
|
212
|
-
// (incl. `Transaction.createConsumeTransaction`) work for every type.
|
|
213
|
-
switch (transaction.type) {
|
|
214
|
-
case TransactionType.Send:
|
|
215
|
-
result = await wallet.requestSend(
|
|
216
|
-
transaction.payload as MidenSendTransaction
|
|
217
|
-
);
|
|
218
|
-
break;
|
|
219
|
-
case TransactionType.Consume:
|
|
220
|
-
result = await wallet.requestConsume(
|
|
221
|
-
transaction.payload as MidenConsumeTransaction
|
|
222
|
-
);
|
|
223
|
-
break;
|
|
224
|
-
default:
|
|
225
|
-
// Custom transactions — and legacy callers that pass a bare
|
|
226
|
-
// `CustomTransaction` payload — go through the generalized endpoint.
|
|
227
|
-
result = await wallet.requestTransaction(transaction);
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
} catch (error: any) {
|
|
231
|
-
throw new WalletTransactionError(error?.message, error);
|
|
232
|
-
}
|
|
233
|
-
return this.requireTransactionId(result);
|
|
234
|
-
} catch (error: any) {
|
|
235
|
-
this.emit("error", error);
|
|
236
|
-
throw error;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
async requestAssets(): Promise<Asset[]> {
|
|
241
|
-
try {
|
|
242
|
-
const wallet = this._wallet;
|
|
243
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
244
|
-
try {
|
|
245
|
-
const result = await wallet.requestAssets();
|
|
246
|
-
return result.assets;
|
|
247
|
-
} catch (error: any) {
|
|
248
|
-
throw new WalletTransactionError(error?.message, error);
|
|
249
|
-
}
|
|
250
|
-
} catch (error: any) {
|
|
251
|
-
this.emit("error", error);
|
|
252
|
-
throw error;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async requestGuardianInfo(): Promise<GuardianInfo> {
|
|
257
|
-
try {
|
|
258
|
-
const wallet = this._wallet;
|
|
259
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
260
|
-
try {
|
|
261
|
-
const result = await wallet.requestGuardianInfo();
|
|
262
|
-
return result.guardianInfo;
|
|
263
|
-
} catch (error: any) {
|
|
264
|
-
throw new WalletTransactionError(error?.message, error);
|
|
265
|
-
}
|
|
266
|
-
} catch (error: any) {
|
|
267
|
-
this.emit("error", error);
|
|
268
|
-
throw error;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
async requestPrivateNotes(
|
|
273
|
-
noteFilterType: NoteFilterTypes,
|
|
274
|
-
noteIds?: string[]
|
|
275
|
-
): Promise<InputNoteDetails[]> {
|
|
276
|
-
try {
|
|
277
|
-
const wallet = this._wallet;
|
|
278
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
279
|
-
try {
|
|
280
|
-
const result = await wallet.requestPrivateNotes(
|
|
281
|
-
noteFilterType,
|
|
282
|
-
noteIds
|
|
283
|
-
);
|
|
284
|
-
return result.privateNotes;
|
|
285
|
-
} catch (error: any) {
|
|
286
|
-
throw new WalletTransactionError(error?.message, error);
|
|
287
|
-
}
|
|
288
|
-
} catch (error: any) {
|
|
289
|
-
this.emit("error", error);
|
|
290
|
-
throw error;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async signBytes(message: Uint8Array, kind: SignKind): Promise<Uint8Array> {
|
|
295
|
-
try {
|
|
296
|
-
const wallet = this._wallet;
|
|
297
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
298
|
-
try {
|
|
299
|
-
const result = await wallet.signBytes(message, kind);
|
|
300
|
-
return result.signature;
|
|
301
|
-
} catch (error: any) {
|
|
302
|
-
throw new WalletTransactionError(error?.message, error);
|
|
303
|
-
}
|
|
304
|
-
} catch (error: any) {
|
|
305
|
-
this.emit("error", error);
|
|
306
|
-
throw error;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
async importPrivateNote(note: Uint8Array): Promise<string> {
|
|
311
|
-
try {
|
|
312
|
-
const wallet = this._wallet;
|
|
313
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
314
|
-
const result = await wallet.importPrivateNote(note);
|
|
315
|
-
return result.noteId;
|
|
316
|
-
} catch (error: any) {
|
|
317
|
-
this.emit("error", error);
|
|
318
|
-
throw error;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
async requestConsumableNotes(): Promise<InputNoteDetails[]> {
|
|
323
|
-
try {
|
|
324
|
-
const wallet = this._wallet;
|
|
325
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
326
|
-
const result = await wallet.requestConsumableNotes();
|
|
327
|
-
return result.consumableNotes;
|
|
328
|
-
} catch (error: any) {
|
|
329
|
-
this.emit("error", error);
|
|
330
|
-
throw error;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
async waitForTransaction(
|
|
335
|
-
txId: string,
|
|
336
|
-
timeout?: number
|
|
337
|
-
): Promise<TransactionOutput> {
|
|
338
|
-
try {
|
|
339
|
-
const wallet = this._wallet;
|
|
340
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
341
|
-
const result = await wallet.waitForTransaction(txId, timeout);
|
|
342
|
-
if ("errorMessage" in result) {
|
|
343
|
-
throw new WalletTransactionError(result.errorMessage);
|
|
344
|
-
}
|
|
345
|
-
const notes = result.outputNotes.map((serializedNote) => {
|
|
346
|
-
const u8Arr = b64ToU8(serializedNote);
|
|
347
|
-
return Note.deserialize(u8Arr);
|
|
348
|
-
});
|
|
349
|
-
return {
|
|
350
|
-
txHash: result.txHash,
|
|
351
|
-
outputNotes: notes,
|
|
352
|
-
};
|
|
353
|
-
} catch (error: any) {
|
|
354
|
-
this.emit("error", error);
|
|
355
|
-
throw error;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
async createAccount(params?: CreateAccountParams): Promise<string> {
|
|
360
|
-
try {
|
|
361
|
-
const wallet = this._wallet;
|
|
362
|
-
if (!wallet || !this.address) throw new WalletNotConnectedError();
|
|
363
|
-
try {
|
|
364
|
-
const result = await wallet.createAccount(params);
|
|
365
|
-
return result.accountId;
|
|
366
|
-
} catch (error: any) {
|
|
367
|
-
throw new WalletTransactionError(error?.message, error);
|
|
368
|
-
}
|
|
369
|
-
} catch (error: any) {
|
|
370
|
-
this.emit("error", error);
|
|
371
|
-
throw error;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
async connect(
|
|
376
|
-
privateDataPermission: PrivateDataPermission,
|
|
377
|
-
network: WalletAdapterNetwork,
|
|
378
|
-
allowedPrivateData?: AllowedPrivateData
|
|
379
|
-
): Promise<void> {
|
|
380
|
-
try {
|
|
381
|
-
// Guard only against a *concurrent* connect — NOT against being
|
|
382
|
-
// already connected. The in-app wallet browser preserves this
|
|
383
|
-
// adapter's JS context across a park/restore (a dApp is minimized and
|
|
384
|
-
// reopened without a page reload), so a re-opened dApp finds this
|
|
385
|
-
// instance with `connected === true`. An early-return-when-connected
|
|
386
|
-
// made a second connect() a silent no-op, so a re-mounted consumer
|
|
387
|
-
// that re-subscribed to events never received its account back —
|
|
388
|
-
// "Connect Wallet works only once" (0xMiden/wallet#470). Re-driving
|
|
389
|
-
// the handshake below is cheap for the common case — the wallet
|
|
390
|
-
// returns the current account for an existing permission without
|
|
391
|
-
// re-prompting — and re-emits `connect`, so repeated connect() calls
|
|
392
|
-
// repopulate the account instead of being suppressed by stale session
|
|
393
|
-
// state. (If the wallet has since locked, the re-drive can surface an
|
|
394
|
-
// unlock prompt where the old code was a silent no-op; that's the
|
|
395
|
-
// intended trade-off — a locked wallet genuinely needs to be unlocked
|
|
396
|
-
// to hand back the account.)
|
|
397
|
-
if (this.connecting) return;
|
|
398
|
-
if (this._readyState !== WalletReadyState.Installed)
|
|
399
|
-
throw new WalletNotReadyError();
|
|
400
|
-
|
|
401
|
-
this._connecting = true;
|
|
402
|
-
|
|
403
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
404
|
-
const wallet = window.midenWallet! || window.miden!;
|
|
405
|
-
|
|
406
|
-
try {
|
|
407
|
-
await wallet.connect(
|
|
408
|
-
privateDataPermission,
|
|
409
|
-
network,
|
|
410
|
-
allowedPrivateData
|
|
411
|
-
);
|
|
412
|
-
if (!wallet.address) {
|
|
413
|
-
throw new WalletConnectionError();
|
|
414
|
-
}
|
|
415
|
-
this._address = wallet.address;
|
|
416
|
-
this._publicKey = wallet.publicKey!;
|
|
417
|
-
} catch (error: any) {
|
|
418
|
-
throw new WalletConnectionError(error?.message, error);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
this._wallet = wallet;
|
|
422
|
-
this._privateDataPermission = privateDataPermission;
|
|
423
|
-
|
|
424
|
-
this.emit("connect", this._address);
|
|
425
|
-
} catch (error: any) {
|
|
426
|
-
this.emit("error", error);
|
|
427
|
-
throw error;
|
|
428
|
-
} finally {
|
|
429
|
-
this._connecting = false;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
async disconnect(): Promise<void> {
|
|
434
|
-
const wallet = this._wallet;
|
|
435
|
-
if (wallet) {
|
|
436
|
-
this._wallet = null;
|
|
437
|
-
this._address = null;
|
|
438
|
-
this._publicKey = null;
|
|
439
|
-
|
|
440
|
-
try {
|
|
441
|
-
await wallet.disconnect();
|
|
442
|
-
} catch (error: any) {
|
|
443
|
-
this.emit("error", new WalletDisconnectionError(error?.message, error));
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
this.emit("disconnect");
|
|
448
|
-
}
|
|
449
|
-
}
|