@sip-protocol/sdk 0.7.3 → 0.7.4
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/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +47556 -19603
- package/dist/browser.mjs +628 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
- package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48396 -19623
- package/dist/index.mjs +537 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +54 -21
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +252 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +47 -6
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +186 -33
- package/src/chains/solana/providers/index.ts +31 -0
- package/src/chains/solana/providers/interface.ts +61 -18
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +338 -67
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +83 -66
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +57 -6
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +23 -0
- package/src/compliance/range-sas.ts +398 -33
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +686 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +254 -4
- package/src/privacy-backends/interface.ts +649 -6
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash.ts +13 -17
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +414 -2
- package/src/privacy-backends/router.ts +283 -3
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +3 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +110 -29
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-2XIVXWHA.mjs +0 -1930
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-7RFRWDCW.mjs +0 -1504
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-F6F73W35.mjs +0 -16166
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-OFDBEIEK.mjs +0 -16166
- package/dist/chunk-SF7YSLF5.mjs +0 -1515
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/chunk-WWUSGOXE.mjs +0 -17129
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-B71aXVzk.d.ts +0 -13264
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-pOIIuwfV.d.mts +0 -13264
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-4O4K45VU.mjs +0 -46
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-NDABAZ6P.mjs +0 -56
- package/dist/solana-Q4NAVBTS.mjs +0 -46
- package/dist/solana-ZYO63LY5.mjs +0 -46
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Wallet Privacy Adapter
|
|
3
|
+
*
|
|
4
|
+
* Unified privacy adapter supporting multiple Ethereum wallets including
|
|
5
|
+
* Rabby, Rainbow, MetaMask, and any EIP-1193 compatible wallet.
|
|
6
|
+
*
|
|
7
|
+
* @module wallet/ethereum/multi-wallet
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { PrivacyEthereumWalletAdapter } from './privacy-adapter'
|
|
11
|
+
import type { HexString } from '@sip-protocol/types'
|
|
12
|
+
|
|
13
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Supported wallet types
|
|
17
|
+
*/
|
|
18
|
+
export type WalletType =
|
|
19
|
+
| 'metamask'
|
|
20
|
+
| 'rabby'
|
|
21
|
+
| 'rainbow'
|
|
22
|
+
| 'coinbase'
|
|
23
|
+
| 'trust'
|
|
24
|
+
| 'brave'
|
|
25
|
+
| 'frame'
|
|
26
|
+
| 'phantom'
|
|
27
|
+
| 'okx'
|
|
28
|
+
| 'unknown'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Wallet detection result
|
|
32
|
+
*/
|
|
33
|
+
export interface DetectedWallet {
|
|
34
|
+
/** Wallet type identifier */
|
|
35
|
+
type: WalletType
|
|
36
|
+
/** Display name */
|
|
37
|
+
name: string
|
|
38
|
+
/** Wallet icon URL (if available) */
|
|
39
|
+
icon?: string
|
|
40
|
+
/** EIP-1193 provider */
|
|
41
|
+
provider: EIP1193Provider
|
|
42
|
+
/** Whether this wallet is the default (window.ethereum) */
|
|
43
|
+
isDefault: boolean
|
|
44
|
+
/** Wallet version (if available) */
|
|
45
|
+
version?: string
|
|
46
|
+
/** Chain ID if already connected */
|
|
47
|
+
chainId?: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* EIP-1193 provider interface
|
|
52
|
+
*/
|
|
53
|
+
export interface EIP1193Provider {
|
|
54
|
+
request: (args: { method: string; params?: unknown[] }) => Promise<unknown>
|
|
55
|
+
on?: (event: string, handler: (...args: unknown[]) => void) => void
|
|
56
|
+
removeListener?: (event: string, handler: (...args: unknown[]) => void) => void
|
|
57
|
+
isMetaMask?: boolean
|
|
58
|
+
isRabby?: boolean
|
|
59
|
+
isRainbow?: boolean
|
|
60
|
+
isCoinbaseWallet?: boolean
|
|
61
|
+
isTrust?: boolean
|
|
62
|
+
isBraveWallet?: boolean
|
|
63
|
+
isFrame?: boolean
|
|
64
|
+
isPhantom?: boolean
|
|
65
|
+
isOKExWallet?: boolean
|
|
66
|
+
providers?: EIP1193Provider[]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Multi-wallet configuration options
|
|
71
|
+
*/
|
|
72
|
+
export interface MultiWalletConfig {
|
|
73
|
+
/** Preferred wallet type (if multiple detected) */
|
|
74
|
+
preferredWallet?: WalletType
|
|
75
|
+
/** Auto-connect to last used wallet */
|
|
76
|
+
autoConnect?: boolean
|
|
77
|
+
/** Chain ID to request */
|
|
78
|
+
chainId?: number
|
|
79
|
+
/** Storage key for persisting wallet preference */
|
|
80
|
+
storageKey?: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Wallet connection options
|
|
85
|
+
*/
|
|
86
|
+
export interface WalletConnectionOptions {
|
|
87
|
+
/** Target chain ID */
|
|
88
|
+
chainId?: number
|
|
89
|
+
/** Request specific permissions */
|
|
90
|
+
permissions?: string[]
|
|
91
|
+
/** Silent connection (no popup if already connected) */
|
|
92
|
+
silent?: boolean
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ─── Wallet Detection ─────────────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Wallet metadata for display
|
|
99
|
+
*/
|
|
100
|
+
const WALLET_METADATA: Record<WalletType, { name: string; icon?: string }> = {
|
|
101
|
+
metamask: {
|
|
102
|
+
name: 'MetaMask',
|
|
103
|
+
icon: 'https://raw.githubusercontent.com/MetaMask/brand-resources/master/SVG/metamask-fox.svg',
|
|
104
|
+
},
|
|
105
|
+
rabby: {
|
|
106
|
+
name: 'Rabby',
|
|
107
|
+
icon: 'https://rabby.io/assets/images/logo-rabby.svg',
|
|
108
|
+
},
|
|
109
|
+
rainbow: {
|
|
110
|
+
name: 'Rainbow',
|
|
111
|
+
icon: 'https://rainbow.me/favicon.ico',
|
|
112
|
+
},
|
|
113
|
+
coinbase: {
|
|
114
|
+
name: 'Coinbase Wallet',
|
|
115
|
+
icon: 'https://www.coinbase.com/favicon.ico',
|
|
116
|
+
},
|
|
117
|
+
trust: {
|
|
118
|
+
name: 'Trust Wallet',
|
|
119
|
+
icon: 'https://trustwallet.com/favicon.ico',
|
|
120
|
+
},
|
|
121
|
+
brave: {
|
|
122
|
+
name: 'Brave Wallet',
|
|
123
|
+
icon: 'https://brave.com/static-assets/images/brave-favicon.png',
|
|
124
|
+
},
|
|
125
|
+
frame: {
|
|
126
|
+
name: 'Frame',
|
|
127
|
+
icon: 'https://frame.sh/favicon.ico',
|
|
128
|
+
},
|
|
129
|
+
phantom: {
|
|
130
|
+
name: 'Phantom',
|
|
131
|
+
icon: 'https://phantom.app/favicon.ico',
|
|
132
|
+
},
|
|
133
|
+
okx: {
|
|
134
|
+
name: 'OKX Wallet',
|
|
135
|
+
icon: 'https://www.okx.com/favicon.ico',
|
|
136
|
+
},
|
|
137
|
+
unknown: {
|
|
138
|
+
name: 'Unknown Wallet',
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Detect wallet type from provider
|
|
144
|
+
*/
|
|
145
|
+
function detectWalletType(provider: EIP1193Provider): WalletType {
|
|
146
|
+
// Check specific wallet flags (order matters - some wallets set multiple flags)
|
|
147
|
+
if (provider.isRabby) return 'rabby'
|
|
148
|
+
if (provider.isRainbow) return 'rainbow'
|
|
149
|
+
if (provider.isCoinbaseWallet) return 'coinbase'
|
|
150
|
+
if (provider.isTrust) return 'trust'
|
|
151
|
+
if (provider.isBraveWallet) return 'brave'
|
|
152
|
+
if (provider.isFrame) return 'frame'
|
|
153
|
+
if (provider.isPhantom) return 'phantom'
|
|
154
|
+
if (provider.isOKExWallet) return 'okx'
|
|
155
|
+
if (provider.isMetaMask) return 'metamask'
|
|
156
|
+
|
|
157
|
+
return 'unknown'
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get global window.ethereum provider
|
|
162
|
+
*/
|
|
163
|
+
function getWindowEthereum(): EIP1193Provider | undefined {
|
|
164
|
+
if (typeof window !== 'undefined' && 'ethereum' in window) {
|
|
165
|
+
return window.ethereum as EIP1193Provider
|
|
166
|
+
}
|
|
167
|
+
return undefined
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Detect all available wallets
|
|
172
|
+
*
|
|
173
|
+
* @returns Array of detected wallets
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* const wallets = detectWallets()
|
|
178
|
+
* console.log(wallets.map(w => w.name)) // ['MetaMask', 'Rabby']
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export function detectWallets(): DetectedWallet[] {
|
|
182
|
+
const wallets: DetectedWallet[] = []
|
|
183
|
+
const ethereum = getWindowEthereum()
|
|
184
|
+
|
|
185
|
+
if (!ethereum) {
|
|
186
|
+
return wallets
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Check for multiple providers (some wallets expose array)
|
|
190
|
+
if (ethereum.providers && Array.isArray(ethereum.providers)) {
|
|
191
|
+
for (const provider of ethereum.providers) {
|
|
192
|
+
const type = detectWalletType(provider)
|
|
193
|
+
const metadata = WALLET_METADATA[type]
|
|
194
|
+
|
|
195
|
+
wallets.push({
|
|
196
|
+
type,
|
|
197
|
+
name: metadata.name,
|
|
198
|
+
icon: metadata.icon,
|
|
199
|
+
provider,
|
|
200
|
+
isDefault: false,
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Mark the default provider
|
|
205
|
+
const defaultType = detectWalletType(ethereum)
|
|
206
|
+
const defaultWallet = wallets.find(w => w.type === defaultType)
|
|
207
|
+
if (defaultWallet) {
|
|
208
|
+
defaultWallet.isDefault = true
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
// Single provider
|
|
212
|
+
const type = detectWalletType(ethereum)
|
|
213
|
+
const metadata = WALLET_METADATA[type]
|
|
214
|
+
|
|
215
|
+
wallets.push({
|
|
216
|
+
type,
|
|
217
|
+
name: metadata.name,
|
|
218
|
+
icon: metadata.icon,
|
|
219
|
+
provider: ethereum,
|
|
220
|
+
isDefault: true,
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return wallets
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Check if a specific wallet is installed
|
|
229
|
+
*
|
|
230
|
+
* @param walletType - Wallet type to check
|
|
231
|
+
* @returns Whether the wallet is available
|
|
232
|
+
*/
|
|
233
|
+
export function isWalletInstalled(walletType: WalletType): boolean {
|
|
234
|
+
const wallets = detectWallets()
|
|
235
|
+
return wallets.some(w => w.type === walletType)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get a specific wallet provider
|
|
240
|
+
*
|
|
241
|
+
* @param walletType - Wallet type to get
|
|
242
|
+
* @returns Wallet provider or undefined
|
|
243
|
+
*/
|
|
244
|
+
export function getWalletProvider(walletType: WalletType): EIP1193Provider | undefined {
|
|
245
|
+
const wallets = detectWallets()
|
|
246
|
+
const wallet = wallets.find(w => w.type === walletType)
|
|
247
|
+
return wallet?.provider
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ─── Multi-Wallet Adapter ─────────────────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* MultiWalletPrivacyAdapter - Unified privacy adapter for multiple wallets
|
|
254
|
+
*
|
|
255
|
+
* Extends PrivacyEthereumWalletAdapter with multi-wallet detection and
|
|
256
|
+
* connection management.
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* // Create adapter
|
|
261
|
+
* const adapter = new MultiWalletPrivacyAdapter()
|
|
262
|
+
*
|
|
263
|
+
* // Detect available wallets
|
|
264
|
+
* const wallets = adapter.getAvailableWallets()
|
|
265
|
+
* console.log(wallets.map(w => w.name)) // ['MetaMask', 'Rabby']
|
|
266
|
+
*
|
|
267
|
+
* // Connect to specific wallet
|
|
268
|
+
* await adapter.connectWallet('rabby')
|
|
269
|
+
*
|
|
270
|
+
* // Use privacy features
|
|
271
|
+
* const meta = await adapter.generateStealthMetaAddress()
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
export class MultiWalletPrivacyAdapter extends PrivacyEthereumWalletAdapter {
|
|
275
|
+
private currentWallet: DetectedWallet | null = null
|
|
276
|
+
private config: MultiWalletConfig
|
|
277
|
+
private walletListeners: Map<string, (...args: unknown[]) => void> = new Map()
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Create a new multi-wallet privacy adapter
|
|
281
|
+
*
|
|
282
|
+
* @param config - Configuration options
|
|
283
|
+
*/
|
|
284
|
+
constructor(config: MultiWalletConfig = {}) {
|
|
285
|
+
// Initialize with default/preferred provider
|
|
286
|
+
const wallets = detectWallets()
|
|
287
|
+
const preferred = config.preferredWallet
|
|
288
|
+
? wallets.find(w => w.type === config.preferredWallet)
|
|
289
|
+
: wallets.find(w => w.isDefault)
|
|
290
|
+
|
|
291
|
+
super({
|
|
292
|
+
chainId: config.chainId ?? 1,
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
this.config = {
|
|
296
|
+
storageKey: 'sip-preferred-wallet',
|
|
297
|
+
...config,
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (preferred) {
|
|
301
|
+
this.currentWallet = preferred
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Auto-connect if configured
|
|
305
|
+
if (config.autoConnect && preferred) {
|
|
306
|
+
this.connectWallet(preferred.type, { silent: true }).catch(() => {
|
|
307
|
+
// Silent connection failed, user will need to explicitly connect
|
|
308
|
+
})
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Get all available wallets
|
|
314
|
+
*
|
|
315
|
+
* @returns Array of detected wallets
|
|
316
|
+
*/
|
|
317
|
+
getAvailableWallets(): DetectedWallet[] {
|
|
318
|
+
return detectWallets()
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Get currently connected wallet
|
|
323
|
+
*
|
|
324
|
+
* @returns Current wallet or null
|
|
325
|
+
*/
|
|
326
|
+
getCurrentWallet(): DetectedWallet | null {
|
|
327
|
+
return this.currentWallet
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Check if a specific wallet is available
|
|
332
|
+
*
|
|
333
|
+
* @param walletType - Wallet type to check
|
|
334
|
+
* @returns Whether wallet is installed
|
|
335
|
+
*/
|
|
336
|
+
isWalletAvailable(walletType: WalletType): boolean {
|
|
337
|
+
return isWalletInstalled(walletType)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Connect to a specific wallet
|
|
342
|
+
*
|
|
343
|
+
* @param walletType - Wallet type to connect
|
|
344
|
+
* @param options - Connection options
|
|
345
|
+
* @returns Connected address
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```typescript
|
|
349
|
+
* // Connect to Rabby
|
|
350
|
+
* const address = await adapter.connectWallet('rabby')
|
|
351
|
+
*
|
|
352
|
+
* // Connect to Rainbow with specific chain
|
|
353
|
+
* const address = await adapter.connectWallet('rainbow', { chainId: 42161 })
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
async connectWallet(
|
|
357
|
+
walletType: WalletType,
|
|
358
|
+
options: WalletConnectionOptions = {}
|
|
359
|
+
): Promise<HexString> {
|
|
360
|
+
const wallets = detectWallets()
|
|
361
|
+
const wallet = wallets.find(w => w.type === walletType)
|
|
362
|
+
|
|
363
|
+
if (!wallet) {
|
|
364
|
+
throw new Error(`Wallet ${walletType} is not installed`)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const provider = wallet.provider
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
// Request accounts
|
|
371
|
+
const accounts = options.silent
|
|
372
|
+
? await provider.request({ method: 'eth_accounts' })
|
|
373
|
+
: await provider.request({ method: 'eth_requestAccounts' })
|
|
374
|
+
|
|
375
|
+
const accountList = accounts as string[]
|
|
376
|
+
if (!accountList || accountList.length === 0) {
|
|
377
|
+
throw new Error('No accounts available')
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Switch chain if needed
|
|
381
|
+
if (options.chainId) {
|
|
382
|
+
await this.switchChainForProvider(provider, options.chainId)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Update current wallet
|
|
386
|
+
this.currentWallet = {
|
|
387
|
+
...wallet,
|
|
388
|
+
chainId: options.chainId ?? this.config.chainId,
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Set up event listeners
|
|
392
|
+
this.setupWalletListeners(provider)
|
|
393
|
+
|
|
394
|
+
// Persist preference
|
|
395
|
+
this.persistWalletPreference(walletType)
|
|
396
|
+
|
|
397
|
+
return accountList[0] as HexString
|
|
398
|
+
} catch (error) {
|
|
399
|
+
// Handle user rejection
|
|
400
|
+
if ((error as { code?: number }).code === 4001) {
|
|
401
|
+
throw new Error('User rejected connection request')
|
|
402
|
+
}
|
|
403
|
+
throw error
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Disconnect from current wallet
|
|
409
|
+
*/
|
|
410
|
+
async disconnectWallet(): Promise<void> {
|
|
411
|
+
if (this.currentWallet?.provider) {
|
|
412
|
+
// Remove listeners
|
|
413
|
+
this.removeWalletListeners(this.currentWallet.provider)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
this.currentWallet = null
|
|
417
|
+
this.clearWalletPreference()
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Switch chain for a specific provider
|
|
422
|
+
*
|
|
423
|
+
* Unlike the base class switchChain(), this works with any EIP-1193 provider.
|
|
424
|
+
* Useful when working with multiple wallets or dynamically detected providers.
|
|
425
|
+
*
|
|
426
|
+
* @param provider - EIP-1193 provider to switch chain on
|
|
427
|
+
* @param chainId - Target chain ID
|
|
428
|
+
*/
|
|
429
|
+
async switchChainForProvider(provider: EIP1193Provider, chainId: number): Promise<void> {
|
|
430
|
+
const chainIdHex = `0x${chainId.toString(16)}`
|
|
431
|
+
|
|
432
|
+
try {
|
|
433
|
+
await provider.request({
|
|
434
|
+
method: 'wallet_switchEthereumChain',
|
|
435
|
+
params: [{ chainId: chainIdHex }],
|
|
436
|
+
})
|
|
437
|
+
} catch (error) {
|
|
438
|
+
// Chain not added, try to add it
|
|
439
|
+
if ((error as { code?: number }).code === 4902) {
|
|
440
|
+
await this.addChain(provider, chainId)
|
|
441
|
+
} else {
|
|
442
|
+
throw error
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Add a chain to the wallet
|
|
449
|
+
*/
|
|
450
|
+
private async addChain(provider: EIP1193Provider, chainId: number): Promise<void> {
|
|
451
|
+
const chainConfigs: Record<number, { name: string; rpcUrl: string; symbol: string; explorer: string }> = {
|
|
452
|
+
1: { name: 'Ethereum', rpcUrl: 'https://eth.llamarpc.com', symbol: 'ETH', explorer: 'https://etherscan.io' },
|
|
453
|
+
42161: { name: 'Arbitrum One', rpcUrl: 'https://arb1.arbitrum.io/rpc', symbol: 'ETH', explorer: 'https://arbiscan.io' },
|
|
454
|
+
10: { name: 'Optimism', rpcUrl: 'https://mainnet.optimism.io', symbol: 'ETH', explorer: 'https://optimistic.etherscan.io' },
|
|
455
|
+
8453: { name: 'Base', rpcUrl: 'https://mainnet.base.org', symbol: 'ETH', explorer: 'https://basescan.org' },
|
|
456
|
+
137: { name: 'Polygon', rpcUrl: 'https://polygon-rpc.com', symbol: 'MATIC', explorer: 'https://polygonscan.com' },
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const config = chainConfigs[chainId]
|
|
460
|
+
if (!config) {
|
|
461
|
+
throw new Error(`Unknown chain ID: ${chainId}`)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
await provider.request({
|
|
465
|
+
method: 'wallet_addEthereumChain',
|
|
466
|
+
params: [{
|
|
467
|
+
chainId: `0x${chainId.toString(16)}`,
|
|
468
|
+
chainName: config.name,
|
|
469
|
+
nativeCurrency: { name: config.symbol, symbol: config.symbol, decimals: 18 },
|
|
470
|
+
rpcUrls: [config.rpcUrl],
|
|
471
|
+
blockExplorerUrls: [config.explorer],
|
|
472
|
+
}],
|
|
473
|
+
})
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Sign a personal message with the connected wallet
|
|
478
|
+
*
|
|
479
|
+
* Convenience method that accepts a string message directly.
|
|
480
|
+
* For Uint8Array messages, use the inherited signMessage() method.
|
|
481
|
+
*
|
|
482
|
+
* @param message - Message string to sign
|
|
483
|
+
* @returns Signature as hex string
|
|
484
|
+
*/
|
|
485
|
+
async signPersonalMessage(message: string): Promise<HexString> {
|
|
486
|
+
if (!this.currentWallet) {
|
|
487
|
+
throw new Error('No wallet connected')
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const accounts = await this.currentWallet.provider.request({
|
|
491
|
+
method: 'eth_accounts',
|
|
492
|
+
}) as string[]
|
|
493
|
+
|
|
494
|
+
if (!accounts || accounts.length === 0) {
|
|
495
|
+
throw new Error('No accounts available')
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const signature = await this.currentWallet.provider.request({
|
|
499
|
+
method: 'personal_sign',
|
|
500
|
+
params: [message, accounts[0]],
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
return signature as HexString
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Sign typed data (EIP-712 v4) with the connected wallet
|
|
508
|
+
*
|
|
509
|
+
* Convenience method that accepts a generic typed data object.
|
|
510
|
+
* For strict EIP712TypedData, use the inherited signTypedData() method.
|
|
511
|
+
*
|
|
512
|
+
* @param typedData - Typed data object to sign
|
|
513
|
+
* @returns Signature as hex string
|
|
514
|
+
*/
|
|
515
|
+
async signTypedDataV4(typedData: Record<string, unknown>): Promise<HexString> {
|
|
516
|
+
if (!this.currentWallet) {
|
|
517
|
+
throw new Error('No wallet connected')
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const accounts = await this.currentWallet.provider.request({
|
|
521
|
+
method: 'eth_accounts',
|
|
522
|
+
}) as string[]
|
|
523
|
+
|
|
524
|
+
if (!accounts || accounts.length === 0) {
|
|
525
|
+
throw new Error('No accounts available')
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const signature = await this.currentWallet.provider.request({
|
|
529
|
+
method: 'eth_signTypedData_v4',
|
|
530
|
+
params: [accounts[0], JSON.stringify(typedData)],
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
return signature as HexString
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Set up wallet event listeners
|
|
538
|
+
*/
|
|
539
|
+
private setupWalletListeners(provider: EIP1193Provider): void {
|
|
540
|
+
if (!provider.on) return
|
|
541
|
+
|
|
542
|
+
const accountsHandler = (accounts: unknown) => {
|
|
543
|
+
const accountList = accounts as string[]
|
|
544
|
+
if (accountList.length === 0) {
|
|
545
|
+
// Disconnected
|
|
546
|
+
this.disconnectWallet()
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const chainHandler = (chainId: unknown) => {
|
|
551
|
+
if (this.currentWallet) {
|
|
552
|
+
this.currentWallet.chainId = parseInt(chainId as string, 16)
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
provider.on('accountsChanged', accountsHandler)
|
|
557
|
+
provider.on('chainChanged', chainHandler)
|
|
558
|
+
|
|
559
|
+
this.walletListeners.set('accountsChanged', accountsHandler)
|
|
560
|
+
this.walletListeners.set('chainChanged', chainHandler)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Remove wallet event listeners
|
|
565
|
+
*/
|
|
566
|
+
private removeWalletListeners(provider: EIP1193Provider): void {
|
|
567
|
+
if (!provider.removeListener) return
|
|
568
|
+
|
|
569
|
+
for (const [event, handler] of this.walletListeners) {
|
|
570
|
+
provider.removeListener(event, handler)
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
this.walletListeners.clear()
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Persist wallet preference to storage
|
|
578
|
+
*/
|
|
579
|
+
private persistWalletPreference(walletType: WalletType): void {
|
|
580
|
+
if (typeof localStorage !== 'undefined' && this.config.storageKey) {
|
|
581
|
+
localStorage.setItem(this.config.storageKey, walletType)
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Clear wallet preference from storage
|
|
587
|
+
*/
|
|
588
|
+
private clearWalletPreference(): void {
|
|
589
|
+
if (typeof localStorage !== 'undefined' && this.config.storageKey) {
|
|
590
|
+
localStorage.removeItem(this.config.storageKey)
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Load persisted wallet preference
|
|
596
|
+
*
|
|
597
|
+
* @returns Preferred wallet type or undefined
|
|
598
|
+
*/
|
|
599
|
+
getPersistedWalletPreference(): WalletType | undefined {
|
|
600
|
+
if (typeof localStorage !== 'undefined' && this.config.storageKey) {
|
|
601
|
+
const stored = localStorage.getItem(this.config.storageKey)
|
|
602
|
+
return stored as WalletType | undefined
|
|
603
|
+
}
|
|
604
|
+
return undefined
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Create a multi-wallet privacy adapter
|
|
610
|
+
*
|
|
611
|
+
* @param config - Configuration options
|
|
612
|
+
* @returns MultiWalletPrivacyAdapter instance
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* ```typescript
|
|
616
|
+
* // Basic usage
|
|
617
|
+
* const adapter = createMultiWalletAdapter()
|
|
618
|
+
*
|
|
619
|
+
* // With preferred wallet
|
|
620
|
+
* const adapter = createMultiWalletAdapter({
|
|
621
|
+
* preferredWallet: 'rabby',
|
|
622
|
+
* autoConnect: true,
|
|
623
|
+
* })
|
|
624
|
+
* ```
|
|
625
|
+
*/
|
|
626
|
+
export function createMultiWalletAdapter(
|
|
627
|
+
config: MultiWalletConfig = {}
|
|
628
|
+
): MultiWalletPrivacyAdapter {
|
|
629
|
+
return new MultiWalletPrivacyAdapter(config)
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Create adapter for Rabby wallet
|
|
634
|
+
*/
|
|
635
|
+
export function createRabbyPrivacyAdapter(): MultiWalletPrivacyAdapter {
|
|
636
|
+
return new MultiWalletPrivacyAdapter({ preferredWallet: 'rabby' })
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Create adapter for Rainbow wallet
|
|
641
|
+
*/
|
|
642
|
+
export function createRainbowPrivacyAdapter(): MultiWalletPrivacyAdapter {
|
|
643
|
+
return new MultiWalletPrivacyAdapter({ preferredWallet: 'rainbow' })
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
export default MultiWalletPrivacyAdapter
|