@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/dest/types.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ChainInfo } from '@aztec/aztec.js/account';
|
|
2
|
+
import type { ExportedPublicKey } from './crypto.js';
|
|
3
|
+
/**
|
|
4
|
+
* Message types for wallet SDK communication.
|
|
5
|
+
* All types are prefixed with 'aztec-wallet-' for namespacing.
|
|
6
|
+
*/
|
|
7
|
+
export declare enum WalletMessageType {
|
|
8
|
+
/** Discovery request to find installed wallets */
|
|
9
|
+
DISCOVERY = "aztec-wallet-discovery",
|
|
10
|
+
/** Discovery response from a wallet */
|
|
11
|
+
DISCOVERY_RESPONSE = "aztec-wallet-discovery-response",
|
|
12
|
+
/** Session disconnected notification (unencrypted control message) */
|
|
13
|
+
SESSION_DISCONNECTED = "aztec-wallet-session-disconnected",
|
|
14
|
+
/** Explicit disconnect request from dApp */
|
|
15
|
+
DISCONNECT = "aztec-wallet-disconnect"
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Information about an installed Aztec wallet
|
|
19
|
+
*/
|
|
20
|
+
export interface WalletInfo {
|
|
21
|
+
/** Unique identifier for the wallet */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Display name of the wallet */
|
|
24
|
+
name: string;
|
|
25
|
+
/** URL to the wallet's icon */
|
|
26
|
+
icon?: string;
|
|
27
|
+
/** Wallet version */
|
|
28
|
+
version: string;
|
|
29
|
+
/** Wallet's ECDH public key for secure channel establishment */
|
|
30
|
+
publicKey: ExportedPublicKey;
|
|
31
|
+
/**
|
|
32
|
+
* Hash of the shared secret for anti-MITM verification.
|
|
33
|
+
* Both dApp and wallet independently compute this from the ECDH shared secret.
|
|
34
|
+
* Use {@link hashToEmoji} to convert to a visual representation for user verification.
|
|
35
|
+
*/
|
|
36
|
+
verificationHash?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Message format for wallet communication (internal, before encryption)
|
|
40
|
+
*/
|
|
41
|
+
export interface WalletMessage {
|
|
42
|
+
/** Unique message ID for tracking responses */
|
|
43
|
+
messageId: string;
|
|
44
|
+
/** The wallet method to call */
|
|
45
|
+
type: string;
|
|
46
|
+
/** Arguments for the method */
|
|
47
|
+
args: unknown[];
|
|
48
|
+
/** Chain information */
|
|
49
|
+
chainInfo: ChainInfo;
|
|
50
|
+
/** Application ID making the request */
|
|
51
|
+
appId: string;
|
|
52
|
+
/** Wallet ID to target a specific wallet */
|
|
53
|
+
walletId: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Response message from wallet
|
|
57
|
+
*/
|
|
58
|
+
export interface WalletResponse {
|
|
59
|
+
/** Message ID matching the request */
|
|
60
|
+
messageId: string;
|
|
61
|
+
/** Result data (if successful) */
|
|
62
|
+
result?: unknown;
|
|
63
|
+
/** Error data (if failed) */
|
|
64
|
+
error?: unknown;
|
|
65
|
+
/** Wallet ID that sent the response */
|
|
66
|
+
walletId: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Discovery message for finding installed wallets (public, unencrypted)
|
|
70
|
+
*/
|
|
71
|
+
export interface DiscoveryRequest {
|
|
72
|
+
/** Message type for discovery */
|
|
73
|
+
type: WalletMessageType.DISCOVERY;
|
|
74
|
+
/** Request ID */
|
|
75
|
+
requestId: string;
|
|
76
|
+
/** Chain information to check if wallet supports this network */
|
|
77
|
+
chainInfo: ChainInfo;
|
|
78
|
+
/** dApp's ECDH public key for deriving shared secret */
|
|
79
|
+
publicKey: ExportedPublicKey;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Discovery response from a wallet (public, unencrypted)
|
|
83
|
+
*/
|
|
84
|
+
export interface DiscoveryResponse {
|
|
85
|
+
/** Message type for discovery response */
|
|
86
|
+
type: WalletMessageType.DISCOVERY_RESPONSE;
|
|
87
|
+
/** Request ID matching the discovery request */
|
|
88
|
+
requestId: string;
|
|
89
|
+
/** Wallet information */
|
|
90
|
+
walletInfo: WalletInfo;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUV6RCxPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVyRDs7O0dBR0c7QUFDSCxvQkFBWSxpQkFBaUI7SUFDM0Isa0RBQWtEO0lBQ2xELFNBQVMsMkJBQTJCO0lBQ3BDLHVDQUF1QztJQUN2QyxrQkFBa0Isb0NBQW9DO0lBQ3RELHNFQUFzRTtJQUN0RSxvQkFBb0Isc0NBQXNDO0lBQzFELDRDQUE0QztJQUM1QyxVQUFVLDRCQUE0QjtDQUN2QztBQUVEOztHQUVHO0FBQ0gsTUFBTSxXQUFXLFVBQVU7SUFDekIsdUNBQXVDO0lBQ3ZDLEVBQUUsRUFBRSxNQUFNLENBQUM7SUFDWCxpQ0FBaUM7SUFDakMsSUFBSSxFQUFFLE1BQU0sQ0FBQztJQUNiLCtCQUErQjtJQUMvQixJQUFJLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDZCxxQkFBcUI7SUFDckIsT0FBTyxFQUFFLE1BQU0sQ0FBQztJQUNoQixnRUFBZ0U7SUFDaEUsU0FBUyxFQUFFLGlCQUFpQixDQUFDO0lBQzdCOzs7O09BSUc7SUFDSCxnQkFBZ0IsQ0FBQyxFQUFFLE1BQU0sQ0FBQztDQUMzQjtBQUVEOztHQUVHO0FBQ0gsTUFBTSxXQUFXLGFBQWE7SUFDNUIsK0NBQStDO0lBQy9DLFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIsZ0NBQWdDO0lBQ2hDLElBQUksRUFBRSxNQUFNLENBQUM7SUFDYiwrQkFBK0I7SUFDL0IsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFDO0lBQ2hCLHdCQUF3QjtJQUN4QixTQUFTLEVBQUUsU0FBUyxDQUFDO0lBQ3JCLHdDQUF3QztJQUN4QyxLQUFLLEVBQUUsTUFBTSxDQUFDO0lBQ2QsNENBQTRDO0lBQzVDLFFBQVEsRUFBRSxNQUFNLENBQUM7Q0FDbEI7QUFFRDs7R0FFRztBQUNILE1BQU0sV0FBVyxjQUFjO0lBQzdCLHNDQUFzQztJQUN0QyxTQUFTLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLGtDQUFrQztJQUNsQyxNQUFNLENBQUMsRUFBRSxPQUFPLENBQUM7SUFDakIsNkJBQTZCO0lBQzdCLEtBQUssQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUNoQix1Q0FBdUM7SUFDdkMsUUFBUSxFQUFFLE1BQU0sQ0FBQztDQUNsQjtBQUVEOztHQUVHO0FBQ0gsTUFBTSxXQUFXLGdCQUFnQjtJQUMvQixpQ0FBaUM7SUFDakMsSUFBSSxFQUFFLGlCQUFpQixDQUFDLFNBQVMsQ0FBQztJQUNsQyxpQkFBaUI7SUFDakIsU0FBUyxFQUFFLE1BQU0sQ0FBQztJQUNsQixpRUFBaUU7SUFDakUsU0FBUyxFQUFFLFNBQVMsQ0FBQztJQUNyQix3REFBd0Q7SUFDeEQsU0FBUyxFQUFFLGlCQUFpQixDQUFDO0NBQzlCO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFdBQVcsaUJBQWlCO0lBQ2hDLDBDQUEwQztJQUMxQyxJQUFJLEVBQUUsaUJBQWlCLENBQUMsa0JBQWtCLENBQUM7SUFDM0MsZ0RBQWdEO0lBQ2hELFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIseUJBQXlCO0lBQ3pCLFVBQVUsRUFBRSxVQUFVLENBQUM7Q0FDeEIifQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;GAGG;AACH,oBAAY,iBAAiB;IAC3B,kDAAkD;IAClD,SAAS,2BAA2B;IACpC,uCAAuC;IACvC,kBAAkB,oCAAoC;IACtD,sEAAsE;IACtE,oBAAoB,sCAAsC;IAC1D,4CAA4C;IAC5C,UAAU,4BAA4B;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,EAAE,iBAAiB,CAAC;IAC7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,wBAAwB;IACxB,SAAS,EAAE,SAAS,CAAC;IACrB,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC;IAClC,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,SAAS,EAAE,SAAS,CAAC;IACrB,wDAAwD;IACxD,SAAS,EAAE,iBAAiB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,IAAI,EAAE,iBAAiB,CAAC,kBAAkB,CAAC;IAC3C,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,UAAU,EAAE,UAAU,CAAC;CACxB"}
|
package/dest/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message types for wallet SDK communication.
|
|
3
|
+
* All types are prefixed with 'aztec-wallet-' for namespacing.
|
|
4
|
+
*/ export var WalletMessageType = /*#__PURE__*/ function(WalletMessageType) {
|
|
5
|
+
/** Discovery request to find installed wallets */ WalletMessageType["DISCOVERY"] = "aztec-wallet-discovery";
|
|
6
|
+
/** Discovery response from a wallet */ WalletMessageType["DISCOVERY_RESPONSE"] = "aztec-wallet-discovery-response";
|
|
7
|
+
/** Session disconnected notification (unencrypted control message) */ WalletMessageType["SESSION_DISCONNECTED"] = "aztec-wallet-session-disconnected";
|
|
8
|
+
/** Explicit disconnect request from dApp */ WalletMessageType["DISCONNECT"] = "aztec-wallet-disconnect";
|
|
9
|
+
return WalletMessageType;
|
|
10
|
+
}({});
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/wallet-sdk",
|
|
3
3
|
"homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/wallet-sdk",
|
|
4
|
-
"version": "0.0.1-commit.
|
|
4
|
+
"version": "0.0.1-commit.f295ac2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./base-wallet": "./dest/base-wallet/index.js",
|
|
8
8
|
"./providers/extension": "./dest/providers/extension/index.js",
|
|
9
|
+
"./crypto": "./dest/crypto.js",
|
|
10
|
+
"./types": "./dest/types.js",
|
|
9
11
|
"./manager": "./dest/manager/index.js"
|
|
10
12
|
},
|
|
11
13
|
"typedocOptions": {
|
|
@@ -62,19 +64,19 @@
|
|
|
62
64
|
]
|
|
63
65
|
},
|
|
64
66
|
"dependencies": {
|
|
65
|
-
"@aztec/aztec.js": "0.0.1-commit.
|
|
66
|
-
"@aztec/constants": "0.0.1-commit.
|
|
67
|
-
"@aztec/entrypoints": "0.0.1-commit.
|
|
68
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
69
|
-
"@aztec/pxe": "0.0.1-commit.
|
|
70
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
67
|
+
"@aztec/aztec.js": "0.0.1-commit.f295ac2",
|
|
68
|
+
"@aztec/constants": "0.0.1-commit.f295ac2",
|
|
69
|
+
"@aztec/entrypoints": "0.0.1-commit.f295ac2",
|
|
70
|
+
"@aztec/foundation": "0.0.1-commit.f295ac2",
|
|
71
|
+
"@aztec/pxe": "0.0.1-commit.f295ac2",
|
|
72
|
+
"@aztec/stdlib": "0.0.1-commit.f295ac2"
|
|
71
73
|
},
|
|
72
74
|
"devDependencies": {
|
|
73
|
-
"@aztec/noir-contracts.js": "0.0.1-commit.
|
|
75
|
+
"@aztec/noir-contracts.js": "0.0.1-commit.f295ac2",
|
|
74
76
|
"@jest/globals": "^30.0.0",
|
|
75
77
|
"@types/jest": "^30.0.0",
|
|
76
78
|
"@types/node": "^22.15.17",
|
|
77
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
79
|
+
"@typescript/native-preview": "7.0.0-dev.20260113.1",
|
|
78
80
|
"jest": "^30.0.0",
|
|
79
81
|
"jest-mock-extended": "^4.0.0",
|
|
80
82
|
"resolve-typescript-plugin": "^2.0.1",
|
|
@@ -4,7 +4,6 @@ import type { FeePaymentMethod } from '@aztec/aztec.js/fee';
|
|
|
4
4
|
import type {
|
|
5
5
|
Aliased,
|
|
6
6
|
BatchResults,
|
|
7
|
-
BatchableMethods,
|
|
8
7
|
BatchedMethod,
|
|
9
8
|
PrivateEvent,
|
|
10
9
|
PrivateEventFilter,
|
|
@@ -34,14 +33,13 @@ import {
|
|
|
34
33
|
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
35
34
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
36
35
|
import {
|
|
37
|
-
type ContractClassMetadata,
|
|
38
36
|
type ContractInstanceWithAddress,
|
|
39
|
-
type ContractMetadata,
|
|
40
37
|
computePartialAddress,
|
|
41
38
|
getContractClassFromArtifact,
|
|
42
39
|
} from '@aztec/stdlib/contract';
|
|
43
40
|
import { SimulationError } from '@aztec/stdlib/errors';
|
|
44
41
|
import { Gas, GasSettings } from '@aztec/stdlib/gas';
|
|
42
|
+
import { siloNullifier } from '@aztec/stdlib/hash';
|
|
45
43
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
46
44
|
import type {
|
|
47
45
|
TxExecutionRequest,
|
|
@@ -76,7 +74,7 @@ export type FeeOptions = {
|
|
|
76
74
|
export abstract class BaseWallet implements Wallet {
|
|
77
75
|
protected log = createLogger('wallet-sdk:base_wallet');
|
|
78
76
|
|
|
79
|
-
protected
|
|
77
|
+
protected minFeePadding = 0.5;
|
|
80
78
|
protected cancellableTransactions = false;
|
|
81
79
|
|
|
82
80
|
// Protected because we want to force wallets to instantiate their own PXE.
|
|
@@ -132,9 +130,7 @@ export abstract class BaseWallet implements Wallet {
|
|
|
132
130
|
return account.createAuthWit(messageHashOrIntent);
|
|
133
131
|
}
|
|
134
132
|
|
|
135
|
-
public async batch<const T extends readonly BatchedMethod
|
|
136
|
-
methods: T,
|
|
137
|
-
): Promise<BatchResults<T>> {
|
|
133
|
+
public async batch<const T extends readonly BatchedMethod[]>(methods: T): Promise<BatchResults<T>> {
|
|
138
134
|
const results: any[] = [];
|
|
139
135
|
for (const method of methods) {
|
|
140
136
|
const { name, args } = method;
|
|
@@ -165,7 +161,7 @@ export abstract class BaseWallet implements Wallet {
|
|
|
165
161
|
gasSettings?: Partial<FieldsOf<GasSettings>>,
|
|
166
162
|
): Promise<FeeOptions> {
|
|
167
163
|
const maxFeesPerGas =
|
|
168
|
-
gasSettings?.maxFeesPerGas ?? (await this.aztecNode.
|
|
164
|
+
gasSettings?.maxFeesPerGas ?? (await this.aztecNode.getCurrentMinFees()).mul(1 + this.minFeePadding);
|
|
169
165
|
let accountFeePaymentMethodOptions;
|
|
170
166
|
// The transaction does not include a fee payment method, so we set the flag
|
|
171
167
|
// for the account to use its fee juice balance
|
|
@@ -227,7 +223,7 @@ export abstract class BaseWallet implements Wallet {
|
|
|
227
223
|
artifact?: ContractArtifact,
|
|
228
224
|
secretKey?: Fr,
|
|
229
225
|
): Promise<ContractInstanceWithAddress> {
|
|
230
|
-
const
|
|
226
|
+
const existingInstance = await this.pxe.getContractInstance(instance.address);
|
|
231
227
|
|
|
232
228
|
if (existingInstance) {
|
|
233
229
|
// Instance already registered in the wallet
|
|
@@ -244,13 +240,12 @@ export abstract class BaseWallet implements Wallet {
|
|
|
244
240
|
// Instance not registered yet
|
|
245
241
|
if (!artifact) {
|
|
246
242
|
// Try to get the artifact from the wallet's contract class storage
|
|
247
|
-
|
|
248
|
-
if (!
|
|
243
|
+
artifact = await this.pxe.getContractArtifact(instance.currentContractClassId);
|
|
244
|
+
if (!artifact) {
|
|
249
245
|
throw new Error(
|
|
250
246
|
`Cannot register contract at ${instance.address.toString()}: artifact is required but not provided, and wallet does not have the artifact for contract class ${instance.currentContractClassId.toString()}`,
|
|
251
247
|
);
|
|
252
248
|
}
|
|
253
|
-
artifact = classMetadata.artifact;
|
|
254
249
|
}
|
|
255
250
|
await this.pxe.registerContract({ artifact, instance });
|
|
256
251
|
}
|
|
@@ -315,13 +310,6 @@ export abstract class BaseWallet implements Wallet {
|
|
|
315
310
|
return this.pxe.simulateUtility(call, authwits);
|
|
316
311
|
}
|
|
317
312
|
|
|
318
|
-
getContractClassMetadata(id: Fr, includeArtifact: boolean = false): Promise<ContractClassMetadata> {
|
|
319
|
-
return this.pxe.getContractClassMetadata(id, includeArtifact);
|
|
320
|
-
}
|
|
321
|
-
getContractMetadata(address: AztecAddress): Promise<ContractMetadata> {
|
|
322
|
-
return this.pxe.getContractMetadata(address);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
313
|
getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
|
|
326
314
|
return this.aztecNode.getTxReceipt(txHash);
|
|
327
315
|
}
|
|
@@ -345,4 +333,37 @@ export abstract class BaseWallet implements Wallet {
|
|
|
345
333
|
|
|
346
334
|
return decodedEvents;
|
|
347
335
|
}
|
|
336
|
+
|
|
337
|
+
async getContractMetadata(address: AztecAddress) {
|
|
338
|
+
const instance = await this.pxe.getContractInstance(address);
|
|
339
|
+
const initNullifier = await siloNullifier(address, address.toField());
|
|
340
|
+
const publiclyRegisteredContract = await this.aztecNode.getContract(address);
|
|
341
|
+
const [initNullifierMembershipWitness, publiclyRegisteredContractClass] = await Promise.all([
|
|
342
|
+
this.aztecNode.getNullifierMembershipWitness('latest', initNullifier),
|
|
343
|
+
publiclyRegisteredContract
|
|
344
|
+
? this.aztecNode.getContractClass(
|
|
345
|
+
publiclyRegisteredContract.currentContractClassId || instance?.currentContractClassId,
|
|
346
|
+
)
|
|
347
|
+
: undefined,
|
|
348
|
+
]);
|
|
349
|
+
const isContractUpdated =
|
|
350
|
+
publiclyRegisteredContract &&
|
|
351
|
+
!publiclyRegisteredContract.currentContractClassId.equals(publiclyRegisteredContract.originalContractClassId);
|
|
352
|
+
return {
|
|
353
|
+
instance: instance ?? undefined,
|
|
354
|
+
isContractInitialized: !!initNullifierMembershipWitness,
|
|
355
|
+
isContractPublished: !!publiclyRegisteredContract,
|
|
356
|
+
isContractClassPubliclyRegistered: !!publiclyRegisteredContractClass,
|
|
357
|
+
isContractUpdated: !!isContractUpdated,
|
|
358
|
+
updatedContractClassId: isContractUpdated ? publiclyRegisteredContract.currentContractClassId : undefined,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async getContractClassMetadata(id: Fr) {
|
|
363
|
+
const publiclyRegisteredContractClass = await this.aztecNode.getContractClass(id);
|
|
364
|
+
return {
|
|
365
|
+
isArtifactRegistered: !!(await this.pxe.getContractArtifact(id)),
|
|
366
|
+
isContractClassPubliclyRegistered: !!publiclyRegisteredContractClass,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
348
369
|
}
|
package/src/crypto.ts
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cryptographic utilities for secure wallet communication.
|
|
3
|
+
*
|
|
4
|
+
* This module provides ECDH key exchange and AES-GCM encryption primitives
|
|
5
|
+
* for establishing secure communication channels between dApps and wallet extensions.
|
|
6
|
+
*
|
|
7
|
+
* The crypto flow:
|
|
8
|
+
* 1. Both parties generate ECDH key pairs using {@link generateKeyPair}
|
|
9
|
+
* 2. Public keys are exchanged (exported via {@link exportPublicKey}, imported via {@link importPublicKey})
|
|
10
|
+
* 3. Both parties derive the same shared secret using {@link deriveSharedKey}
|
|
11
|
+
* 4. Messages are encrypted/decrypted using {@link encrypt} and {@link decrypt}
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // Party A
|
|
16
|
+
* const keyPairA = await generateKeyPair();
|
|
17
|
+
* const publicKeyA = await exportPublicKey(keyPairA.publicKey);
|
|
18
|
+
*
|
|
19
|
+
* // Party B
|
|
20
|
+
* const keyPairB = await generateKeyPair();
|
|
21
|
+
* const publicKeyB = await exportPublicKey(keyPairB.publicKey);
|
|
22
|
+
*
|
|
23
|
+
* // Exchange public keys, then derive shared secret
|
|
24
|
+
* const importedB = await importPublicKey(publicKeyB);
|
|
25
|
+
* const sharedKeyA = await deriveSharedKey(keyPairA.privateKey, importedB);
|
|
26
|
+
*
|
|
27
|
+
* // Encrypt and decrypt
|
|
28
|
+
* const encrypted = await encrypt(sharedKeyA, { message: 'hello' });
|
|
29
|
+
* const decrypted = await decrypt(sharedKeyB, encrypted);
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @packageDocumentation
|
|
33
|
+
*/
|
|
34
|
+
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Exported public key in JWK format for transmission over untrusted channels.
|
|
38
|
+
*
|
|
39
|
+
* Contains only the public components of an ECDH P-256 key, safe to share.
|
|
40
|
+
*/
|
|
41
|
+
export interface ExportedPublicKey {
|
|
42
|
+
/** Key type - always "EC" for elliptic curve */
|
|
43
|
+
kty: string;
|
|
44
|
+
/** Curve name - always "P-256" */
|
|
45
|
+
crv: string;
|
|
46
|
+
/** X coordinate (base64url encoded) */
|
|
47
|
+
x: string;
|
|
48
|
+
/** Y coordinate (base64url encoded) */
|
|
49
|
+
y: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Encrypted message payload containing ciphertext and initialization vector.
|
|
54
|
+
*
|
|
55
|
+
* Both fields are base64-encoded for safe transmission as JSON.
|
|
56
|
+
*/
|
|
57
|
+
export interface EncryptedPayload {
|
|
58
|
+
/** Initialization vector (base64 encoded, 12 bytes) */
|
|
59
|
+
iv: string;
|
|
60
|
+
/** Ciphertext (base64 encoded) */
|
|
61
|
+
ciphertext: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* ECDH key pair for secure communication.
|
|
66
|
+
*
|
|
67
|
+
* The private key should never be exported or transmitted.
|
|
68
|
+
* The public key can be exported via {@link exportPublicKey} for exchange.
|
|
69
|
+
*/
|
|
70
|
+
export interface SecureKeyPair {
|
|
71
|
+
/** Public key - safe to share */
|
|
72
|
+
publicKey: CryptoKey;
|
|
73
|
+
/** Private key - keep secret, used for key derivation */
|
|
74
|
+
privateKey: CryptoKey;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Generates an ECDH P-256 key pair for key exchange.
|
|
79
|
+
*
|
|
80
|
+
* The generated key pair can be used to derive a shared secret with another
|
|
81
|
+
* party's public key using {@link deriveSharedKey}.
|
|
82
|
+
*
|
|
83
|
+
* @returns A new ECDH key pair
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const keyPair = await generateKeyPair();
|
|
88
|
+
* const publicKey = await exportPublicKey(keyPair.publicKey);
|
|
89
|
+
* // Send publicKey to the other party
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export async function generateKeyPair(): Promise<SecureKeyPair> {
|
|
93
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
94
|
+
{
|
|
95
|
+
name: 'ECDH',
|
|
96
|
+
namedCurve: 'P-256',
|
|
97
|
+
},
|
|
98
|
+
true, // extractable (needed to export public key)
|
|
99
|
+
['deriveKey'],
|
|
100
|
+
);
|
|
101
|
+
return {
|
|
102
|
+
publicKey: keyPair.publicKey,
|
|
103
|
+
privateKey: keyPair.privateKey,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Exports a public key to JWK format for transmission.
|
|
109
|
+
*
|
|
110
|
+
* The exported key contains only public components and is safe to transmit
|
|
111
|
+
* over untrusted channels.
|
|
112
|
+
*
|
|
113
|
+
* @param publicKey - The CryptoKey public key to export
|
|
114
|
+
* @returns The public key in JWK format
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const keyPair = await generateKeyPair();
|
|
119
|
+
* const exported = await exportPublicKey(keyPair.publicKey);
|
|
120
|
+
* // exported can be JSON serialized and sent to another party
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export async function exportPublicKey(publicKey: CryptoKey): Promise<ExportedPublicKey> {
|
|
124
|
+
const jwk = await crypto.subtle.exportKey('jwk', publicKey);
|
|
125
|
+
return {
|
|
126
|
+
kty: jwk.kty!,
|
|
127
|
+
crv: jwk.crv!,
|
|
128
|
+
x: jwk.x!,
|
|
129
|
+
y: jwk.y!,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Imports a public key from JWK format.
|
|
135
|
+
*
|
|
136
|
+
* Used to import the other party's public key for deriving a shared secret.
|
|
137
|
+
*
|
|
138
|
+
* @param exported - The public key in JWK format
|
|
139
|
+
* @returns A CryptoKey that can be used with {@link deriveSharedKey}
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* // Receive exported public key from other party
|
|
144
|
+
* const theirPublicKey = await importPublicKey(receivedPublicKey);
|
|
145
|
+
* const sharedKey = await deriveSharedKey(myPrivateKey, theirPublicKey);
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export function importPublicKey(exported: ExportedPublicKey): Promise<CryptoKey> {
|
|
149
|
+
return crypto.subtle.importKey(
|
|
150
|
+
'jwk',
|
|
151
|
+
{
|
|
152
|
+
kty: exported.kty,
|
|
153
|
+
crv: exported.crv,
|
|
154
|
+
x: exported.x,
|
|
155
|
+
y: exported.y,
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'ECDH',
|
|
159
|
+
namedCurve: 'P-256',
|
|
160
|
+
},
|
|
161
|
+
false,
|
|
162
|
+
[],
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Derives a shared AES-256-GCM key from ECDH key exchange.
|
|
168
|
+
*
|
|
169
|
+
* Both parties will derive the same shared key when using their own private key
|
|
170
|
+
* and the other party's public key. This is the core of ECDH key agreement.
|
|
171
|
+
*
|
|
172
|
+
* @param privateKey - Your ECDH private key
|
|
173
|
+
* @param publicKey - The other party's ECDH public key
|
|
174
|
+
* @returns An AES-256-GCM key for encryption/decryption
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* // Both parties derive the same key
|
|
179
|
+
* const sharedKeyA = await deriveSharedKey(privateKeyA, publicKeyB);
|
|
180
|
+
* const sharedKeyB = await deriveSharedKey(privateKeyB, publicKeyA);
|
|
181
|
+
* // sharedKeyA and sharedKeyB are equivalent
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export function deriveSharedKey(privateKey: CryptoKey, publicKey: CryptoKey): Promise<CryptoKey> {
|
|
185
|
+
return crypto.subtle.deriveKey(
|
|
186
|
+
{
|
|
187
|
+
name: 'ECDH',
|
|
188
|
+
public: publicKey,
|
|
189
|
+
},
|
|
190
|
+
privateKey,
|
|
191
|
+
{
|
|
192
|
+
name: 'AES-GCM',
|
|
193
|
+
length: 256,
|
|
194
|
+
},
|
|
195
|
+
true, // extractable - needed for hashing
|
|
196
|
+
['encrypt', 'decrypt'],
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Encrypts data using AES-256-GCM.
|
|
202
|
+
*
|
|
203
|
+
* The data is JSON serialized before encryption. A random 12-byte IV is
|
|
204
|
+
* generated for each encryption operation.
|
|
205
|
+
*
|
|
206
|
+
* AES-GCM provides both confidentiality and authenticity - any tampering
|
|
207
|
+
* with the ciphertext will cause decryption to fail.
|
|
208
|
+
*
|
|
209
|
+
* @param key - The AES-GCM key (from {@link deriveSharedKey})
|
|
210
|
+
* @param data - The data to encrypt (will be JSON serialized)
|
|
211
|
+
* @returns The encrypted payload with IV and ciphertext
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* const encrypted = await encrypt(sharedKey, { action: 'transfer', amount: 100 });
|
|
216
|
+
* // encrypted.iv and encrypted.ciphertext are base64 strings
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export async function encrypt(key: CryptoKey, data: unknown): Promise<EncryptedPayload> {
|
|
220
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
221
|
+
const encoded = new TextEncoder().encode(jsonStringify(data));
|
|
222
|
+
|
|
223
|
+
const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded);
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
iv: arrayBufferToBase64(iv),
|
|
227
|
+
ciphertext: arrayBufferToBase64(ciphertext),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Decrypts data using AES-256-GCM.
|
|
233
|
+
*
|
|
234
|
+
* The decrypted data is JSON parsed before returning.
|
|
235
|
+
*
|
|
236
|
+
* @typeParam T - The expected type of the decrypted data
|
|
237
|
+
* @param key - The AES-GCM key (from {@link deriveSharedKey})
|
|
238
|
+
* @param payload - The encrypted payload from {@link encrypt}
|
|
239
|
+
* @returns The decrypted and parsed data
|
|
240
|
+
*
|
|
241
|
+
* @throws Error if decryption fails (wrong key or tampered ciphertext)
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* const decrypted = await decrypt<{ action: string; amount: number }>(sharedKey, encrypted);
|
|
246
|
+
* console.log(decrypted.action); // 'transfer'
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
export async function decrypt<T = unknown>(key: CryptoKey, payload: EncryptedPayload): Promise<T> {
|
|
250
|
+
const iv = base64ToArrayBuffer(payload.iv);
|
|
251
|
+
const ciphertext = base64ToArrayBuffer(payload.ciphertext);
|
|
252
|
+
|
|
253
|
+
const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);
|
|
254
|
+
|
|
255
|
+
const decoded = new TextDecoder().decode(decrypted);
|
|
256
|
+
return JSON.parse(decoded) as T;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Converts ArrayBuffer to base64 string.
|
|
261
|
+
* @internal
|
|
262
|
+
*/
|
|
263
|
+
function arrayBufferToBase64(buffer: ArrayBuffer | Uint8Array): string {
|
|
264
|
+
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
265
|
+
let binary = '';
|
|
266
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
267
|
+
binary += String.fromCharCode(bytes[i]);
|
|
268
|
+
}
|
|
269
|
+
return btoa(binary);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Converts base64 string to ArrayBuffer.
|
|
274
|
+
* @internal
|
|
275
|
+
*/
|
|
276
|
+
function base64ToArrayBuffer(base64: string): ArrayBuffer {
|
|
277
|
+
const binary = atob(base64);
|
|
278
|
+
const bytes = new Uint8Array(binary.length);
|
|
279
|
+
for (let i = 0; i < binary.length; i++) {
|
|
280
|
+
bytes[i] = binary.charCodeAt(i);
|
|
281
|
+
}
|
|
282
|
+
return bytes.buffer;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Emoji alphabet for visual verification of shared secrets.
|
|
287
|
+
* 32 distinct, easily recognizable emojis for anti-spoofing verification.
|
|
288
|
+
* @internal
|
|
289
|
+
*/
|
|
290
|
+
const EMOJI_ALPHABET = [
|
|
291
|
+
'🔵',
|
|
292
|
+
'🟢',
|
|
293
|
+
'🔴',
|
|
294
|
+
'🟡',
|
|
295
|
+
'🟣',
|
|
296
|
+
'🟠',
|
|
297
|
+
'⚫',
|
|
298
|
+
'⚪',
|
|
299
|
+
'🌟',
|
|
300
|
+
'🌙',
|
|
301
|
+
'☀️',
|
|
302
|
+
'🌈',
|
|
303
|
+
'🔥',
|
|
304
|
+
'💧',
|
|
305
|
+
'🌸',
|
|
306
|
+
'🍀',
|
|
307
|
+
'🦋',
|
|
308
|
+
'🐬',
|
|
309
|
+
'🦊',
|
|
310
|
+
'🐼',
|
|
311
|
+
'🦁',
|
|
312
|
+
'🐯',
|
|
313
|
+
'🐸',
|
|
314
|
+
'🦉',
|
|
315
|
+
'🎵',
|
|
316
|
+
'🎨',
|
|
317
|
+
'🎯',
|
|
318
|
+
'🎲',
|
|
319
|
+
'🔔',
|
|
320
|
+
'💎',
|
|
321
|
+
'🔑',
|
|
322
|
+
'🏆',
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Hashes a shared AES key to a hex string for verification.
|
|
327
|
+
*
|
|
328
|
+
* This extracts the raw key material and hashes it with SHA-256,
|
|
329
|
+
* returning the first 16 bytes as a hex string.
|
|
330
|
+
*
|
|
331
|
+
* @param sharedKey - The AES-GCM shared key (must be extractable)
|
|
332
|
+
* @returns A hex string representation of the hash
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```typescript
|
|
336
|
+
* const hash = await hashSharedSecret(sharedKey);
|
|
337
|
+
* const emoji = hashToEmoji(hash);
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
export async function hashSharedSecret(sharedKey: CryptoKey): Promise<string> {
|
|
341
|
+
const rawKey = await crypto.subtle.exportKey('raw', sharedKey);
|
|
342
|
+
const hash = await crypto.subtle.digest('SHA-256', rawKey);
|
|
343
|
+
const bytes = new Uint8Array(hash.slice(0, 16));
|
|
344
|
+
return Array.from(bytes)
|
|
345
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
346
|
+
.join('');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Converts a hex hash to an emoji sequence for visual verification.
|
|
351
|
+
*
|
|
352
|
+
* This is used for anti-MITM verification - both the dApp and wallet
|
|
353
|
+
* independently compute the same emoji sequence from the shared secret.
|
|
354
|
+
* Users can visually compare the sequences to detect interception.
|
|
355
|
+
*
|
|
356
|
+
* Similar to SAS (Short Authentication String) in ZRTP/Signal.
|
|
357
|
+
*
|
|
358
|
+
* @param hash - Hex string from {@link hashSharedSecret}
|
|
359
|
+
* @param length - Number of emojis to generate (default: 4)
|
|
360
|
+
* @returns A string of emojis representing the hash
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```typescript
|
|
364
|
+
* const hash = await hashSharedSecret(sharedKey);
|
|
365
|
+
* const emoji = hashToEmoji(hash); // e.g., "🔵🦋🎯🐼"
|
|
366
|
+
* // Display to user for verification
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
export function hashToEmoji(hash: string, length: number = 4): string {
|
|
370
|
+
const bytes: number[] = [];
|
|
371
|
+
for (let i = 0; i < hash.length && bytes.length < length; i += 2) {
|
|
372
|
+
bytes.push(parseInt(hash.slice(i, i + 2), 16));
|
|
373
|
+
}
|
|
374
|
+
return bytes.map(b => EMOJI_ALPHABET[b % EMOJI_ALPHABET.length]).join('');
|
|
375
|
+
}
|
package/src/manager/index.ts
CHANGED
|
@@ -5,17 +5,13 @@ export type {
|
|
|
5
5
|
WebWalletConfig,
|
|
6
6
|
WalletProviderType,
|
|
7
7
|
WalletProvider,
|
|
8
|
+
ProviderDisconnectionCallback,
|
|
8
9
|
DiscoverWalletsOptions,
|
|
9
10
|
} from './types.js';
|
|
10
11
|
|
|
11
|
-
// Re-export types from providers for convenience
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
WalletMessage,
|
|
15
|
-
WalletResponse,
|
|
16
|
-
DiscoveryRequest,
|
|
17
|
-
DiscoveryResponse,
|
|
18
|
-
} from '../providers/types.js';
|
|
12
|
+
// Re-export types and enums from providers for convenience
|
|
13
|
+
export { WalletMessageType } from '../types.js';
|
|
14
|
+
export type { WalletInfo, WalletMessage, WalletResponse, DiscoveryRequest, DiscoveryResponse } from '../types.js';
|
|
19
15
|
|
|
20
16
|
// Re-export commonly needed utilities for wallet integration
|
|
21
17
|
export { ChainInfoSchema } from '@aztec/aztec.js/account';
|