noah-avalanche-sdk 0.1.2
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 +892 -0
- package/dist/core/APIClient.d.ts +71 -0
- package/dist/core/APIClient.d.ts.map +1 -0
- package/dist/core/APIClient.js +92 -0
- package/dist/core/APIClient.js.map +1 -0
- package/dist/core/ContractClient.d.ts +38 -0
- package/dist/core/ContractClient.d.ts.map +1 -0
- package/dist/core/ContractClient.js +209 -0
- package/dist/core/ContractClient.js.map +1 -0
- package/dist/core/NoahSDK.d.ts +43 -0
- package/dist/core/NoahSDK.d.ts.map +1 -0
- package/dist/core/NoahSDK.js +93 -0
- package/dist/core/NoahSDK.js.map +1 -0
- package/dist/core/WalletAdapter.d.ts +188 -0
- package/dist/core/WalletAdapter.d.ts.map +1 -0
- package/dist/core/WalletAdapter.js +425 -0
- package/dist/core/WalletAdapter.js.map +1 -0
- package/dist/hooks/index.d.ts +18 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +15 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useCredentials.d.ts +136 -0
- package/dist/hooks/useCredentials.d.ts.map +1 -0
- package/dist/hooks/useCredentials.js +217 -0
- package/dist/hooks/useCredentials.js.map +1 -0
- package/dist/hooks/useProtocol.d.ts +117 -0
- package/dist/hooks/useProtocol.d.ts.map +1 -0
- package/dist/hooks/useProtocol.js +165 -0
- package/dist/hooks/useProtocol.js.map +1 -0
- package/dist/hooks/useUser.d.ts +159 -0
- package/dist/hooks/useUser.d.ts.map +1 -0
- package/dist/hooks/useUser.js +188 -0
- package/dist/hooks/useUser.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/issuer/IssuerClient.d.ts +98 -0
- package/dist/issuer/IssuerClient.d.ts.map +1 -0
- package/dist/issuer/IssuerClient.js +159 -0
- package/dist/issuer/IssuerClient.js.map +1 -0
- package/dist/protocol/ProtocolClient.d.ts +124 -0
- package/dist/protocol/ProtocolClient.d.ts.map +1 -0
- package/dist/protocol/ProtocolClient.js +265 -0
- package/dist/protocol/ProtocolClient.js.map +1 -0
- package/dist/protocol/RequirementsManager.d.ts +9 -0
- package/dist/protocol/RequirementsManager.d.ts.map +1 -0
- package/dist/protocol/RequirementsManager.js +9 -0
- package/dist/protocol/RequirementsManager.js.map +1 -0
- package/dist/user/ProofGenerator.d.ts +49 -0
- package/dist/user/ProofGenerator.d.ts.map +1 -0
- package/dist/user/ProofGenerator.js +80 -0
- package/dist/user/ProofGenerator.js.map +1 -0
- package/dist/user/UserClient.d.ts +191 -0
- package/dist/user/UserClient.d.ts.map +1 -0
- package/dist/user/UserClient.js +338 -0
- package/dist/user/UserClient.js.map +1 -0
- package/dist/utils/credentials.d.ts +47 -0
- package/dist/utils/credentials.d.ts.map +1 -0
- package/dist/utils/credentials.js +99 -0
- package/dist/utils/credentials.js.map +1 -0
- package/dist/utils/identity.d.ts +22 -0
- package/dist/utils/identity.d.ts.map +1 -0
- package/dist/utils/identity.js +35 -0
- package/dist/utils/identity.js.map +1 -0
- package/dist/utils/jurisdiction.d.ts +21 -0
- package/dist/utils/jurisdiction.d.ts.map +1 -0
- package/dist/utils/jurisdiction.js +64 -0
- package/dist/utils/jurisdiction.js.map +1 -0
- package/dist/utils/mrz.d.ts +16 -0
- package/dist/utils/mrz.d.ts.map +1 -0
- package/dist/utils/mrz.js +91 -0
- package/dist/utils/mrz.js.map +1 -0
- package/dist/utils/ocr.d.ts +31 -0
- package/dist/utils/ocr.d.ts.map +1 -0
- package/dist/utils/ocr.js +69 -0
- package/dist/utils/ocr.js.map +1 -0
- package/dist/utils/types.d.ts +122 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +2 -0
- package/dist/utils/types.js.map +1 -0
- package/package.json +53 -0
- package/src/core/APIClient.ts +165 -0
- package/src/core/ContractClient.ts +266 -0
- package/src/core/NoahSDK.ts +123 -0
- package/src/core/WalletAdapter.ts +546 -0
- package/src/hooks/index.ts +31 -0
- package/src/hooks/types.d.ts +18 -0
- package/src/hooks/useCredentials.ts +359 -0
- package/src/hooks/useProtocol.ts +284 -0
- package/src/hooks/useUser.ts +331 -0
- package/src/index.ts +80 -0
- package/src/issuer/IssuerClient.ts +209 -0
- package/src/protocol/ProtocolClient.ts +330 -0
- package/src/protocol/RequirementsManager.ts +16 -0
- package/src/user/ProofGenerator.ts +113 -0
- package/src/user/UserClient.ts +440 -0
- package/src/utils/credentials.ts +122 -0
- package/src/utils/identity.ts +46 -0
- package/src/utils/jurisdiction.ts +83 -0
- package/src/utils/mrz.ts +113 -0
- package/src/utils/ocr.ts +84 -0
- package/src/utils/types.ts +144 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
import { ethers, BrowserProvider } from 'ethers';
|
|
2
|
+
import type {
|
|
3
|
+
Provider,
|
|
4
|
+
Signer,
|
|
5
|
+
Eip1193Provider
|
|
6
|
+
} from 'ethers';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Supported wallet types
|
|
10
|
+
*/
|
|
11
|
+
export type WalletType = 'metamask' | 'walletconnect' | 'injected' | 'custom';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration for wallet adapter
|
|
15
|
+
*/
|
|
16
|
+
export interface WalletAdapterConfig {
|
|
17
|
+
/**
|
|
18
|
+
* Optional RPC URL for fallback provider
|
|
19
|
+
*/
|
|
20
|
+
rpcUrl?: string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Optional chain ID to validate against
|
|
24
|
+
*/
|
|
25
|
+
chainId?: number;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Optional network configuration for switching networks
|
|
29
|
+
*/
|
|
30
|
+
networkConfig?: {
|
|
31
|
+
chainId: number;
|
|
32
|
+
chainName: string;
|
|
33
|
+
nativeCurrency: {
|
|
34
|
+
name: string;
|
|
35
|
+
symbol: string;
|
|
36
|
+
decimals: number;
|
|
37
|
+
};
|
|
38
|
+
rpcUrls: string[];
|
|
39
|
+
blockExplorerUrls?: string[];
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* EIP-6963 Provider Information
|
|
45
|
+
*/
|
|
46
|
+
export interface EIP6963ProviderDetail {
|
|
47
|
+
info: EIP6963ProviderInfo;
|
|
48
|
+
provider: Eip1193Provider;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface EIP6963ProviderInfo {
|
|
52
|
+
rdns: string;
|
|
53
|
+
uuid: string;
|
|
54
|
+
name: string;
|
|
55
|
+
icon: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface EIP6963AnnounceProviderEvent extends CustomEvent {
|
|
59
|
+
detail: EIP6963ProviderDetail;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Wallet connection state
|
|
63
|
+
*/
|
|
64
|
+
export interface WalletState {
|
|
65
|
+
account: string | null;
|
|
66
|
+
chainId: number | null;
|
|
67
|
+
connected: boolean;
|
|
68
|
+
provider: Provider | null;
|
|
69
|
+
signer: Signer | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Wallet adapter for abstracting wallet connections
|
|
74
|
+
* Supports MetaMask, WalletConnect, and any ethers.js-compatible wallet
|
|
75
|
+
*/
|
|
76
|
+
export class WalletAdapter {
|
|
77
|
+
private provider: Provider | null = null;
|
|
78
|
+
private signer: Signer | null = null;
|
|
79
|
+
private account: string | null = null;
|
|
80
|
+
private chainId: number | null = null;
|
|
81
|
+
private walletType: WalletType | null = null;
|
|
82
|
+
private config: WalletAdapterConfig;
|
|
83
|
+
private listeners: Set<(state: WalletState) => void> = new Set();
|
|
84
|
+
private eip1193Provider: Eip1193Provider | null = null;
|
|
85
|
+
private discoveredProviders: EIP6963ProviderDetail[] = [];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Create a new WalletAdapter instance
|
|
89
|
+
* @param config Optional configuration
|
|
90
|
+
*/
|
|
91
|
+
constructor(config: WalletAdapterConfig = {}) {
|
|
92
|
+
this.config = {
|
|
93
|
+
chainId: 43113, // Fuji default
|
|
94
|
+
rpcUrl: 'https://api.avax-test.network/ext/bc/C/rpc',
|
|
95
|
+
...config
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (typeof globalThis !== 'undefined' && (globalThis as any).window) {
|
|
99
|
+
this.discoverWallets();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Discover wallets via EIP-6963
|
|
105
|
+
*/
|
|
106
|
+
private discoverWallets(): void {
|
|
107
|
+
const handler = (event: Event) => {
|
|
108
|
+
const e = event as EIP6963AnnounceProviderEvent;
|
|
109
|
+
if (!this.discoveredProviders.some(p => p.info.uuid === e.detail.info.uuid)) {
|
|
110
|
+
this.discoveredProviders.push(e.detail);
|
|
111
|
+
this.notifyListeners(this.getState());
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const win = (globalThis as any).window;
|
|
116
|
+
if (win) {
|
|
117
|
+
win.addEventListener("eip6963:announceProvider", handler);
|
|
118
|
+
win.dispatchEvent(new Event("eip6963:requestProvider"));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get list of discovered EIP-6963 wallets
|
|
124
|
+
*/
|
|
125
|
+
getDiscoveredWallets(): EIP6963ProviderDetail[] {
|
|
126
|
+
return this.discoveredProviders;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Connect using an EIP-1193 provider (e.g., MetaMask, WalletConnect)
|
|
131
|
+
* @param provider EIP-1193 provider (window.ethereum, WalletConnect provider, etc.)
|
|
132
|
+
* @param walletType Type of wallet being connected
|
|
133
|
+
* @returns Promise resolving to wallet state
|
|
134
|
+
*/
|
|
135
|
+
async connectWithProvider(
|
|
136
|
+
provider: Eip1193Provider,
|
|
137
|
+
walletType: WalletType = 'injected'
|
|
138
|
+
): Promise<WalletState> {
|
|
139
|
+
try {
|
|
140
|
+
this.eip1193Provider = provider;
|
|
141
|
+
this.walletType = walletType;
|
|
142
|
+
|
|
143
|
+
// Request account access
|
|
144
|
+
const accounts = await provider.request({
|
|
145
|
+
method: 'eth_requestAccounts',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
if (!accounts || accounts.length === 0) {
|
|
149
|
+
throw new Error('No accounts found. Please unlock your wallet.');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.account = accounts[0];
|
|
153
|
+
const browserProvider = new BrowserProvider(provider);
|
|
154
|
+
this.provider = browserProvider;
|
|
155
|
+
this.signer = await browserProvider.getSigner();
|
|
156
|
+
|
|
157
|
+
// Get current chain ID
|
|
158
|
+
const network = await this.provider.getNetwork();
|
|
159
|
+
this.chainId = Number(network.chainId);
|
|
160
|
+
|
|
161
|
+
// Validate chain ID if configured
|
|
162
|
+
if (this.config.chainId && this.chainId !== this.config.chainId) {
|
|
163
|
+
if (this.config.networkConfig) {
|
|
164
|
+
await this.switchNetwork();
|
|
165
|
+
} else {
|
|
166
|
+
console.warn(
|
|
167
|
+
`Chain ID mismatch: expected ${this.config.chainId}, got ${this.chainId}`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Set up event listeners
|
|
173
|
+
this.setupEventListeners(provider);
|
|
174
|
+
|
|
175
|
+
const state = this.getState();
|
|
176
|
+
this.notifyListeners(state);
|
|
177
|
+
return state;
|
|
178
|
+
} catch (error) {
|
|
179
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
180
|
+
throw new Error(`Failed to connect wallet: ${message}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Connect using MetaMask (convenience method)
|
|
186
|
+
* @returns Promise resolving to wallet state
|
|
187
|
+
*/
|
|
188
|
+
async connectMetaMask(): Promise<WalletState> {
|
|
189
|
+
if (typeof globalThis === 'undefined' || typeof (globalThis as any).window === 'undefined') {
|
|
190
|
+
throw new Error('MetaMask is only available in browser environments');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const window = (globalThis as any).window;
|
|
194
|
+
const ethereum = window.ethereum;
|
|
195
|
+
if (!ethereum) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
'MetaMask is not installed. Please install MetaMask extension to continue.'
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Check if it's MetaMask specifically
|
|
202
|
+
const isMetaMask = ethereum.isMetaMask === true;
|
|
203
|
+
return this.connectWithProvider(ethereum, isMetaMask ? 'metamask' : 'injected');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Connect using an existing ethers Provider
|
|
208
|
+
* @param provider ethers Provider instance
|
|
209
|
+
* @returns Promise resolving to wallet state
|
|
210
|
+
*/
|
|
211
|
+
async connectWithProviderInstance(provider: Provider): Promise<WalletState> {
|
|
212
|
+
try {
|
|
213
|
+
this.provider = provider;
|
|
214
|
+
this.walletType = 'custom';
|
|
215
|
+
|
|
216
|
+
// Try to get signer if provider is a BrowserProvider
|
|
217
|
+
if (provider instanceof BrowserProvider) {
|
|
218
|
+
try {
|
|
219
|
+
this.signer = await provider.getSigner();
|
|
220
|
+
this.account = await this.signer.getAddress();
|
|
221
|
+
} catch (error) {
|
|
222
|
+
// Provider might not have a signer (read-only)
|
|
223
|
+
console.warn('Provider does not have a signer, read-only mode');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Get current chain ID
|
|
228
|
+
const network = await provider.getNetwork();
|
|
229
|
+
this.chainId = Number(network.chainId);
|
|
230
|
+
|
|
231
|
+
const state = this.getState();
|
|
232
|
+
this.notifyListeners(state);
|
|
233
|
+
return state;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
236
|
+
throw new Error(`Failed to connect with provider: ${message}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Connect using an existing Signer
|
|
242
|
+
* @param signer ethers Signer instance
|
|
243
|
+
* @returns Promise resolving to wallet state
|
|
244
|
+
*/
|
|
245
|
+
async connectWithSigner(signer: Signer): Promise<WalletState> {
|
|
246
|
+
try {
|
|
247
|
+
this.signer = signer;
|
|
248
|
+
this.walletType = 'custom';
|
|
249
|
+
|
|
250
|
+
// Get provider from signer if available
|
|
251
|
+
if (signer.provider) {
|
|
252
|
+
this.provider = signer.provider;
|
|
253
|
+
const network = await signer.provider.getNetwork();
|
|
254
|
+
this.chainId = Number(network.chainId);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Get account address
|
|
258
|
+
this.account = await signer.getAddress();
|
|
259
|
+
|
|
260
|
+
const state = this.getState();
|
|
261
|
+
this.notifyListeners(state);
|
|
262
|
+
return state;
|
|
263
|
+
} catch (error) {
|
|
264
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
265
|
+
throw new Error(`Failed to connect with signer: ${message}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Connect using RPC URL (read-only provider)
|
|
271
|
+
* @param rpcUrl RPC endpoint URL
|
|
272
|
+
* @returns Promise resolving to wallet state
|
|
273
|
+
*/
|
|
274
|
+
async connectWithRpc(rpcUrl: string): Promise<WalletState> {
|
|
275
|
+
try {
|
|
276
|
+
this.provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
277
|
+
this.walletType = 'custom';
|
|
278
|
+
|
|
279
|
+
// Get current chain ID
|
|
280
|
+
const network = await this.provider.getNetwork();
|
|
281
|
+
this.chainId = Number(network.chainId);
|
|
282
|
+
|
|
283
|
+
// No signer for RPC-only connection (read-only)
|
|
284
|
+
this.signer = null;
|
|
285
|
+
this.account = null;
|
|
286
|
+
|
|
287
|
+
const state = this.getState();
|
|
288
|
+
this.notifyListeners(state);
|
|
289
|
+
return state;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
292
|
+
throw new Error(`Failed to connect with RPC: ${message}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Switch to configured network
|
|
298
|
+
* @returns Promise that resolves when network is switched
|
|
299
|
+
*/
|
|
300
|
+
async switchNetwork(): Promise<void> {
|
|
301
|
+
if (!this.config.networkConfig) {
|
|
302
|
+
throw new Error('Network configuration not provided');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (!this.eip1193Provider) {
|
|
306
|
+
throw new Error('Network switching requires an EIP-1193 provider');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const { chainId, chainName, nativeCurrency, rpcUrls, blockExplorerUrls } =
|
|
310
|
+
this.config.networkConfig;
|
|
311
|
+
const chainIdHex = `0x${chainId.toString(16)}`;
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
// Try to switch directly
|
|
315
|
+
await this.eip1193Provider.request({
|
|
316
|
+
method: 'wallet_switchEthereumChain',
|
|
317
|
+
params: [{ chainId: chainIdHex }],
|
|
318
|
+
});
|
|
319
|
+
return;
|
|
320
|
+
} catch (switchError: any) {
|
|
321
|
+
// User rejected
|
|
322
|
+
if (switchError.code === 4001) {
|
|
323
|
+
throw new Error(
|
|
324
|
+
'User rejected network switch. Please switch manually in your wallet.'
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Chain doesn't exist, add it
|
|
329
|
+
if (switchError.code === 4902) {
|
|
330
|
+
try {
|
|
331
|
+
await this.eip1193Provider.request({
|
|
332
|
+
method: 'wallet_addEthereumChain',
|
|
333
|
+
params: [
|
|
334
|
+
{
|
|
335
|
+
chainId: chainIdHex,
|
|
336
|
+
chainName,
|
|
337
|
+
nativeCurrency,
|
|
338
|
+
rpcUrls: Array.isArray(rpcUrls) ? rpcUrls : [rpcUrls],
|
|
339
|
+
blockExplorerUrls: blockExplorerUrls
|
|
340
|
+
? Array.isArray(blockExplorerUrls)
|
|
341
|
+
? blockExplorerUrls
|
|
342
|
+
: [blockExplorerUrls]
|
|
343
|
+
: undefined,
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Retry switch after adding
|
|
349
|
+
await this.eip1193Provider.request({
|
|
350
|
+
method: 'wallet_switchEthereumChain',
|
|
351
|
+
params: [{ chainId: chainIdHex }],
|
|
352
|
+
});
|
|
353
|
+
return;
|
|
354
|
+
} catch (addError: any) {
|
|
355
|
+
throw new Error(`Failed to add network: ${addError.message}`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
throw new Error(`Failed to switch network: ${switchError.message}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Disconnect wallet
|
|
365
|
+
*/
|
|
366
|
+
disconnect(): void {
|
|
367
|
+
this.removeEventListeners();
|
|
368
|
+
this.provider = null;
|
|
369
|
+
this.signer = null;
|
|
370
|
+
this.account = null;
|
|
371
|
+
this.chainId = null;
|
|
372
|
+
this.walletType = null;
|
|
373
|
+
this.eip1193Provider = null;
|
|
374
|
+
|
|
375
|
+
const state = this.getState();
|
|
376
|
+
this.notifyListeners(state);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Get current wallet state
|
|
381
|
+
* @returns Current wallet state
|
|
382
|
+
*/
|
|
383
|
+
getState(): WalletState {
|
|
384
|
+
return {
|
|
385
|
+
account: this.account,
|
|
386
|
+
chainId: this.chainId,
|
|
387
|
+
connected: this.account !== null && this.provider !== null,
|
|
388
|
+
provider: this.provider,
|
|
389
|
+
signer: this.signer,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get current provider
|
|
395
|
+
* @returns Current provider or null
|
|
396
|
+
*/
|
|
397
|
+
getProvider(): Provider | null {
|
|
398
|
+
return this.provider;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Get current signer
|
|
403
|
+
* @returns Current signer or null
|
|
404
|
+
*/
|
|
405
|
+
getSigner(): Signer | null {
|
|
406
|
+
return this.signer;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Get current account address
|
|
411
|
+
* @returns Current account address or null
|
|
412
|
+
*/
|
|
413
|
+
getAccount(): string | null {
|
|
414
|
+
return this.account;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Get current chain ID
|
|
419
|
+
* @returns Current chain ID or null
|
|
420
|
+
*/
|
|
421
|
+
getChainId(): number | null {
|
|
422
|
+
return this.chainId;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Get wallet type
|
|
427
|
+
* @returns Wallet type or null
|
|
428
|
+
*/
|
|
429
|
+
getWalletType(): WalletType | null {
|
|
430
|
+
return this.walletType;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Check if wallet is connected
|
|
435
|
+
* @returns True if wallet is connected
|
|
436
|
+
*/
|
|
437
|
+
isConnected(): boolean {
|
|
438
|
+
return this.account !== null && this.provider !== null;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Subscribe to wallet state changes
|
|
443
|
+
* @param callback Callback function to receive state updates
|
|
444
|
+
* @returns Unsubscribe function
|
|
445
|
+
*/
|
|
446
|
+
onStateChange(callback: (state: WalletState) => void): () => void {
|
|
447
|
+
this.listeners.add(callback);
|
|
448
|
+
return () => {
|
|
449
|
+
this.listeners.delete(callback);
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Notify all listeners of state changes
|
|
455
|
+
* @param state New wallet state
|
|
456
|
+
*/
|
|
457
|
+
private notifyListeners(state: WalletState): void {
|
|
458
|
+
this.listeners.forEach((callback) => {
|
|
459
|
+
try {
|
|
460
|
+
callback(state);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
console.error('Error in wallet state listener:', error);
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Set up event listeners for EIP-1193 provider
|
|
469
|
+
* @param provider EIP-1193 provider
|
|
470
|
+
*/
|
|
471
|
+
private setupEventListeners(provider: Eip1193Provider & { on?: (event: string, handler: (...args: any[]) => void) => void }): void {
|
|
472
|
+
this.removeEventListeners();
|
|
473
|
+
|
|
474
|
+
if (!provider.on) {
|
|
475
|
+
console.warn('Provider does not support event listeners');
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Handle account changes
|
|
480
|
+
provider.on('accountsChanged', async (accounts: string[]) => {
|
|
481
|
+
if (accounts.length === 0) {
|
|
482
|
+
this.disconnect();
|
|
483
|
+
} else {
|
|
484
|
+
this.account = accounts[0];
|
|
485
|
+
if (this.provider instanceof BrowserProvider) {
|
|
486
|
+
this.signer = await this.provider.getSigner();
|
|
487
|
+
}
|
|
488
|
+
const state = this.getState();
|
|
489
|
+
this.notifyListeners(state);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
// Handle chain changes
|
|
494
|
+
provider.on('chainChanged', async (chainId: string) => {
|
|
495
|
+
this.chainId = parseInt(chainId, 16);
|
|
496
|
+
if (this.provider instanceof BrowserProvider) {
|
|
497
|
+
this.signer = await this.provider.getSigner();
|
|
498
|
+
}
|
|
499
|
+
const state = this.getState();
|
|
500
|
+
this.notifyListeners(state);
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// Handle disconnect
|
|
504
|
+
provider.on('disconnect', () => {
|
|
505
|
+
this.disconnect();
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Remove event listeners
|
|
511
|
+
*/
|
|
512
|
+
private removeEventListeners(): void {
|
|
513
|
+
if (this.eip1193Provider && 'removeAllListeners' in this.eip1193Provider) {
|
|
514
|
+
try {
|
|
515
|
+
(this.eip1193Provider as any).removeAllListeners('accountsChanged');
|
|
516
|
+
(this.eip1193Provider as any).removeAllListeners('chainChanged');
|
|
517
|
+
(this.eip1193Provider as any).removeAllListeners('disconnect');
|
|
518
|
+
} catch (error) {
|
|
519
|
+
// Some providers might not support removeAllListeners
|
|
520
|
+
console.warn('Failed to remove event listeners:', error);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Check if MetaMask is installed
|
|
528
|
+
* @returns True if MetaMask is available
|
|
529
|
+
*/
|
|
530
|
+
export function isMetaMaskInstalled(): boolean {
|
|
531
|
+
if (typeof globalThis === 'undefined' || typeof (globalThis as any).window === 'undefined') return false;
|
|
532
|
+
const window = (globalThis as any).window;
|
|
533
|
+
const ethereum = window.ethereum;
|
|
534
|
+
return ethereum?.isMetaMask === true;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Get MetaMask provider if available
|
|
539
|
+
* @returns MetaMask provider or null
|
|
540
|
+
*/
|
|
541
|
+
export function getMetaMaskProvider(): Eip1193Provider | null {
|
|
542
|
+
if (typeof globalThis === 'undefined' || typeof (globalThis as any).window === 'undefined') return null;
|
|
543
|
+
const window = (globalThis as any).window;
|
|
544
|
+
const ethereum = window.ethereum;
|
|
545
|
+
return ethereum?.isMetaMask ? ethereum : null;
|
|
546
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React hooks for NOAH SDK
|
|
3
|
+
*
|
|
4
|
+
* These hooks provide React integration for the NOAH SDK, making it easy
|
|
5
|
+
* to use NOAH functionality in React applications.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { useProtocol, useUser, useCredentials } from '@noah-protocol/sdk/hooks';
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export { useProtocol } from './useProtocol';
|
|
14
|
+
export type { UseProtocolOptions, UseProtocolReturn } from './useProtocol';
|
|
15
|
+
|
|
16
|
+
export { useUser } from './useUser';
|
|
17
|
+
export type { UseUserOptions, UseUserReturn, Credential } from './useUser';
|
|
18
|
+
|
|
19
|
+
export { useCredentials } from './useCredentials';
|
|
20
|
+
export type {
|
|
21
|
+
UseCredentialsOptions,
|
|
22
|
+
UseCredentialsReturn,
|
|
23
|
+
CredentialInfo,
|
|
24
|
+
IssuerInfo,
|
|
25
|
+
} from './useCredentials';
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for optional peer dependencies
|
|
3
|
+
* These allow the hooks to compile even if React/React Query are not installed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare module '@tanstack/react-query' {
|
|
7
|
+
export function useQuery<T>(options: any): any;
|
|
8
|
+
export function useMutation<T>(options: any): any;
|
|
9
|
+
export function useQueryClient(): any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare module 'react' {
|
|
13
|
+
export function useMemo<T>(factory: () => T, deps: any[]): T;
|
|
14
|
+
export function useState<T>(initial: T): [T, (value: T) => void];
|
|
15
|
+
export function useEffect(effect: () => void | (() => void), deps?: any[]): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|