@sip-protocol/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.mts +3640 -0
- package/dist/index.d.ts +3640 -0
- package/dist/index.js +5725 -0
- package/dist/index.mjs +5606 -0
- package/package.json +61 -0
- package/src/adapters/index.ts +19 -0
- package/src/adapters/near-intents.ts +475 -0
- package/src/adapters/oneclick-client.ts +367 -0
- package/src/commitment.ts +470 -0
- package/src/crypto.ts +93 -0
- package/src/errors.ts +471 -0
- package/src/index.ts +369 -0
- package/src/intent.ts +488 -0
- package/src/privacy.ts +382 -0
- package/src/proofs/index.ts +52 -0
- package/src/proofs/interface.ts +228 -0
- package/src/proofs/mock.ts +258 -0
- package/src/proofs/noir.ts +233 -0
- package/src/sip.ts +299 -0
- package/src/solver/index.ts +25 -0
- package/src/solver/mock-solver.ts +278 -0
- package/src/stealth.ts +414 -0
- package/src/validation.ts +401 -0
- package/src/wallet/base-adapter.ts +407 -0
- package/src/wallet/errors.ts +106 -0
- package/src/wallet/ethereum/adapter.ts +655 -0
- package/src/wallet/ethereum/index.ts +48 -0
- package/src/wallet/ethereum/mock.ts +505 -0
- package/src/wallet/ethereum/types.ts +364 -0
- package/src/wallet/index.ts +116 -0
- package/src/wallet/registry.ts +207 -0
- package/src/wallet/solana/adapter.ts +533 -0
- package/src/wallet/solana/index.ts +40 -0
- package/src/wallet/solana/mock.ts +522 -0
- package/src/wallet/solana/types.ts +253 -0
- package/src/zcash/index.ts +53 -0
- package/src/zcash/rpc-client.ts +623 -0
- package/src/zcash/shielded-service.ts +641 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ethereum Wallet Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for Ethereum wallet integration.
|
|
5
|
+
* Follows EIP-1193 (Provider API) and EIP-712 (Typed Data Signing).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { HexString } from '@sip-protocol/types'
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// EIP-1193 Provider Types
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* EIP-1193 Provider interface
|
|
16
|
+
* Standard interface for Ethereum providers (MetaMask, etc.)
|
|
17
|
+
*/
|
|
18
|
+
export interface EIP1193Provider {
|
|
19
|
+
/** Make an Ethereum JSON-RPC request */
|
|
20
|
+
request<T = unknown>(args: EIP1193RequestArguments): Promise<T>
|
|
21
|
+
/** Event emitter for provider events */
|
|
22
|
+
on(event: string, handler: (...args: unknown[]) => void): void
|
|
23
|
+
removeListener(event: string, handler: (...args: unknown[]) => void): void
|
|
24
|
+
/** Provider is MetaMask */
|
|
25
|
+
isMetaMask?: boolean
|
|
26
|
+
/** Provider is Coinbase Wallet */
|
|
27
|
+
isCoinbaseWallet?: boolean
|
|
28
|
+
/** Selected address (may be undefined before connection) */
|
|
29
|
+
selectedAddress?: string | null
|
|
30
|
+
/** Chain ID in hex format */
|
|
31
|
+
chainId?: string
|
|
32
|
+
/** Whether provider is connected */
|
|
33
|
+
isConnected?(): boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* EIP-1193 Request arguments
|
|
38
|
+
*/
|
|
39
|
+
export interface EIP1193RequestArguments {
|
|
40
|
+
method: string
|
|
41
|
+
params?: unknown[] | Record<string, unknown>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* EIP-1193 Provider events
|
|
46
|
+
*/
|
|
47
|
+
export type EIP1193Event =
|
|
48
|
+
| 'connect'
|
|
49
|
+
| 'disconnect'
|
|
50
|
+
| 'chainChanged'
|
|
51
|
+
| 'accountsChanged'
|
|
52
|
+
| 'message'
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* EIP-1193 Connect info
|
|
56
|
+
*/
|
|
57
|
+
export interface EIP1193ConnectInfo {
|
|
58
|
+
chainId: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* EIP-1193 Provider RPC error
|
|
63
|
+
*/
|
|
64
|
+
export interface EIP1193ProviderRpcError extends Error {
|
|
65
|
+
code: number
|
|
66
|
+
data?: unknown
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// EIP-712 Typed Data Types
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* EIP-712 Typed data domain
|
|
75
|
+
*/
|
|
76
|
+
export interface EIP712Domain {
|
|
77
|
+
name?: string
|
|
78
|
+
version?: string
|
|
79
|
+
chainId?: number
|
|
80
|
+
verifyingContract?: string
|
|
81
|
+
salt?: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* EIP-712 Type definition
|
|
86
|
+
*/
|
|
87
|
+
export interface EIP712TypeDefinition {
|
|
88
|
+
name: string
|
|
89
|
+
type: string
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* EIP-712 Types object
|
|
94
|
+
*/
|
|
95
|
+
export interface EIP712Types {
|
|
96
|
+
EIP712Domain?: EIP712TypeDefinition[]
|
|
97
|
+
[key: string]: EIP712TypeDefinition[] | undefined
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* EIP-712 Typed data for signing
|
|
102
|
+
*/
|
|
103
|
+
export interface EIP712TypedData {
|
|
104
|
+
domain: EIP712Domain
|
|
105
|
+
types: EIP712Types
|
|
106
|
+
primaryType: string
|
|
107
|
+
message: Record<string, unknown>
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Transaction Types
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Ethereum transaction request
|
|
116
|
+
*/
|
|
117
|
+
export interface EthereumTransactionRequest {
|
|
118
|
+
/** Sender address */
|
|
119
|
+
from?: string
|
|
120
|
+
/** Recipient address */
|
|
121
|
+
to?: string
|
|
122
|
+
/** Value in wei (hex) */
|
|
123
|
+
value?: string
|
|
124
|
+
/** Transaction data (hex) */
|
|
125
|
+
data?: string
|
|
126
|
+
/** Gas limit (hex) */
|
|
127
|
+
gas?: string
|
|
128
|
+
/** Gas price (hex) - legacy */
|
|
129
|
+
gasPrice?: string
|
|
130
|
+
/** Max fee per gas (hex) - EIP-1559 */
|
|
131
|
+
maxFeePerGas?: string
|
|
132
|
+
/** Max priority fee per gas (hex) - EIP-1559 */
|
|
133
|
+
maxPriorityFeePerGas?: string
|
|
134
|
+
/** Nonce (hex) */
|
|
135
|
+
nonce?: string
|
|
136
|
+
/** Chain ID */
|
|
137
|
+
chainId?: number
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Ethereum transaction receipt
|
|
142
|
+
*/
|
|
143
|
+
export interface EthereumTransactionReceipt {
|
|
144
|
+
/** Transaction hash */
|
|
145
|
+
transactionHash: string
|
|
146
|
+
/** Block number */
|
|
147
|
+
blockNumber: string
|
|
148
|
+
/** Block hash */
|
|
149
|
+
blockHash: string
|
|
150
|
+
/** Sender address */
|
|
151
|
+
from: string
|
|
152
|
+
/** Recipient address */
|
|
153
|
+
to: string | null
|
|
154
|
+
/** Gas used */
|
|
155
|
+
gasUsed: string
|
|
156
|
+
/** Effective gas price */
|
|
157
|
+
effectiveGasPrice: string
|
|
158
|
+
/** Status (1 = success, 0 = failure) */
|
|
159
|
+
status: string
|
|
160
|
+
/** Contract address (if deployment) */
|
|
161
|
+
contractAddress: string | null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// Token Types (ERC-20)
|
|
166
|
+
// ============================================================================
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Token metadata for wallet_watchAsset
|
|
170
|
+
*/
|
|
171
|
+
export interface EthereumTokenMetadata {
|
|
172
|
+
/** Token contract address */
|
|
173
|
+
address: string
|
|
174
|
+
/** Token symbol */
|
|
175
|
+
symbol: string
|
|
176
|
+
/** Token decimals */
|
|
177
|
+
decimals: number
|
|
178
|
+
/** Token image URL (optional) */
|
|
179
|
+
image?: string
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// Chain Types
|
|
184
|
+
// ============================================================================
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Common Ethereum chain IDs
|
|
188
|
+
*/
|
|
189
|
+
export const EthereumChainId = {
|
|
190
|
+
MAINNET: 1,
|
|
191
|
+
GOERLI: 5,
|
|
192
|
+
SEPOLIA: 11155111,
|
|
193
|
+
POLYGON: 137,
|
|
194
|
+
POLYGON_MUMBAI: 80001,
|
|
195
|
+
ARBITRUM: 42161,
|
|
196
|
+
ARBITRUM_GOERLI: 421613,
|
|
197
|
+
OPTIMISM: 10,
|
|
198
|
+
OPTIMISM_GOERLI: 420,
|
|
199
|
+
BASE: 8453,
|
|
200
|
+
BASE_GOERLI: 84531,
|
|
201
|
+
LOCALHOST: 1337,
|
|
202
|
+
} as const
|
|
203
|
+
|
|
204
|
+
export type EthereumChainIdType = (typeof EthereumChainId)[keyof typeof EthereumChainId]
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Chain metadata for wallet_addEthereumChain
|
|
208
|
+
*/
|
|
209
|
+
export interface EthereumChainMetadata {
|
|
210
|
+
chainId: string // hex
|
|
211
|
+
chainName: string
|
|
212
|
+
nativeCurrency: {
|
|
213
|
+
name: string
|
|
214
|
+
symbol: string
|
|
215
|
+
decimals: number
|
|
216
|
+
}
|
|
217
|
+
rpcUrls: string[]
|
|
218
|
+
blockExplorerUrls?: string[]
|
|
219
|
+
iconUrls?: string[]
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Ethereum wallet name/type
|
|
224
|
+
*/
|
|
225
|
+
export type EthereumWalletName = 'metamask' | 'coinbase' | 'walletconnect' | 'generic'
|
|
226
|
+
|
|
227
|
+
// ============================================================================
|
|
228
|
+
// Adapter Configuration
|
|
229
|
+
// ============================================================================
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Ethereum adapter configuration
|
|
233
|
+
*/
|
|
234
|
+
export interface EthereumAdapterConfig {
|
|
235
|
+
/** Wallet to connect to */
|
|
236
|
+
wallet?: EthereumWalletName
|
|
237
|
+
/** Target chain ID */
|
|
238
|
+
chainId?: number
|
|
239
|
+
/** RPC endpoint URL (for balance queries) */
|
|
240
|
+
rpcEndpoint?: string
|
|
241
|
+
/** Custom provider (for testing) */
|
|
242
|
+
provider?: EIP1193Provider
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ============================================================================
|
|
246
|
+
// Provider Detection & Utilities
|
|
247
|
+
// ============================================================================
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get the injected Ethereum provider
|
|
251
|
+
*/
|
|
252
|
+
export function getEthereumProvider(
|
|
253
|
+
wallet: EthereumWalletName = 'metamask'
|
|
254
|
+
): EIP1193Provider | undefined {
|
|
255
|
+
if (typeof window === 'undefined') return undefined
|
|
256
|
+
|
|
257
|
+
const win = window as unknown as {
|
|
258
|
+
ethereum?: EIP1193Provider & {
|
|
259
|
+
providers?: EIP1193Provider[]
|
|
260
|
+
}
|
|
261
|
+
coinbaseWalletExtension?: EIP1193Provider
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Handle multiple injected providers
|
|
265
|
+
if (win.ethereum?.providers?.length) {
|
|
266
|
+
switch (wallet) {
|
|
267
|
+
case 'metamask':
|
|
268
|
+
return win.ethereum.providers.find((p) => p.isMetaMask)
|
|
269
|
+
case 'coinbase':
|
|
270
|
+
return win.ethereum.providers.find((p) => p.isCoinbaseWallet)
|
|
271
|
+
default:
|
|
272
|
+
return win.ethereum.providers[0]
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
switch (wallet) {
|
|
277
|
+
case 'metamask':
|
|
278
|
+
return win.ethereum?.isMetaMask ? win.ethereum : undefined
|
|
279
|
+
case 'coinbase':
|
|
280
|
+
return win.coinbaseWalletExtension ?? (win.ethereum?.isCoinbaseWallet ? win.ethereum : undefined)
|
|
281
|
+
case 'generic':
|
|
282
|
+
default:
|
|
283
|
+
return win.ethereum
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Detect which Ethereum wallets are installed
|
|
289
|
+
*/
|
|
290
|
+
export function detectEthereumWallets(): EthereumWalletName[] {
|
|
291
|
+
if (typeof window === 'undefined') return []
|
|
292
|
+
|
|
293
|
+
const detected: EthereumWalletName[] = []
|
|
294
|
+
const win = window as unknown as {
|
|
295
|
+
ethereum?: EIP1193Provider & { providers?: EIP1193Provider[] }
|
|
296
|
+
coinbaseWalletExtension?: EIP1193Provider
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (win.ethereum?.providers?.length) {
|
|
300
|
+
if (win.ethereum.providers.some((p) => p.isMetaMask)) detected.push('metamask')
|
|
301
|
+
if (win.ethereum.providers.some((p) => p.isCoinbaseWallet)) detected.push('coinbase')
|
|
302
|
+
} else {
|
|
303
|
+
if (win.ethereum?.isMetaMask) detected.push('metamask')
|
|
304
|
+
if (win.ethereum?.isCoinbaseWallet || win.coinbaseWalletExtension) detected.push('coinbase')
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (win.ethereum && detected.length === 0) {
|
|
308
|
+
detected.push('generic')
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return detected
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Convert number to hex string with 0x prefix
|
|
316
|
+
*/
|
|
317
|
+
export function toHex(value: number | bigint): HexString {
|
|
318
|
+
return `0x${value.toString(16)}` as HexString
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Convert hex string to bigint
|
|
323
|
+
*/
|
|
324
|
+
export function fromHex(hex: string): bigint {
|
|
325
|
+
return BigInt(hex)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Convert hex string to number
|
|
330
|
+
*/
|
|
331
|
+
export function hexToNumber(hex: string): number {
|
|
332
|
+
return Number(BigInt(hex))
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Pad address to checksum format
|
|
337
|
+
*/
|
|
338
|
+
export function normalizeAddress(address: string): HexString {
|
|
339
|
+
return address.toLowerCase() as HexString
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Get default RPC endpoint for chain
|
|
344
|
+
*/
|
|
345
|
+
export function getDefaultRpcEndpoint(chainId: number): string {
|
|
346
|
+
switch (chainId) {
|
|
347
|
+
case EthereumChainId.MAINNET:
|
|
348
|
+
return 'https://eth.llamarpc.com'
|
|
349
|
+
case EthereumChainId.GOERLI:
|
|
350
|
+
return 'https://rpc.ankr.com/eth_goerli'
|
|
351
|
+
case EthereumChainId.SEPOLIA:
|
|
352
|
+
return 'https://rpc.sepolia.org'
|
|
353
|
+
case EthereumChainId.POLYGON:
|
|
354
|
+
return 'https://polygon-rpc.com'
|
|
355
|
+
case EthereumChainId.ARBITRUM:
|
|
356
|
+
return 'https://arb1.arbitrum.io/rpc'
|
|
357
|
+
case EthereumChainId.OPTIMISM:
|
|
358
|
+
return 'https://mainnet.optimism.io'
|
|
359
|
+
case EthereumChainId.BASE:
|
|
360
|
+
return 'https://mainnet.base.org'
|
|
361
|
+
default:
|
|
362
|
+
return 'http://localhost:8545'
|
|
363
|
+
}
|
|
364
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet Module
|
|
3
|
+
*
|
|
4
|
+
* Chain-agnostic wallet adapter interface for SIP Protocol.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Base adapter class
|
|
8
|
+
export { BaseWalletAdapter, MockWalletAdapter } from './base-adapter'
|
|
9
|
+
|
|
10
|
+
// Wallet errors
|
|
11
|
+
export { WalletError, notConnectedError, featureNotSupportedError } from './errors'
|
|
12
|
+
|
|
13
|
+
// Registry
|
|
14
|
+
export {
|
|
15
|
+
walletRegistry,
|
|
16
|
+
registerWallet,
|
|
17
|
+
createWalletFactory,
|
|
18
|
+
isPrivateWalletAdapter,
|
|
19
|
+
} from './registry'
|
|
20
|
+
|
|
21
|
+
// Solana adapter
|
|
22
|
+
export {
|
|
23
|
+
SolanaWalletAdapter,
|
|
24
|
+
createSolanaAdapter,
|
|
25
|
+
MockSolanaAdapter,
|
|
26
|
+
createMockSolanaAdapter,
|
|
27
|
+
createMockSolanaProvider,
|
|
28
|
+
createMockSolanaConnection,
|
|
29
|
+
getSolanaProvider,
|
|
30
|
+
detectSolanaWallets,
|
|
31
|
+
solanaPublicKeyToHex,
|
|
32
|
+
base58ToHex,
|
|
33
|
+
} from './solana'
|
|
34
|
+
|
|
35
|
+
export type {
|
|
36
|
+
SolanaPublicKey,
|
|
37
|
+
SolanaTransaction,
|
|
38
|
+
SolanaVersionedTransaction,
|
|
39
|
+
SolanaWalletProvider,
|
|
40
|
+
SolanaWalletName,
|
|
41
|
+
SolanaCluster,
|
|
42
|
+
SolanaAdapterConfig,
|
|
43
|
+
SolanaConnection,
|
|
44
|
+
SolanaSendOptions,
|
|
45
|
+
SolanaUnsignedTransaction,
|
|
46
|
+
SolanaSignature,
|
|
47
|
+
MockSolanaAdapterConfig,
|
|
48
|
+
} from './solana'
|
|
49
|
+
|
|
50
|
+
// Ethereum adapter
|
|
51
|
+
export {
|
|
52
|
+
EthereumWalletAdapter,
|
|
53
|
+
createEthereumAdapter,
|
|
54
|
+
MockEthereumAdapter,
|
|
55
|
+
createMockEthereumAdapter,
|
|
56
|
+
createMockEthereumProvider,
|
|
57
|
+
getEthereumProvider,
|
|
58
|
+
detectEthereumWallets,
|
|
59
|
+
toHex,
|
|
60
|
+
fromHex,
|
|
61
|
+
hexToNumber,
|
|
62
|
+
normalizeAddress,
|
|
63
|
+
getDefaultRpcEndpoint,
|
|
64
|
+
EthereumChainId,
|
|
65
|
+
} from './ethereum'
|
|
66
|
+
|
|
67
|
+
export type {
|
|
68
|
+
EIP1193Provider,
|
|
69
|
+
EIP1193RequestArguments,
|
|
70
|
+
EIP1193Event,
|
|
71
|
+
EIP1193ConnectInfo,
|
|
72
|
+
EIP1193ProviderRpcError,
|
|
73
|
+
EIP712Domain,
|
|
74
|
+
EIP712TypeDefinition,
|
|
75
|
+
EIP712Types,
|
|
76
|
+
EIP712TypedData,
|
|
77
|
+
EthereumTransactionRequest,
|
|
78
|
+
EthereumTransactionReceipt,
|
|
79
|
+
EthereumTokenMetadata,
|
|
80
|
+
EthereumChainMetadata,
|
|
81
|
+
EthereumWalletName,
|
|
82
|
+
EthereumAdapterConfig,
|
|
83
|
+
EthereumChainIdType,
|
|
84
|
+
MockEthereumAdapterConfig,
|
|
85
|
+
} from './ethereum'
|
|
86
|
+
|
|
87
|
+
// Re-export types from types package for convenience
|
|
88
|
+
export type {
|
|
89
|
+
// Core types
|
|
90
|
+
WalletConnectionState,
|
|
91
|
+
Signature,
|
|
92
|
+
UnsignedTransaction,
|
|
93
|
+
SignedTransaction,
|
|
94
|
+
TransactionReceipt,
|
|
95
|
+
// Events
|
|
96
|
+
WalletEventType,
|
|
97
|
+
WalletEvent,
|
|
98
|
+
WalletEventHandler,
|
|
99
|
+
WalletConnectEvent,
|
|
100
|
+
WalletDisconnectEvent,
|
|
101
|
+
WalletAccountChangedEvent,
|
|
102
|
+
WalletChainChangedEvent,
|
|
103
|
+
WalletErrorEvent,
|
|
104
|
+
// Adapter interfaces
|
|
105
|
+
WalletAdapter,
|
|
106
|
+
PrivateWalletAdapter,
|
|
107
|
+
// Privacy types
|
|
108
|
+
WalletShieldedSendParams,
|
|
109
|
+
WalletShieldedSendResult,
|
|
110
|
+
// Registry types
|
|
111
|
+
WalletInfo,
|
|
112
|
+
WalletAdapterFactory,
|
|
113
|
+
WalletRegistryEntry,
|
|
114
|
+
} from '@sip-protocol/types'
|
|
115
|
+
|
|
116
|
+
export { WalletErrorCode } from '@sip-protocol/types'
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages wallet adapter registration and discovery.
|
|
5
|
+
* Allows applications to register and detect available wallets.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
ChainId,
|
|
10
|
+
WalletAdapter,
|
|
11
|
+
PrivateWalletAdapter,
|
|
12
|
+
WalletInfo,
|
|
13
|
+
WalletRegistryEntry,
|
|
14
|
+
WalletAdapterFactory,
|
|
15
|
+
} from '@sip-protocol/types'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Global wallet registry
|
|
19
|
+
*
|
|
20
|
+
* Manages available wallet adapters and provides discovery functionality.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Register a wallet adapter
|
|
25
|
+
* walletRegistry.register({
|
|
26
|
+
* info: {
|
|
27
|
+
* id: 'phantom',
|
|
28
|
+
* name: 'Phantom',
|
|
29
|
+
* chains: ['solana'],
|
|
30
|
+
* supportsPrivacy: false,
|
|
31
|
+
* },
|
|
32
|
+
* factory: () => new PhantomWalletAdapter(),
|
|
33
|
+
* detect: () => typeof window !== 'undefined' && 'phantom' in window,
|
|
34
|
+
* })
|
|
35
|
+
*
|
|
36
|
+
* // Get available wallets for a chain
|
|
37
|
+
* const solanaWallets = walletRegistry.getAvailableWallets('solana')
|
|
38
|
+
*
|
|
39
|
+
* // Create a wallet adapter
|
|
40
|
+
* const wallet = walletRegistry.create('phantom')
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
class WalletRegistry {
|
|
44
|
+
private entries: Map<string, WalletRegistryEntry> = new Map()
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Register a wallet adapter
|
|
48
|
+
*
|
|
49
|
+
* @param entry - The wallet registry entry
|
|
50
|
+
*/
|
|
51
|
+
register(entry: WalletRegistryEntry): void {
|
|
52
|
+
this.entries.set(entry.info.id, entry)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Unregister a wallet adapter
|
|
57
|
+
*
|
|
58
|
+
* @param id - The wallet identifier
|
|
59
|
+
*/
|
|
60
|
+
unregister(id: string): void {
|
|
61
|
+
this.entries.delete(id)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get wallet info by ID
|
|
66
|
+
*
|
|
67
|
+
* @param id - The wallet identifier
|
|
68
|
+
* @returns The wallet info or undefined
|
|
69
|
+
*/
|
|
70
|
+
getInfo(id: string): WalletInfo | undefined {
|
|
71
|
+
return this.entries.get(id)?.info
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get all registered wallet infos
|
|
76
|
+
*
|
|
77
|
+
* @returns Array of all wallet infos
|
|
78
|
+
*/
|
|
79
|
+
getAllWallets(): WalletInfo[] {
|
|
80
|
+
return Array.from(this.entries.values()).map((entry) => entry.info)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get wallets that support a specific chain
|
|
85
|
+
*
|
|
86
|
+
* @param chain - The chain to filter by
|
|
87
|
+
* @returns Array of wallet infos that support the chain
|
|
88
|
+
*/
|
|
89
|
+
getWalletsForChain(chain: ChainId): WalletInfo[] {
|
|
90
|
+
return Array.from(this.entries.values())
|
|
91
|
+
.filter((entry) => entry.info.chains.includes(chain))
|
|
92
|
+
.map((entry) => entry.info)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get available (detected) wallets
|
|
97
|
+
*
|
|
98
|
+
* @param chain - Optional chain to filter by
|
|
99
|
+
* @returns Array of wallet infos for detected wallets
|
|
100
|
+
*/
|
|
101
|
+
getAvailableWallets(chain?: ChainId): WalletInfo[] {
|
|
102
|
+
return Array.from(this.entries.values())
|
|
103
|
+
.filter((entry) => {
|
|
104
|
+
// Check if detected
|
|
105
|
+
if (!entry.detect()) return false
|
|
106
|
+
// Check chain if specified
|
|
107
|
+
if (chain && !entry.info.chains.includes(chain)) return false
|
|
108
|
+
return true
|
|
109
|
+
})
|
|
110
|
+
.map((entry) => entry.info)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get wallets that support privacy features
|
|
115
|
+
*
|
|
116
|
+
* @param chain - Optional chain to filter by
|
|
117
|
+
* @returns Array of wallet infos with privacy support
|
|
118
|
+
*/
|
|
119
|
+
getPrivacyWallets(chain?: ChainId): WalletInfo[] {
|
|
120
|
+
return Array.from(this.entries.values())
|
|
121
|
+
.filter((entry) => {
|
|
122
|
+
if (!entry.info.supportsPrivacy) return false
|
|
123
|
+
if (chain && !entry.info.chains.includes(chain)) return false
|
|
124
|
+
return true
|
|
125
|
+
})
|
|
126
|
+
.map((entry) => entry.info)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Check if a wallet is available (detected)
|
|
131
|
+
*
|
|
132
|
+
* @param id - The wallet identifier
|
|
133
|
+
* @returns True if wallet is detected
|
|
134
|
+
*/
|
|
135
|
+
isAvailable(id: string): boolean {
|
|
136
|
+
const entry = this.entries.get(id)
|
|
137
|
+
return entry ? entry.detect() : false
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Create a wallet adapter instance
|
|
142
|
+
*
|
|
143
|
+
* @param id - The wallet identifier
|
|
144
|
+
* @returns A new wallet adapter instance
|
|
145
|
+
* @throws If wallet is not registered
|
|
146
|
+
*/
|
|
147
|
+
create(id: string): WalletAdapter | PrivateWalletAdapter {
|
|
148
|
+
const entry = this.entries.get(id)
|
|
149
|
+
if (!entry) {
|
|
150
|
+
throw new Error(`Wallet '${id}' is not registered`)
|
|
151
|
+
}
|
|
152
|
+
return entry.factory()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Create and connect a wallet adapter
|
|
157
|
+
*
|
|
158
|
+
* @param id - The wallet identifier
|
|
159
|
+
* @returns A connected wallet adapter
|
|
160
|
+
* @throws If wallet is not registered or connection fails
|
|
161
|
+
*/
|
|
162
|
+
async connect(id: string): Promise<WalletAdapter | PrivateWalletAdapter> {
|
|
163
|
+
const wallet = this.create(id)
|
|
164
|
+
await wallet.connect()
|
|
165
|
+
return wallet
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Clear all registered wallets
|
|
170
|
+
*/
|
|
171
|
+
clear(): void {
|
|
172
|
+
this.entries.clear()
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Global wallet registry instance
|
|
178
|
+
*/
|
|
179
|
+
export const walletRegistry = new WalletRegistry()
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Helper to register a wallet adapter
|
|
183
|
+
*/
|
|
184
|
+
export function registerWallet(entry: WalletRegistryEntry): void {
|
|
185
|
+
walletRegistry.register(entry)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Helper to create a wallet adapter factory
|
|
190
|
+
*/
|
|
191
|
+
export function createWalletFactory<T extends WalletAdapter | PrivateWalletAdapter>(
|
|
192
|
+
AdapterClass: new () => T
|
|
193
|
+
): WalletAdapterFactory {
|
|
194
|
+
return () => new AdapterClass()
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Check if an adapter is a PrivateWalletAdapter
|
|
199
|
+
*/
|
|
200
|
+
export function isPrivateWalletAdapter(
|
|
201
|
+
adapter: WalletAdapter | PrivateWalletAdapter
|
|
202
|
+
): adapter is PrivateWalletAdapter {
|
|
203
|
+
return (
|
|
204
|
+
'supportsStealthAddresses' in adapter &&
|
|
205
|
+
typeof adapter.supportsStealthAddresses === 'function'
|
|
206
|
+
)
|
|
207
|
+
}
|