@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,675 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WalletConnect v2 Privacy Adapter
|
|
3
|
+
*
|
|
4
|
+
* Extends privacy wallet adapter for WalletConnect v2 protocol,
|
|
5
|
+
* enabling mobile wallet privacy operations.
|
|
6
|
+
*
|
|
7
|
+
* @module wallet/ethereum/walletconnect-adapter
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { HexString } from '@sip-protocol/types'
|
|
11
|
+
import { WalletErrorCode } from '@sip-protocol/types'
|
|
12
|
+
import { WalletError } from '../errors'
|
|
13
|
+
import {
|
|
14
|
+
PrivacyEthereumWalletAdapter,
|
|
15
|
+
type PrivacyEthereumAdapterConfig,
|
|
16
|
+
type PrivacyContext,
|
|
17
|
+
} from './privacy-adapter'
|
|
18
|
+
import type { EIP1193Provider, EIP712TypedData } from './types'
|
|
19
|
+
import { EthereumChainId } from './types'
|
|
20
|
+
|
|
21
|
+
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* WalletConnect session info
|
|
25
|
+
*/
|
|
26
|
+
export interface WalletConnectSession {
|
|
27
|
+
/** Session topic */
|
|
28
|
+
topic: string
|
|
29
|
+
/** Peer metadata */
|
|
30
|
+
peer: {
|
|
31
|
+
name: string
|
|
32
|
+
description: string
|
|
33
|
+
url: string
|
|
34
|
+
icons: string[]
|
|
35
|
+
}
|
|
36
|
+
/** Namespaces with accounts and methods */
|
|
37
|
+
namespaces: {
|
|
38
|
+
eip155?: {
|
|
39
|
+
accounts: string[]
|
|
40
|
+
methods: string[]
|
|
41
|
+
events: string[]
|
|
42
|
+
chains?: string[]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Session expiry timestamp */
|
|
46
|
+
expiry: number
|
|
47
|
+
/** Acknowledged flag */
|
|
48
|
+
acknowledged: boolean
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* WalletConnect adapter configuration
|
|
53
|
+
*/
|
|
54
|
+
export interface WalletConnectAdapterConfig extends Omit<PrivacyEthereumAdapterConfig, 'provider' | 'wallet'> {
|
|
55
|
+
/**
|
|
56
|
+
* WalletConnect project ID from cloud.walletconnect.com
|
|
57
|
+
*/
|
|
58
|
+
projectId: string
|
|
59
|
+
/**
|
|
60
|
+
* Relay URL (defaults to wss://relay.walletconnect.com)
|
|
61
|
+
*/
|
|
62
|
+
relayUrl?: string
|
|
63
|
+
/**
|
|
64
|
+
* App metadata for pairing proposal
|
|
65
|
+
*/
|
|
66
|
+
metadata?: {
|
|
67
|
+
name: string
|
|
68
|
+
description: string
|
|
69
|
+
url: string
|
|
70
|
+
icons: string[]
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Required chain IDs for session
|
|
74
|
+
*/
|
|
75
|
+
requiredChains?: number[]
|
|
76
|
+
/**
|
|
77
|
+
* Optional chain IDs
|
|
78
|
+
*/
|
|
79
|
+
optionalChains?: number[]
|
|
80
|
+
/**
|
|
81
|
+
* Session storage key
|
|
82
|
+
*/
|
|
83
|
+
storageKey?: string
|
|
84
|
+
/**
|
|
85
|
+
* Connection timeout in ms
|
|
86
|
+
*/
|
|
87
|
+
connectionTimeout?: number
|
|
88
|
+
/**
|
|
89
|
+
* Auto-reconnect to previous session
|
|
90
|
+
*/
|
|
91
|
+
autoReconnect?: boolean
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Connection result
|
|
96
|
+
*/
|
|
97
|
+
export interface WalletConnectResult {
|
|
98
|
+
/** Connected address */
|
|
99
|
+
address: string
|
|
100
|
+
/** Chain ID */
|
|
101
|
+
chainId: number
|
|
102
|
+
/** Session info */
|
|
103
|
+
session: WalletConnectSession
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Pairing URI for QR code
|
|
108
|
+
*/
|
|
109
|
+
export interface PairingUri {
|
|
110
|
+
/** Full URI for QR code */
|
|
111
|
+
uri: string
|
|
112
|
+
/** Topic for tracking */
|
|
113
|
+
topic: string
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─── WalletConnect Adapter ──────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* WalletConnect v2 Privacy Adapter
|
|
120
|
+
*
|
|
121
|
+
* Enables privacy operations through WalletConnect for mobile wallets.
|
|
122
|
+
* Handles session management, reconnection, and multi-chain support.
|
|
123
|
+
*
|
|
124
|
+
* @example Basic usage
|
|
125
|
+
* ```typescript
|
|
126
|
+
* const adapter = new WalletConnectPrivacyAdapter({
|
|
127
|
+
* projectId: 'your-project-id',
|
|
128
|
+
* chainId: 1,
|
|
129
|
+
* })
|
|
130
|
+
*
|
|
131
|
+
* // Generate pairing URI for QR code
|
|
132
|
+
* const { uri } = await adapter.createPairing()
|
|
133
|
+
* displayQRCode(uri)
|
|
134
|
+
*
|
|
135
|
+
* // Wait for connection
|
|
136
|
+
* await adapter.connect()
|
|
137
|
+
* await adapter.initializePrivacy()
|
|
138
|
+
*
|
|
139
|
+
* // Use privacy features
|
|
140
|
+
* const metaAddress = adapter.getMetaAddress()
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* @example With auto-reconnect
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const adapter = new WalletConnectPrivacyAdapter({
|
|
146
|
+
* projectId: 'your-project-id',
|
|
147
|
+
* autoReconnect: true,
|
|
148
|
+
* storageKey: 'my-app-wc-session',
|
|
149
|
+
* })
|
|
150
|
+
*
|
|
151
|
+
* // Attempt to reconnect to previous session
|
|
152
|
+
* const reconnected = await adapter.tryReconnect()
|
|
153
|
+
* if (!reconnected) {
|
|
154
|
+
* // Create new pairing
|
|
155
|
+
* const { uri } = await adapter.createPairing()
|
|
156
|
+
* displayQRCode(uri)
|
|
157
|
+
* }
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
export class WalletConnectPrivacyAdapter extends PrivacyEthereumWalletAdapter {
|
|
161
|
+
private projectId: string
|
|
162
|
+
private relayUrl: string
|
|
163
|
+
private wcMetadata: Required<WalletConnectAdapterConfig>['metadata']
|
|
164
|
+
private requiredChains: number[]
|
|
165
|
+
private optionalChains: number[]
|
|
166
|
+
private storageKey: string
|
|
167
|
+
private connectionTimeout: number
|
|
168
|
+
private autoReconnect: boolean
|
|
169
|
+
private currentSession: WalletConnectSession | undefined
|
|
170
|
+
private pairingUri: PairingUri | undefined
|
|
171
|
+
private signClient: unknown // WalletConnect SignClient instance
|
|
172
|
+
private wcProvider: EIP1193Provider | undefined
|
|
173
|
+
|
|
174
|
+
constructor(config: WalletConnectAdapterConfig) {
|
|
175
|
+
// Create with a placeholder provider - will be set during connect
|
|
176
|
+
super({
|
|
177
|
+
...config,
|
|
178
|
+
wallet: 'walletconnect',
|
|
179
|
+
provider: undefined,
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
this.projectId = config.projectId
|
|
183
|
+
this.relayUrl = config.relayUrl ?? 'wss://relay.walletconnect.com'
|
|
184
|
+
this.wcMetadata = config.metadata ?? {
|
|
185
|
+
name: 'SIP Protocol',
|
|
186
|
+
description: 'Privacy-preserving transactions',
|
|
187
|
+
url: 'https://sip-protocol.org',
|
|
188
|
+
icons: ['https://sip-protocol.org/icon.png'],
|
|
189
|
+
}
|
|
190
|
+
this.requiredChains = config.requiredChains ?? [config.chainId ?? EthereumChainId.MAINNET]
|
|
191
|
+
this.optionalChains = config.optionalChains ?? [
|
|
192
|
+
EthereumChainId.MAINNET,
|
|
193
|
+
EthereumChainId.SEPOLIA,
|
|
194
|
+
EthereumChainId.ARBITRUM,
|
|
195
|
+
EthereumChainId.OPTIMISM,
|
|
196
|
+
EthereumChainId.BASE,
|
|
197
|
+
EthereumChainId.POLYGON,
|
|
198
|
+
]
|
|
199
|
+
this.storageKey = config.storageKey ?? 'sip-wc-session'
|
|
200
|
+
this.connectionTimeout = config.connectionTimeout ?? 30000
|
|
201
|
+
this.autoReconnect = config.autoReconnect ?? true
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ─── Session Management ─────────────────────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Create a pairing URI for QR code display
|
|
208
|
+
*
|
|
209
|
+
* Call this before connect() to get the pairing URI.
|
|
210
|
+
*
|
|
211
|
+
* @returns Pairing URI and topic
|
|
212
|
+
*/
|
|
213
|
+
async createPairing(): Promise<PairingUri> {
|
|
214
|
+
await this.ensureSignClient()
|
|
215
|
+
|
|
216
|
+
// Create pairing proposal
|
|
217
|
+
const { uri, approval } = await this.createConnectProposal()
|
|
218
|
+
|
|
219
|
+
this.pairingUri = { uri, topic: '' }
|
|
220
|
+
|
|
221
|
+
// Store approval promise for connect()
|
|
222
|
+
;(this as unknown as { _approval: Promise<WalletConnectSession> })._approval = approval
|
|
223
|
+
|
|
224
|
+
return this.pairingUri
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Connect to WalletConnect
|
|
229
|
+
*
|
|
230
|
+
* If createPairing() was called, waits for user to scan QR.
|
|
231
|
+
* Otherwise, attempts to reconnect to existing session.
|
|
232
|
+
*/
|
|
233
|
+
async connect(): Promise<void> {
|
|
234
|
+
try {
|
|
235
|
+
this._connectionState = 'connecting'
|
|
236
|
+
|
|
237
|
+
// Try auto-reconnect if enabled
|
|
238
|
+
if (this.autoReconnect && !this.pairingUri) {
|
|
239
|
+
const reconnected = await this.tryReconnect()
|
|
240
|
+
if (reconnected) {
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Wait for approval from pairing
|
|
246
|
+
const approval = (this as unknown as { _approval: Promise<WalletConnectSession> })._approval
|
|
247
|
+
if (!approval) {
|
|
248
|
+
throw new WalletError(
|
|
249
|
+
'Call createPairing() first to get pairing URI',
|
|
250
|
+
WalletErrorCode.NOT_CONNECTED
|
|
251
|
+
)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Wait for session with timeout
|
|
255
|
+
const session = await Promise.race([
|
|
256
|
+
approval,
|
|
257
|
+
new Promise<never>((_, reject) =>
|
|
258
|
+
setTimeout(
|
|
259
|
+
() => reject(new Error('Connection timeout')),
|
|
260
|
+
this.connectionTimeout
|
|
261
|
+
)
|
|
262
|
+
),
|
|
263
|
+
])
|
|
264
|
+
|
|
265
|
+
this.currentSession = session
|
|
266
|
+
await this.setupFromSession(session)
|
|
267
|
+
|
|
268
|
+
// Store session for reconnection
|
|
269
|
+
this.storeSession(session)
|
|
270
|
+
|
|
271
|
+
} catch (error) {
|
|
272
|
+
this._connectionState = 'error'
|
|
273
|
+
|
|
274
|
+
if (error instanceof WalletError) {
|
|
275
|
+
throw error
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
throw new WalletError(
|
|
279
|
+
`WalletConnect connection failed: ${String(error)}`,
|
|
280
|
+
WalletErrorCode.CONNECTION_FAILED
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Try to reconnect to a previous session
|
|
287
|
+
*
|
|
288
|
+
* @returns True if successfully reconnected
|
|
289
|
+
*/
|
|
290
|
+
async tryReconnect(): Promise<boolean> {
|
|
291
|
+
const storedSession = this.loadSession()
|
|
292
|
+
if (!storedSession) {
|
|
293
|
+
return false
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
await this.ensureSignClient()
|
|
298
|
+
|
|
299
|
+
// Check if session is still valid
|
|
300
|
+
const now = Math.floor(Date.now() / 1000)
|
|
301
|
+
if (storedSession.expiry < now) {
|
|
302
|
+
this.clearStoredSession()
|
|
303
|
+
return false
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Try to restore session
|
|
307
|
+
this.currentSession = storedSession
|
|
308
|
+
await this.setupFromSession(storedSession)
|
|
309
|
+
|
|
310
|
+
return true
|
|
311
|
+
} catch {
|
|
312
|
+
this.clearStoredSession()
|
|
313
|
+
return false
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Disconnect from WalletConnect
|
|
319
|
+
*/
|
|
320
|
+
async disconnect(): Promise<void> {
|
|
321
|
+
if (this.currentSession && this.signClient) {
|
|
322
|
+
try {
|
|
323
|
+
// Disconnect WalletConnect session
|
|
324
|
+
await (this.signClient as { disconnect: (params: { topic: string; reason: { code: number; message: string } }) => Promise<void> }).disconnect({
|
|
325
|
+
topic: this.currentSession.topic,
|
|
326
|
+
reason: { code: 6000, message: 'User disconnected' },
|
|
327
|
+
})
|
|
328
|
+
} catch {
|
|
329
|
+
// Ignore disconnect errors
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
this.currentSession = undefined
|
|
334
|
+
this.wcProvider = undefined
|
|
335
|
+
this.pairingUri = undefined
|
|
336
|
+
this.clearStoredSession()
|
|
337
|
+
this.clearPrivacy()
|
|
338
|
+
|
|
339
|
+
await super.disconnect()
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ─── Session Info ───────────────────────────────────────────────────────────
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Get current session info
|
|
346
|
+
*/
|
|
347
|
+
getSession(): WalletConnectSession | undefined {
|
|
348
|
+
return this.currentSession
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Check if session is active
|
|
353
|
+
*/
|
|
354
|
+
isSessionActive(): boolean {
|
|
355
|
+
if (!this.currentSession) return false
|
|
356
|
+
const now = Math.floor(Date.now() / 1000)
|
|
357
|
+
return this.currentSession.expiry > now
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Get connected peer metadata
|
|
362
|
+
*/
|
|
363
|
+
getPeerMetadata(): WalletConnectSession['peer'] | undefined {
|
|
364
|
+
return this.currentSession?.peer
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Get pairing URI for QR code
|
|
369
|
+
*/
|
|
370
|
+
getPairingUri(): string | undefined {
|
|
371
|
+
return this.pairingUri?.uri
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// ─── Privacy Context Persistence ────────────────────────────────────────────
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Save privacy context to storage
|
|
378
|
+
*
|
|
379
|
+
* Allows preserving privacy keys across page reloads.
|
|
380
|
+
*/
|
|
381
|
+
savePrivacyContext(): void {
|
|
382
|
+
const context = this.getPrivacyContext()
|
|
383
|
+
if (context && typeof localStorage !== 'undefined') {
|
|
384
|
+
localStorage.setItem(
|
|
385
|
+
`${this.storageKey}-privacy`,
|
|
386
|
+
JSON.stringify(context)
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Load and restore privacy context from storage
|
|
393
|
+
*
|
|
394
|
+
* @returns True if context was restored
|
|
395
|
+
*/
|
|
396
|
+
loadPrivacyContext(): boolean {
|
|
397
|
+
if (typeof localStorage === 'undefined') return false
|
|
398
|
+
|
|
399
|
+
const stored = localStorage.getItem(`${this.storageKey}-privacy`)
|
|
400
|
+
if (!stored) return false
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
const context = JSON.parse(stored) as PrivacyContext
|
|
404
|
+
this.setPrivacyContext(context)
|
|
405
|
+
return true
|
|
406
|
+
} catch {
|
|
407
|
+
return false
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Clear stored privacy context
|
|
413
|
+
*/
|
|
414
|
+
clearPrivacyContext(): void {
|
|
415
|
+
if (typeof localStorage !== 'undefined') {
|
|
416
|
+
localStorage.removeItem(`${this.storageKey}-privacy`)
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// ─── Signing with Mobile Wallet Handling ────────────────────────────────────
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Sign typed data with extended timeout for mobile
|
|
424
|
+
*
|
|
425
|
+
* Mobile wallets may take longer to respond due to user interaction.
|
|
426
|
+
*/
|
|
427
|
+
async signTypedDataWithTimeout(
|
|
428
|
+
typedData: EIP712TypedData,
|
|
429
|
+
timeout: number = 60000
|
|
430
|
+
): Promise<HexString> {
|
|
431
|
+
if (!this.wcProvider) {
|
|
432
|
+
throw new WalletError(
|
|
433
|
+
'WalletConnect not connected',
|
|
434
|
+
WalletErrorCode.NOT_CONNECTED
|
|
435
|
+
)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const signature = await Promise.race([
|
|
439
|
+
this.signTypedData(typedData),
|
|
440
|
+
new Promise<never>((_, reject) =>
|
|
441
|
+
setTimeout(
|
|
442
|
+
() => reject(new WalletError('Signing timeout', WalletErrorCode.SIGNING_FAILED)),
|
|
443
|
+
timeout
|
|
444
|
+
)
|
|
445
|
+
),
|
|
446
|
+
])
|
|
447
|
+
|
|
448
|
+
return signature.signature
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// ─── Private Methods ────────────────────────────────────────────────────────
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Ensure SignClient is initialized
|
|
455
|
+
*/
|
|
456
|
+
private async ensureSignClient(): Promise<void> {
|
|
457
|
+
if (this.signClient) return
|
|
458
|
+
|
|
459
|
+
// Dynamic import of WalletConnect
|
|
460
|
+
// This allows the package to be optional
|
|
461
|
+
try {
|
|
462
|
+
// @ts-expect-error - Optional peer dependency, users must install separately
|
|
463
|
+
const { SignClient } = await import('@walletconnect/sign-client')
|
|
464
|
+
|
|
465
|
+
this.signClient = await SignClient.init({
|
|
466
|
+
projectId: this.projectId,
|
|
467
|
+
relayUrl: this.relayUrl,
|
|
468
|
+
metadata: this.wcMetadata,
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
// Set up event handlers
|
|
472
|
+
this.setupEventHandlers()
|
|
473
|
+
} catch (error) {
|
|
474
|
+
throw new WalletError(
|
|
475
|
+
'Failed to initialize WalletConnect. Make sure @walletconnect/sign-client is installed.',
|
|
476
|
+
WalletErrorCode.CONNECTION_FAILED
|
|
477
|
+
)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Create connection proposal
|
|
483
|
+
*/
|
|
484
|
+
private async createConnectProposal(): Promise<{
|
|
485
|
+
uri: string
|
|
486
|
+
approval: Promise<WalletConnectSession>
|
|
487
|
+
}> {
|
|
488
|
+
const client = this.signClient as {
|
|
489
|
+
connect: (params: {
|
|
490
|
+
requiredNamespaces: Record<string, { chains: string[]; methods: string[]; events: string[] }>
|
|
491
|
+
optionalNamespaces?: Record<string, { chains: string[]; methods: string[]; events: string[] }>
|
|
492
|
+
}) => Promise<{ uri: string; approval: () => Promise<{ topic: string; peer: { metadata: WalletConnectSession['peer'] }; namespaces: WalletConnectSession['namespaces']; expiry: number; acknowledged: boolean }> }>
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const { uri, approval } = await client.connect({
|
|
496
|
+
requiredNamespaces: {
|
|
497
|
+
eip155: {
|
|
498
|
+
chains: this.requiredChains.map(id => `eip155:${id}`),
|
|
499
|
+
methods: [
|
|
500
|
+
'eth_sendTransaction',
|
|
501
|
+
'eth_signTransaction',
|
|
502
|
+
'eth_sign',
|
|
503
|
+
'personal_sign',
|
|
504
|
+
'eth_signTypedData',
|
|
505
|
+
'eth_signTypedData_v4',
|
|
506
|
+
],
|
|
507
|
+
events: ['chainChanged', 'accountsChanged'],
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
optionalNamespaces: {
|
|
511
|
+
eip155: {
|
|
512
|
+
chains: this.optionalChains.map(id => `eip155:${id}`),
|
|
513
|
+
methods: [
|
|
514
|
+
'eth_sendTransaction',
|
|
515
|
+
'personal_sign',
|
|
516
|
+
'eth_signTypedData_v4',
|
|
517
|
+
],
|
|
518
|
+
events: ['chainChanged', 'accountsChanged'],
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
})
|
|
522
|
+
|
|
523
|
+
return {
|
|
524
|
+
uri: uri ?? '',
|
|
525
|
+
approval: approval().then(session => ({
|
|
526
|
+
topic: session.topic,
|
|
527
|
+
peer: session.peer.metadata,
|
|
528
|
+
namespaces: session.namespaces,
|
|
529
|
+
expiry: session.expiry,
|
|
530
|
+
acknowledged: session.acknowledged,
|
|
531
|
+
})),
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Set up adapter from session
|
|
537
|
+
*/
|
|
538
|
+
private async setupFromSession(session: WalletConnectSession): Promise<void> {
|
|
539
|
+
// Get first account from session
|
|
540
|
+
const account = session.namespaces.eip155?.accounts[0]
|
|
541
|
+
if (!account) {
|
|
542
|
+
throw new WalletError(
|
|
543
|
+
'No accounts in WalletConnect session',
|
|
544
|
+
WalletErrorCode.CONNECTION_FAILED
|
|
545
|
+
)
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Parse account format: eip155:chainId:address
|
|
549
|
+
const [, _chainIdStr, address] = account.split(':')
|
|
550
|
+
|
|
551
|
+
// Create EIP-1193 provider from SignClient
|
|
552
|
+
this.wcProvider = this.createProviderFromSession(session)
|
|
553
|
+
|
|
554
|
+
// Set connected state
|
|
555
|
+
this.setConnected(address, address as HexString)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Create EIP-1193 provider from session
|
|
560
|
+
*/
|
|
561
|
+
private createProviderFromSession(session: WalletConnectSession): EIP1193Provider {
|
|
562
|
+
const client = this.signClient as {
|
|
563
|
+
request: <T>(params: { topic: string; chainId: string; request: { method: string; params: unknown[] } }) => Promise<T>
|
|
564
|
+
}
|
|
565
|
+
const topic = session.topic
|
|
566
|
+
const chainId = this.getChainId()
|
|
567
|
+
|
|
568
|
+
return {
|
|
569
|
+
request: async <T>({ method, params }: { method: string; params?: unknown[] }): Promise<T> => {
|
|
570
|
+
return client.request<T>({
|
|
571
|
+
topic,
|
|
572
|
+
chainId: `eip155:${chainId}`,
|
|
573
|
+
request: { method, params: params ?? [] },
|
|
574
|
+
})
|
|
575
|
+
},
|
|
576
|
+
on: () => {},
|
|
577
|
+
removeListener: () => {},
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Set up WalletConnect event handlers
|
|
583
|
+
*/
|
|
584
|
+
private setupEventHandlers(): void {
|
|
585
|
+
const client = this.signClient as {
|
|
586
|
+
on: (event: string, callback: (data: { topic: string; params?: { message?: string } }) => void) => void
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
client.on('session_delete', ({ topic }) => {
|
|
590
|
+
if (this.currentSession?.topic === topic) {
|
|
591
|
+
this.onWalletConnectDisconnect()
|
|
592
|
+
}
|
|
593
|
+
})
|
|
594
|
+
|
|
595
|
+
client.on('session_expire', ({ topic }) => {
|
|
596
|
+
if (this.currentSession?.topic === topic) {
|
|
597
|
+
this.onWalletConnectDisconnect()
|
|
598
|
+
}
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
client.on('session_event', () => {
|
|
602
|
+
// Handle session events (chainChanged, accountsChanged)
|
|
603
|
+
})
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Handle WalletConnect disconnect event
|
|
608
|
+
*/
|
|
609
|
+
private onWalletConnectDisconnect(): void {
|
|
610
|
+
this.currentSession = undefined
|
|
611
|
+
this.wcProvider = undefined
|
|
612
|
+
this.setDisconnected('WalletConnect session ended')
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// ─── Session Storage ────────────────────────────────────────────────────────
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Store session to localStorage
|
|
619
|
+
*/
|
|
620
|
+
private storeSession(session: WalletConnectSession): void {
|
|
621
|
+
if (typeof localStorage !== 'undefined') {
|
|
622
|
+
localStorage.setItem(this.storageKey, JSON.stringify(session))
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Load session from localStorage
|
|
628
|
+
*/
|
|
629
|
+
private loadSession(): WalletConnectSession | undefined {
|
|
630
|
+
if (typeof localStorage === 'undefined') return undefined
|
|
631
|
+
|
|
632
|
+
const stored = localStorage.getItem(this.storageKey)
|
|
633
|
+
if (!stored) return undefined
|
|
634
|
+
|
|
635
|
+
try {
|
|
636
|
+
return JSON.parse(stored) as WalletConnectSession
|
|
637
|
+
} catch {
|
|
638
|
+
return undefined
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Clear stored session
|
|
644
|
+
*/
|
|
645
|
+
private clearStoredSession(): void {
|
|
646
|
+
if (typeof localStorage !== 'undefined') {
|
|
647
|
+
localStorage.removeItem(this.storageKey)
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// ─── Factory Function ───────────────────────────────────────────────────────
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Create a WalletConnect privacy adapter
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* ```typescript
|
|
659
|
+
* const adapter = createWalletConnectPrivacyAdapter({
|
|
660
|
+
* projectId: 'your-walletconnect-project-id',
|
|
661
|
+
* chainId: 1,
|
|
662
|
+
* })
|
|
663
|
+
*
|
|
664
|
+
* const { uri } = await adapter.createPairing()
|
|
665
|
+
* // Display QR code with uri
|
|
666
|
+
*
|
|
667
|
+
* await adapter.connect()
|
|
668
|
+
* await adapter.initializePrivacy()
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
export function createWalletConnectPrivacyAdapter(
|
|
672
|
+
config: WalletConnectAdapterConfig
|
|
673
|
+
): WalletConnectPrivacyAdapter {
|
|
674
|
+
return new WalletConnectPrivacyAdapter(config)
|
|
675
|
+
}
|
|
@@ -74,6 +74,16 @@ export {
|
|
|
74
74
|
// Ledger adapter
|
|
75
75
|
export { LedgerWalletAdapter, createLedgerAdapter } from './ledger'
|
|
76
76
|
|
|
77
|
+
// Ledger privacy adapter (Ethereum stealth addresses)
|
|
78
|
+
export {
|
|
79
|
+
LedgerPrivacyAdapter,
|
|
80
|
+
createLedgerPrivacyAdapter,
|
|
81
|
+
type LedgerPrivacyConfig,
|
|
82
|
+
type LedgerStealthKeyMaterial,
|
|
83
|
+
type LedgerScannedPayment,
|
|
84
|
+
type LedgerClaimResult,
|
|
85
|
+
} from './ledger-privacy'
|
|
86
|
+
|
|
77
87
|
// Trezor adapter
|
|
78
88
|
export { TrezorWalletAdapter, createTrezorAdapter } from './trezor'
|
|
79
89
|
|