@aztec/wallet-sdk 0.0.1-commit.c7c42ec → 0.0.1-commit.f295ac2
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 +241 -267
- package/dest/base-wallet/base_wallet.d.ts +17 -7
- package/dest/base-wallet/base_wallet.d.ts.map +1 -1
- package/dest/base-wallet/base_wallet.js +32 -13
- package/dest/crypto.d.ts +183 -0
- package/dest/crypto.d.ts.map +1 -0
- package/dest/crypto.js +300 -0
- package/dest/manager/index.d.ts +4 -3
- package/dest/manager/index.d.ts.map +1 -1
- package/dest/manager/index.js +2 -0
- package/dest/manager/types.d.ts +22 -1
- package/dest/manager/types.d.ts.map +1 -1
- package/dest/manager/wallet_manager.d.ts +1 -1
- package/dest/manager/wallet_manager.d.ts.map +1 -1
- package/dest/manager/wallet_manager.js +34 -15
- package/dest/providers/extension/extension_provider.d.ts +53 -7
- package/dest/providers/extension/extension_provider.d.ts.map +1 -1
- package/dest/providers/extension/extension_provider.js +81 -13
- package/dest/providers/extension/extension_wallet.d.ts +140 -8
- package/dest/providers/extension/extension_wallet.d.ts.map +1 -1
- package/dest/providers/extension/extension_wallet.js +268 -46
- package/dest/providers/extension/index.d.ts +6 -4
- package/dest/providers/extension/index.d.ts.map +1 -1
- package/dest/providers/extension/index.js +2 -0
- package/dest/types.d.ts +92 -0
- package/dest/types.d.ts.map +1 -0
- package/dest/types.js +10 -0
- package/package.json +11 -9
- package/src/base-wallet/base_wallet.ts +40 -19
- package/src/crypto.ts +375 -0
- package/src/manager/index.ts +4 -8
- package/src/manager/types.ts +22 -0
- package/src/manager/wallet_manager.ts +43 -16
- package/src/providers/extension/extension_provider.ts +112 -17
- package/src/providers/extension/extension_wallet.ts +310 -55
- package/src/providers/extension/index.ts +5 -3
- package/src/{providers/types.ts → types.ts} +33 -6
- package/dest/providers/types.d.ts +0 -67
- package/dest/providers/types.d.ts.map +0 -1
- package/dest/providers/types.js +0 -3
package/src/manager/types.ts
CHANGED
|
@@ -36,6 +36,11 @@ export interface WalletManagerConfig {
|
|
|
36
36
|
*/
|
|
37
37
|
export type WalletProviderType = 'extension' | 'web' | 'embedded';
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Callback type for wallet disconnect events at the provider level.
|
|
41
|
+
*/
|
|
42
|
+
export type ProviderDisconnectionCallback = () => void;
|
|
43
|
+
|
|
39
44
|
/**
|
|
40
45
|
* A wallet provider that can connect to create a wallet instance.
|
|
41
46
|
* Chain information is already baked in from the discovery process.
|
|
@@ -56,6 +61,23 @@ export interface WalletProvider {
|
|
|
56
61
|
* @param appId - Application identifier for the requesting dapp
|
|
57
62
|
*/
|
|
58
63
|
connect(appId: string): Promise<Wallet>;
|
|
64
|
+
/**
|
|
65
|
+
* Disconnects the current wallet and cleans up resources.
|
|
66
|
+
* After calling this, the wallet returned from connect() should no longer be used.
|
|
67
|
+
* @returns A promise that resolves when disconnection is complete
|
|
68
|
+
*/
|
|
69
|
+
disconnect?(): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Registers a callback to be invoked when the wallet disconnects unexpectedly.
|
|
72
|
+
* @param callback - Function to call when wallet disconnects
|
|
73
|
+
* @returns A function to unregister the callback
|
|
74
|
+
*/
|
|
75
|
+
onDisconnect?(callback: ProviderDisconnectionCallback): () => void;
|
|
76
|
+
/**
|
|
77
|
+
* Returns whether the provider's wallet connection has been disconnected.
|
|
78
|
+
* @returns true if the wallet is no longer connected
|
|
79
|
+
*/
|
|
80
|
+
isDisconnected?(): boolean;
|
|
59
81
|
}
|
|
60
82
|
|
|
61
83
|
/**
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { ExtensionProvider, ExtensionWallet } from '../providers/extension/index.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
DiscoverWalletsOptions,
|
|
4
|
+
ExtensionWalletConfig,
|
|
5
|
+
ProviderDisconnectionCallback,
|
|
6
|
+
WalletManagerConfig,
|
|
7
|
+
WalletProvider,
|
|
8
|
+
} from './types.js';
|
|
3
9
|
|
|
4
10
|
/**
|
|
5
11
|
* Manager for wallet discovery, configuration, and connection
|
|
@@ -35,27 +41,51 @@ export class WalletManager {
|
|
|
35
41
|
const providers: WalletProvider[] = [];
|
|
36
42
|
const { chainInfo } = options;
|
|
37
43
|
|
|
38
|
-
// Discover extension wallets
|
|
39
44
|
if (this.config.extensions?.enabled) {
|
|
40
|
-
const
|
|
45
|
+
const discoveredWallets = await ExtensionProvider.discoverExtensions(chainInfo, options.timeout);
|
|
41
46
|
const extensionConfig = this.config.extensions;
|
|
42
47
|
|
|
43
|
-
for (const
|
|
44
|
-
|
|
45
|
-
if (!this.isExtensionAllowed(ext.id, extensionConfig)) {
|
|
48
|
+
for (const { info, port, sharedKey } of discoveredWallets) {
|
|
49
|
+
if (!this.isExtensionAllowed(info.id, extensionConfig)) {
|
|
46
50
|
continue;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
let extensionWallet: ExtensionWallet | null = null;
|
|
54
|
+
|
|
55
|
+
const provider: WalletProvider = {
|
|
56
|
+
id: info.id,
|
|
51
57
|
type: 'extension',
|
|
52
|
-
name:
|
|
53
|
-
icon:
|
|
58
|
+
name: info.name,
|
|
59
|
+
icon: info.icon,
|
|
54
60
|
metadata: {
|
|
55
|
-
version:
|
|
61
|
+
version: info.version,
|
|
62
|
+
verificationHash: info.verificationHash,
|
|
63
|
+
},
|
|
64
|
+
connect: (appId: string) => {
|
|
65
|
+
extensionWallet = ExtensionWallet.create(info, chainInfo, port, sharedKey, appId);
|
|
66
|
+
return Promise.resolve(extensionWallet.getWallet());
|
|
67
|
+
},
|
|
68
|
+
disconnect: async () => {
|
|
69
|
+
if (extensionWallet) {
|
|
70
|
+
await extensionWallet.disconnect();
|
|
71
|
+
extensionWallet = null;
|
|
72
|
+
}
|
|
56
73
|
},
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
onDisconnect: (callback: ProviderDisconnectionCallback) => {
|
|
75
|
+
if (extensionWallet) {
|
|
76
|
+
return extensionWallet.onDisconnect(callback);
|
|
77
|
+
}
|
|
78
|
+
return () => {};
|
|
79
|
+
},
|
|
80
|
+
isDisconnected: () => {
|
|
81
|
+
if (extensionWallet) {
|
|
82
|
+
return extensionWallet.isDisconnected();
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
providers.push(provider);
|
|
59
89
|
}
|
|
60
90
|
}
|
|
61
91
|
|
|
@@ -70,17 +100,14 @@ export class WalletManager {
|
|
|
70
100
|
* @param config - Extension wallet configuration containing allow/block lists
|
|
71
101
|
*/
|
|
72
102
|
private isExtensionAllowed(extensionId: string, config: ExtensionWalletConfig): boolean {
|
|
73
|
-
// Check block list first
|
|
74
103
|
if (config.blockList && config.blockList.includes(extensionId)) {
|
|
75
104
|
return false;
|
|
76
105
|
}
|
|
77
106
|
|
|
78
|
-
// If allow list exists, extension must be in it
|
|
79
107
|
if (config.allowList && config.allowList.length > 0) {
|
|
80
108
|
return config.allowList.includes(extensionId);
|
|
81
109
|
}
|
|
82
110
|
|
|
83
|
-
// If no allow list, extension is allowed (unless blocked)
|
|
84
111
|
return true;
|
|
85
112
|
}
|
|
86
113
|
}
|
|
@@ -2,34 +2,95 @@ import type { ChainInfo } from '@aztec/aztec.js/account';
|
|
|
2
2
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
3
3
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import { deriveSharedKey, exportPublicKey, generateKeyPair, hashSharedSecret, importPublicKey } from '../../crypto.js';
|
|
6
|
+
import { type DiscoveryRequest, type DiscoveryResponse, type WalletInfo, WalletMessageType } from '../../types.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* A discovered wallet with its secure channel components.
|
|
10
|
+
* Returned by {@link ExtensionProvider.discoverExtensions}.
|
|
11
|
+
*/
|
|
12
|
+
export interface DiscoveredWallet {
|
|
13
|
+
/** Basic wallet information (id, name, icon, version, publicKey, verificationHash) */
|
|
14
|
+
info: WalletInfo;
|
|
15
|
+
/** The MessagePort for private communication with the wallet */
|
|
16
|
+
port: MessagePort;
|
|
17
|
+
/** The derived AES-256-GCM shared key for encryption */
|
|
18
|
+
sharedKey: CryptoKey;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Internal type for discovery response with MessagePort
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
interface DiscoveryResponseWithPort extends DiscoveryResponse {
|
|
26
|
+
/** The MessagePort transferred from the wallet */
|
|
27
|
+
port?: MessagePort;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Provider for discovering Aztec wallet extensions.
|
|
32
|
+
*
|
|
33
|
+
* This class handles the discovery phase of wallet communication:
|
|
34
|
+
* 1. Broadcasts a discovery request with the dApp's public key
|
|
35
|
+
* 2. Receives responses from installed wallets with their public keys
|
|
36
|
+
* 3. Derives shared secrets and computes verification hashes
|
|
37
|
+
* 4. Returns discovered wallets with their secure channel components
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const wallets = await ExtensionProvider.discoverExtensions(chainInfo);
|
|
42
|
+
* // Display wallets to user with optional emoji verification
|
|
43
|
+
* for (const wallet of wallets) {
|
|
44
|
+
* const emoji = hashToEmoji(wallet.info.verificationHash!);
|
|
45
|
+
* console.log(`${wallet.info.name}: ${emoji}`);
|
|
46
|
+
* }
|
|
47
|
+
* // User selects a wallet after verifying
|
|
48
|
+
* const wallet = await ExtensionWallet.create(wallets[0], chainInfo, 'my-app');
|
|
49
|
+
* ```
|
|
9
50
|
*/
|
|
10
51
|
export class ExtensionProvider {
|
|
11
|
-
private static discoveredExtensions: Map<string, WalletInfo> = new Map();
|
|
12
52
|
private static discoveryInProgress = false;
|
|
13
53
|
|
|
14
54
|
/**
|
|
15
|
-
* Discovers all installed Aztec wallet extensions
|
|
55
|
+
* Discovers all installed Aztec wallet extensions and establishes secure channel components.
|
|
56
|
+
*
|
|
57
|
+
* This method:
|
|
58
|
+
* 1. Generates an ECDH key pair for this discovery session
|
|
59
|
+
* 2. Broadcasts a discovery request with the dApp's public key
|
|
60
|
+
* 3. Receives responses from wallets with their public keys and MessagePorts
|
|
61
|
+
* 4. Derives shared secrets and computes verification hashes
|
|
62
|
+
*
|
|
16
63
|
* @param chainInfo - Chain information to check if extensions support this network
|
|
17
64
|
* @param timeout - How long to wait for extensions to respond (ms)
|
|
18
|
-
* @returns Array of discovered
|
|
65
|
+
* @returns Array of discovered wallets with their secure channel components
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const wallets = await ExtensionProvider.discoverExtensions({
|
|
70
|
+
* chainId: Fr(31337),
|
|
71
|
+
* version: Fr(0)
|
|
72
|
+
* });
|
|
73
|
+
* // Access wallet info and secure channel
|
|
74
|
+
* const { info, port, sharedKey } = wallets[0];
|
|
75
|
+
* ```
|
|
19
76
|
*/
|
|
20
|
-
static async discoverExtensions(chainInfo: ChainInfo, timeout: number = 1000): Promise<
|
|
21
|
-
// If discovery is in progress, wait
|
|
77
|
+
static async discoverExtensions(chainInfo: ChainInfo, timeout: number = 1000): Promise<DiscoveredWallet[]> {
|
|
78
|
+
// If discovery is already in progress, wait and return empty
|
|
79
|
+
// (caller should retry or handle appropriately)
|
|
22
80
|
if (this.discoveryInProgress) {
|
|
23
81
|
await new Promise(resolve => setTimeout(resolve, timeout));
|
|
24
|
-
return
|
|
82
|
+
return [];
|
|
25
83
|
}
|
|
26
84
|
|
|
27
85
|
this.discoveryInProgress = true;
|
|
28
|
-
this.discoveredExtensions.clear();
|
|
29
86
|
|
|
30
|
-
|
|
87
|
+
// Generate key pair for this discovery session
|
|
88
|
+
const keyPair = await generateKeyPair();
|
|
89
|
+
const exportedPublicKey = await exportPublicKey(keyPair.publicKey);
|
|
90
|
+
|
|
91
|
+
const { promise, resolve } = promiseWithResolvers<DiscoveredWallet[]>();
|
|
31
92
|
const requestId = globalThis.crypto.randomUUID();
|
|
32
|
-
const responses:
|
|
93
|
+
const responses: DiscoveredWallet[] = [];
|
|
33
94
|
|
|
34
95
|
// Set up listener for discovery responses
|
|
35
96
|
const handleMessage = (event: MessageEvent) => {
|
|
@@ -37,26 +98,60 @@ export class ExtensionProvider {
|
|
|
37
98
|
return;
|
|
38
99
|
}
|
|
39
100
|
|
|
40
|
-
let data:
|
|
101
|
+
let data: DiscoveryResponseWithPort;
|
|
41
102
|
try {
|
|
42
103
|
data = JSON.parse(event.data);
|
|
43
104
|
} catch {
|
|
44
105
|
return;
|
|
45
106
|
}
|
|
46
107
|
|
|
47
|
-
if (data.type ===
|
|
48
|
-
|
|
49
|
-
|
|
108
|
+
if (data.type === WalletMessageType.DISCOVERY_RESPONSE && data.requestId === requestId) {
|
|
109
|
+
// Get the MessagePort from the event
|
|
110
|
+
const port = event.ports?.[0];
|
|
111
|
+
if (!port) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Derive shared key from wallet's public key
|
|
116
|
+
const walletPublicKey = data.walletInfo.publicKey;
|
|
117
|
+
if (!walletPublicKey) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
void (async () => {
|
|
122
|
+
try {
|
|
123
|
+
const importedWalletKey = await importPublicKey(walletPublicKey);
|
|
124
|
+
const sharedKey = await deriveSharedKey(keyPair.privateKey, importedWalletKey);
|
|
125
|
+
|
|
126
|
+
// Compute verification hash
|
|
127
|
+
const verificationHash = await hashSharedSecret(sharedKey);
|
|
128
|
+
|
|
129
|
+
// Create wallet info with verification hash
|
|
130
|
+
const walletInfo: WalletInfo = {
|
|
131
|
+
...data.walletInfo,
|
|
132
|
+
verificationHash,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
responses.push({
|
|
136
|
+
info: walletInfo,
|
|
137
|
+
port,
|
|
138
|
+
sharedKey,
|
|
139
|
+
});
|
|
140
|
+
} catch {
|
|
141
|
+
// Failed to derive key, skip this wallet
|
|
142
|
+
}
|
|
143
|
+
})();
|
|
50
144
|
}
|
|
51
145
|
};
|
|
52
146
|
|
|
53
147
|
window.addEventListener('message', handleMessage);
|
|
54
148
|
|
|
55
|
-
// Send discovery message
|
|
149
|
+
// Send discovery message with our public key
|
|
56
150
|
const discoveryMessage: DiscoveryRequest = {
|
|
57
|
-
type:
|
|
151
|
+
type: WalletMessageType.DISCOVERY,
|
|
58
152
|
requestId,
|
|
59
153
|
chainInfo,
|
|
154
|
+
publicKey: exportedPublicKey,
|
|
60
155
|
};
|
|
61
156
|
window.postMessage(jsonStringify(discoveryMessage), '*');
|
|
62
157
|
|