walletpair-sdk 1.0.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/README.md +415 -0
- package/dist/ble/framing.d.ts +23 -0
- package/dist/ble/framing.d.ts.map +1 -0
- package/dist/ble/framing.js +83 -0
- package/dist/ble/framing.js.map +1 -0
- package/dist/ble/index.d.ts +9 -0
- package/dist/ble/index.d.ts.map +1 -0
- package/dist/ble/index.js +9 -0
- package/dist/ble/index.js.map +1 -0
- package/dist/ble/web-ble-transport.d.ts +29 -0
- package/dist/ble/web-ble-transport.d.ts.map +1 -0
- package/dist/ble/web-ble-transport.js +93 -0
- package/dist/ble/web-ble-transport.js.map +1 -0
- package/dist/crypto.d.ts +102 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +279 -0
- package/dist/crypto.js.map +1 -0
- package/dist/dapp-session.d.ts +106 -0
- package/dist/dapp-session.d.ts.map +1 -0
- package/dist/dapp-session.js +918 -0
- package/dist/dapp-session.js.map +1 -0
- package/dist/emitter.d.ts +16 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +41 -0
- package/dist/emitter.js.map +1 -0
- package/dist/evm/eip1193.d.ts +83 -0
- package/dist/evm/eip1193.d.ts.map +1 -0
- package/dist/evm/eip1193.js +270 -0
- package/dist/evm/eip1193.js.map +1 -0
- package/dist/evm/index.d.ts +8 -0
- package/dist/evm/index.d.ts.map +1 -0
- package/dist/evm/index.js +8 -0
- package/dist/evm/index.js.map +1 -0
- package/dist/evm/wagmi.d.ts +118 -0
- package/dist/evm/wagmi.d.ts.map +1 -0
- package/dist/evm/wagmi.js +205 -0
- package/dist/evm/wagmi.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +225 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +31 -0
- package/dist/types.js.map +1 -0
- package/dist/wallet-session.d.ts +107 -0
- package/dist/wallet-session.d.ts.map +1 -0
- package/dist/wallet-session.js +794 -0
- package/dist/wallet-session.js.map +1 -0
- package/dist/ws-transport.d.ts +29 -0
- package/dist/ws-transport.d.ts.map +1 -0
- package/dist/ws-transport.js +79 -0
- package/dist/ws-transport.js.map +1 -0
- package/package.json +55 -0
- package/src/__tests__/adversarial/crypto-attacks.test.ts +557 -0
- package/src/__tests__/adversarial/malicious-dapp.test.ts +505 -0
- package/src/__tests__/adversarial/malicious-relay.test.ts +528 -0
- package/src/__tests__/adversarial/malicious-wallet.test.ts +467 -0
- package/src/__tests__/spec-compliance/canonical-json.test.ts +227 -0
- package/src/__tests__/spec-compliance/crypto-vectors.test.ts +321 -0
- package/src/__tests__/spec-compliance/message-format.test.ts +356 -0
- package/src/__tests__/spec-compliance/sequence-numbers.test.ts +300 -0
- package/src/__tests__/spec-compliance/state-machine.test.ts +364 -0
- package/src/ble/framing.test.ts +196 -0
- package/src/ble/framing.ts +100 -0
- package/src/ble/index.ts +18 -0
- package/src/ble/web-ble-transport.test.ts +192 -0
- package/src/ble/web-ble-transport.ts +116 -0
- package/src/ble/web-bluetooth.d.ts +47 -0
- package/src/canonical-json.test.ts +612 -0
- package/src/crypto-directional.test.ts +263 -0
- package/src/crypto-hardening.test.ts +529 -0
- package/src/crypto.test.ts +635 -0
- package/src/crypto.ts +405 -0
- package/src/dapp-session.test.ts +647 -0
- package/src/dapp-session.ts +1004 -0
- package/src/emitter.test.ts +169 -0
- package/src/emitter.ts +45 -0
- package/src/evm/eip1193.test.ts +365 -0
- package/src/evm/eip1193.ts +346 -0
- package/src/evm/index.ts +19 -0
- package/src/evm/wagmi.test.ts +396 -0
- package/src/evm/wagmi.ts +321 -0
- package/src/index.ts +86 -0
- package/src/integration.test.ts +385 -0
- package/src/security.test.ts +430 -0
- package/src/sequence-validation.test.ts +1185 -0
- package/src/test-helpers.ts +216 -0
- package/src/types.test.ts +82 -0
- package/src/types.ts +305 -0
- package/src/wallet-session.test.ts +683 -0
- package/src/wallet-session.ts +922 -0
- package/src/ws-transport.test.ts +231 -0
- package/src/ws-transport.ts +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-present
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
# walletpair-sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the [WalletPair Protocol](../walletpair-protocol-v1.md) -- connect dApps and wallets with end-to-end encrypted, relay-based or BLE communication.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Chain-agnostic core** -- uses [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) chain IDs (`eip155:1`, `solana:mainnet`), ready for multi-chain
|
|
8
|
+
- **EVM support** -- EIP-1193 provider + wagmi connector (under `walletpair-sdk/evm`)
|
|
9
|
+
- **Transport-agnostic** -- WebSocket relay and Web Bluetooth (BLE) transports included, pluggable `Transport` interface for custom transports
|
|
10
|
+
- **End-to-end encrypted** -- X25519 key exchange + ChaCha20-Poly1305 AEAD, relay never sees payload content
|
|
11
|
+
- **Session snapshots** -- `serialize()` / `restore()` for controlled reconnect flows; production crash recovery requires write-ahead counter persistence
|
|
12
|
+
- **Zero native dependencies** -- pure JS crypto via [noble](https://github.com/paulmillr/noble-curves) libraries
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
walletpair-sdk
|
|
18
|
+
├── Core (chain-agnostic)
|
|
19
|
+
│ ├── crypto.ts X25519, HKDF, ChaCha20-Poly1305, seal/unseal
|
|
20
|
+
│ ├── types.ts Transport interface, CAIP-2 helpers, protocol messages
|
|
21
|
+
│ ├── emitter.ts Typed event emitter
|
|
22
|
+
│ ├── ws-transport.ts WebSocket transport (browser/Node/Deno/Bun)
|
|
23
|
+
│ ├── dapp-session.ts DApp-side session state machine
|
|
24
|
+
│ └── wallet-session.ts Wallet-side session state machine
|
|
25
|
+
├── BLE (walletpair-sdk/ble)
|
|
26
|
+
│ ├── framing.ts BLE message fragmentation/reassembly (Section 19.5)
|
|
27
|
+
│ └── web-ble-transport.ts Web Bluetooth Central transport (runtime detection)
|
|
28
|
+
└── EVM (walletpair-sdk/evm)
|
|
29
|
+
├── eip1193.ts EIP-1193 provider (maps eth_ methods to WalletPair)
|
|
30
|
+
└── wagmi.ts wagmi connector factory
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Data Flow
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
┌──────────┐ ┌──────────┐
|
|
37
|
+
│ dApp │ │ Wallet │
|
|
38
|
+
│ │ │ │
|
|
39
|
+
│ DAppSession WalletSession │
|
|
40
|
+
│ │ │ │ │ │
|
|
41
|
+
│ ▼ │ ┌──────────────┐ │ ▼ │
|
|
42
|
+
│ Transport├────►│ Relay / BLE │◄────────┤Transport │
|
|
43
|
+
│ │ └──────────────┘ │ │
|
|
44
|
+
└──────────┘ (sees only routing └──────────┘
|
|
45
|
+
metadata -- payloads
|
|
46
|
+
are E2E encrypted)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install walletpair-sdk
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### DApp Side (Vanilla JS/TS)
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { DAppSession, WebSocketTransport } from 'walletpair-sdk'
|
|
61
|
+
|
|
62
|
+
const transport = new WebSocketTransport('wss://relay.walletpair.org/v1')
|
|
63
|
+
const session = new DAppSession({
|
|
64
|
+
transport,
|
|
65
|
+
meta: { name: 'My dApp', description: 'Example dApp', url: 'https://example.com', icon: 'https://example.com/icon.png' },
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// 1. Create pairing -- display the URI as a QR code
|
|
69
|
+
const uri = await session.createPairing()
|
|
70
|
+
console.log('Scan this:', uri)
|
|
71
|
+
|
|
72
|
+
// 2. When wallet joins, show session fingerprint for visual verification
|
|
73
|
+
// (DApp auto-accepts after sealed_join verification)
|
|
74
|
+
session.on('sessionFingerprint', (fingerprint) => {
|
|
75
|
+
console.log('Session fingerprint:', fingerprint)
|
|
76
|
+
// Display to user so they can verify it matches wallet display
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// 3. Once connected, send requests
|
|
80
|
+
session.on('phase', async (phase) => {
|
|
81
|
+
if (phase === 'connected') {
|
|
82
|
+
const accounts = await session.request('wallet_getAccounts')
|
|
83
|
+
console.log('Accounts:', accounts)
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// 4. Listen for wallet events
|
|
88
|
+
session.on('event', ({ event, data }) => {
|
|
89
|
+
console.log(`Event: ${event}`, data)
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Wallet Side (JS/TS / React Native)
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { WalletSession, WebSocketTransport } from 'walletpair-sdk'
|
|
97
|
+
|
|
98
|
+
const transport = new WebSocketTransport('wss://relay.walletpair.org/v1')
|
|
99
|
+
const session = new WalletSession({
|
|
100
|
+
transport,
|
|
101
|
+
capabilities: {
|
|
102
|
+
methods: ['wallet_getAccounts', 'wallet_signMessage'],
|
|
103
|
+
events: ['accountsChanged', 'chainChanged'],
|
|
104
|
+
chains: ['eip155:1', 'eip155:137'],
|
|
105
|
+
},
|
|
106
|
+
meta: { name: 'My Wallet', description: 'Example Wallet', url: 'https://mywallet.app', icon: 'https://mywallet.app/icon.png' },
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// 1. Join from pairing URI (scanned from QR code)
|
|
110
|
+
const fingerprint = await session.joinFromUri(uri)
|
|
111
|
+
console.log('Session fingerprint:', fingerprint) // show to user for visual verification
|
|
112
|
+
|
|
113
|
+
// 2. Handle incoming requests
|
|
114
|
+
session.on('request', ({ id, method, params }) => {
|
|
115
|
+
switch (method) {
|
|
116
|
+
case 'wallet_getAccounts':
|
|
117
|
+
session.approve(id, ['0xYourAddress'])
|
|
118
|
+
break
|
|
119
|
+
case 'wallet_signMessage':
|
|
120
|
+
// Sign and return, or reject
|
|
121
|
+
session.approve(id, { signature: '0x...' })
|
|
122
|
+
// session.reject(id, 'user_rejected', 'User declined')
|
|
123
|
+
break
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// 3. Push events to dApp
|
|
128
|
+
session.pushEvent('accountsChanged', { accounts: ['0xNewAddress'] })
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### EVM dApp with EIP-1193 Provider
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { DAppSession, WebSocketTransport } from 'walletpair-sdk'
|
|
135
|
+
import { WalletPairProvider } from 'walletpair-sdk/evm'
|
|
136
|
+
|
|
137
|
+
const transport = new WebSocketTransport('wss://relay.walletpair.org/v1')
|
|
138
|
+
const session = new DAppSession({
|
|
139
|
+
transport,
|
|
140
|
+
meta: { name: 'My dApp', description: 'Example dApp', url: 'https://example.com', icon: 'https://example.com/icon.png' },
|
|
141
|
+
})
|
|
142
|
+
const provider = new WalletPairProvider({ session, chainId: 1 })
|
|
143
|
+
|
|
144
|
+
// Use like any EIP-1193 provider
|
|
145
|
+
const accounts = await provider.request({ method: 'eth_requestAccounts' })
|
|
146
|
+
const chainId = await provider.request({ method: 'eth_chainId' })
|
|
147
|
+
|
|
148
|
+
// Standard EIP-1193 events
|
|
149
|
+
provider.on('accountsChanged', (accounts) => { /* ... */ })
|
|
150
|
+
provider.on('chainChanged', (chainId) => { /* ... */ })
|
|
151
|
+
provider.on('disconnect', (error) => { /* ... */ })
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### EVM dApp with wagmi
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { walletPair } from 'walletpair-sdk/evm/wagmi'
|
|
158
|
+
import { createConfig, http } from 'wagmi'
|
|
159
|
+
import { mainnet, polygon } from 'wagmi/chains'
|
|
160
|
+
|
|
161
|
+
const config = createConfig({
|
|
162
|
+
chains: [mainnet, polygon],
|
|
163
|
+
connectors: [
|
|
164
|
+
walletPair({
|
|
165
|
+
relayUrl: 'wss://relay.walletpair.org/v1',
|
|
166
|
+
meta: { name: 'My dApp', description: 'Example dApp', url: 'https://example.com', icon: 'https://example.com/icon.png' },
|
|
167
|
+
onPairingUri: (uri) => {
|
|
168
|
+
// Display QR code with this URI
|
|
169
|
+
showQrCode(uri)
|
|
170
|
+
},
|
|
171
|
+
onSessionFingerprint: (fingerprint) => {
|
|
172
|
+
// Display session fingerprint for user visual verification
|
|
173
|
+
showSessionFingerprint(fingerprint)
|
|
174
|
+
},
|
|
175
|
+
}),
|
|
176
|
+
],
|
|
177
|
+
transports: {
|
|
178
|
+
[mainnet.id]: http(),
|
|
179
|
+
[polygon.id]: http(),
|
|
180
|
+
},
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### BLE Transport (Web Bluetooth)
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { DAppSession } from 'walletpair-sdk'
|
|
188
|
+
import { WebBleCentralTransport, isWebBleSupported } from 'walletpair-sdk/ble'
|
|
189
|
+
|
|
190
|
+
if (isWebBleSupported()) {
|
|
191
|
+
const transport = new WebBleCentralTransport()
|
|
192
|
+
const session = new DAppSession({
|
|
193
|
+
transport,
|
|
194
|
+
meta: { name: 'My dApp', description: 'Example dApp', url: 'https://example.com', icon: 'https://example.com/icon.png' },
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
// BLE pairing URI has no relay parameter
|
|
198
|
+
const uri = await session.createPairing()
|
|
199
|
+
// uri = "walletpair:?ch=...&pubkey=..."
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Session Snapshots
|
|
204
|
+
|
|
205
|
+
`serialize()` and `restore()` can be used in controlled reconnect flows,
|
|
206
|
+
but they are not enough for production crash recovery by themselves. The
|
|
207
|
+
protocol requires sequence counters to be persisted before every encrypted
|
|
208
|
+
send. A crash after sending but before saving a new snapshot can roll back a
|
|
209
|
+
counter and cause nonce reuse with the same traffic key.
|
|
210
|
+
|
|
211
|
+
For production, persist `{ traffic_keys, sendSeq, recvSeq }` with a
|
|
212
|
+
write-ahead store before each send, or disable reconnect after process/page
|
|
213
|
+
termination and require fresh pairing.
|
|
214
|
+
|
|
215
|
+
Demo-only page reload snapshot:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
// Save before unload
|
|
219
|
+
window.addEventListener('beforeunload', () => {
|
|
220
|
+
sessionStorage.setItem('wp', session.serialize())
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
// Restore on load
|
|
224
|
+
const saved = sessionStorage.getItem('wp')
|
|
225
|
+
if (saved && session.restore(saved)) {
|
|
226
|
+
await session.reconnect()
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## API Reference
|
|
231
|
+
|
|
232
|
+
### Core
|
|
233
|
+
|
|
234
|
+
#### `DAppSession`
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
new DAppSession({ transport, meta: { name, description, url, icon }, requestTimeout?, autoAccept? })
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
| Method | Description |
|
|
241
|
+
|--------|-------------|
|
|
242
|
+
| `createPairing(): Promise<string>` | Create channel, returns pairing URI for QR display |
|
|
243
|
+
| `acceptWallet()` | Accept wallet (called automatically after sealed_join verification) |
|
|
244
|
+
| `rejectWallet()` | Reject wallet pairing |
|
|
245
|
+
| `request<T>(method, params?): Promise<T>` | Send encrypted request, returns decrypted response |
|
|
246
|
+
| `ping()` | Send heartbeat ping |
|
|
247
|
+
| `close()` | Gracefully close session |
|
|
248
|
+
| `destroy()` | Close + remove all event listeners |
|
|
249
|
+
| `serialize(): string` | Serialize a session snapshot |
|
|
250
|
+
| `restore(json): boolean` | Restore a session snapshot |
|
|
251
|
+
| `reconnect(): Promise<void>` | Reconnect after restore |
|
|
252
|
+
|
|
253
|
+
**Events:**
|
|
254
|
+
|
|
255
|
+
| Event | Payload | Description |
|
|
256
|
+
|-------|---------|-------------|
|
|
257
|
+
| `phase` | `DAppPhase` | State machine transition |
|
|
258
|
+
| `pairingUri` | `string` | Pairing URI generated |
|
|
259
|
+
| `sessionFingerprint` | `string` | Session fingerprint for visual verification |
|
|
260
|
+
| `walletJoined` | `{ pubkey, capabilities?, meta }` | Wallet joined the channel |
|
|
261
|
+
| `response` | `{ id, ok, data }` | Response received |
|
|
262
|
+
| `event` | `{ event, data }` | Wallet pushed an event |
|
|
263
|
+
| `error` | `Error` | Error occurred |
|
|
264
|
+
|
|
265
|
+
**Phases:** `idle` -> `waiting` -> `pending_accept` -> `connected` -> `closed`
|
|
266
|
+
|
|
267
|
+
#### `WalletSession`
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
new WalletSession({ transport, capabilities, meta: { name, description, url, icon } })
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
| Method | Description |
|
|
274
|
+
|--------|-------------|
|
|
275
|
+
| `joinFromUri(uri): Promise<string>` | Join channel, returns session fingerprint |
|
|
276
|
+
| `approve(requestId, result)` | Approve request with encrypted result |
|
|
277
|
+
| `reject(requestId, code?, message?)` | Reject request with error |
|
|
278
|
+
| `pushEvent(event, data)` | Push event to dApp |
|
|
279
|
+
| `ping()` | Send heartbeat ping |
|
|
280
|
+
| `close()` | Gracefully close session |
|
|
281
|
+
| `destroy()` | Close + remove all event listeners |
|
|
282
|
+
| `serialize()` / `restore(json)` | Session snapshot/restore |
|
|
283
|
+
|
|
284
|
+
**Events:**
|
|
285
|
+
|
|
286
|
+
| Event | Payload | Description |
|
|
287
|
+
|-------|---------|-------------|
|
|
288
|
+
| `phase` | `WalletPhase` | State machine transition |
|
|
289
|
+
| `sessionFingerprint` | `string` | Session fingerprint for visual verification |
|
|
290
|
+
| `request` | `{ id, method, params }` | Incoming request from dApp |
|
|
291
|
+
| `error` | `Error` | Error occurred |
|
|
292
|
+
|
|
293
|
+
**Phases:** `idle` -> `waiting` -> `connected` -> `closed`
|
|
294
|
+
|
|
295
|
+
#### `WebSocketTransport`
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
new WebSocketTransport(url: string)
|
|
299
|
+
new WebSocketTransport({ url: string, protocols?: string[] })
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
#### Transport Interface
|
|
303
|
+
|
|
304
|
+
Implement this to create custom transports (e.g., for React Native BLE peripheral):
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
interface Transport {
|
|
308
|
+
readonly state: 'disconnected' | 'connecting' | 'connected'
|
|
309
|
+
send(msg: ProtocolMessage): void
|
|
310
|
+
connect(): Promise<void>
|
|
311
|
+
disconnect(): void
|
|
312
|
+
onMessage(handler: (msg: ProtocolMessage) => void): void
|
|
313
|
+
onClose(handler: () => void): void
|
|
314
|
+
onOpen(handler: () => void): void
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### CAIP-2 Chain ID Helpers
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
import { parseChainId, formatChainId, evmChainId, evmNumericChainId } from 'walletpair-sdk'
|
|
322
|
+
|
|
323
|
+
parseChainId('eip155:1') // { namespace: 'eip155', reference: '1' }
|
|
324
|
+
formatChainId('eip155', '137') // 'eip155:137'
|
|
325
|
+
evmChainId(1) // 'eip155:1'
|
|
326
|
+
evmNumericChainId('eip155:1') // 1
|
|
327
|
+
evmNumericChainId('solana:mainnet') // null
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### EVM
|
|
331
|
+
|
|
332
|
+
#### `WalletPairProvider` (EIP-1193)
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
import { WalletPairProvider } from 'walletpair-sdk/evm'
|
|
336
|
+
|
|
337
|
+
new WalletPairProvider({ session, chainId?, mapper? })
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Default method mapping:**
|
|
341
|
+
|
|
342
|
+
| EIP-1193 Method | WalletPair Method |
|
|
343
|
+
|----------------|-------------------|
|
|
344
|
+
| `eth_requestAccounts` | `wallet_getAccounts` |
|
|
345
|
+
| `eth_accounts` | `wallet_getAccounts` |
|
|
346
|
+
| `personal_sign` | `wallet_signMessage` |
|
|
347
|
+
| `eth_signTypedData_v4` | `wallet_signTypedData` |
|
|
348
|
+
| `eth_sendTransaction` | `wallet_signTransaction` |
|
|
349
|
+
| `wallet_switchEthereumChain` | `wallet_switchChain` |
|
|
350
|
+
| `wallet_addEthereumChain` | `wallet_addChain` |
|
|
351
|
+
| `eth_chainId` | Handled locally (returns cached chain ID) |
|
|
352
|
+
| `net_version` | Handled locally (returns cached chain ID) |
|
|
353
|
+
| Others | Passed through as-is |
|
|
354
|
+
|
|
355
|
+
Override with a custom `MethodMapper` for specialized behavior.
|
|
356
|
+
|
|
357
|
+
#### `walletPair()` (wagmi connector)
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
import { walletPair } from 'walletpair-sdk/evm/wagmi'
|
|
361
|
+
|
|
362
|
+
walletPair({
|
|
363
|
+
relayUrl: string, // WebSocket relay URL
|
|
364
|
+
meta: { name, description, url, icon }, // DApp metadata
|
|
365
|
+
requestTimeout?: number, // Request timeout in ms
|
|
366
|
+
onPairingUri?: (uri) => void, // QR code display callback
|
|
367
|
+
onSessionFingerprint?: (fingerprint) => void, // Session fingerprint display callback
|
|
368
|
+
})
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### BLE
|
|
372
|
+
|
|
373
|
+
```ts
|
|
374
|
+
import {
|
|
375
|
+
WebBleCentralTransport, // Web Bluetooth Central (dApp side)
|
|
376
|
+
isWebBleSupported, // Runtime availability check
|
|
377
|
+
frameMessage, // Low-level: split JSON into BLE frames
|
|
378
|
+
Defragmenter, // Low-level: reassemble BLE frames
|
|
379
|
+
BLE_SERVICE_UUID, // WalletPair BLE service UUID
|
|
380
|
+
BLE_WRITE_CHAR_UUID, // DApp -> Wallet characteristic
|
|
381
|
+
BLE_NOTIFY_CHAR_UUID, // Wallet -> DApp characteristic
|
|
382
|
+
} from 'walletpair-sdk/ble'
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Extending for New Chains
|
|
386
|
+
|
|
387
|
+
To add support for a new chain (e.g., Solana):
|
|
388
|
+
|
|
389
|
+
1. Create `src/solana/` directory
|
|
390
|
+
2. Implement a provider that maps Solana RPC methods to WalletPair requests
|
|
391
|
+
3. Add subpath export in `package.json`:
|
|
392
|
+
```json
|
|
393
|
+
{ "./solana": "./src/solana/index.ts" }
|
|
394
|
+
```
|
|
395
|
+
4. Wallet side: declare Solana chains in capabilities:
|
|
396
|
+
```ts
|
|
397
|
+
capabilities: {
|
|
398
|
+
methods: ['wallet_signTransaction', 'wallet_signMessage'],
|
|
399
|
+
chains: ['solana:mainnet', 'solana:devnet'],
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The core protocol is chain-agnostic -- `DAppSession.request()` and `WalletSession.approve()` work with any method/params structure.
|
|
404
|
+
|
|
405
|
+
## Security
|
|
406
|
+
|
|
407
|
+
- **E2E Encryption**: X25519 ECDH -> HKDF-SHA256 -> ChaCha20-Poly1305 AEAD
|
|
408
|
+
- **MITM Protection**: Session fingerprint derived from SHA256(prefix || channel_id || dapp_pubkey) for visual verification on both devices
|
|
409
|
+
- **Replay Protection**: Sequence-number-based nonces, monotonically increasing
|
|
410
|
+
- **Channel Isolation**: 256-bit random channel IDs
|
|
411
|
+
- **Zero Trust Relay**: Relay sees routing metadata only, never plaintext payloads
|
|
412
|
+
|
|
413
|
+
## License
|
|
414
|
+
|
|
415
|
+
MIT
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLE message framing per WalletPair Protocol Section 19.5.
|
|
3
|
+
*
|
|
4
|
+
* Frame format: [1 byte flags] [2 bytes total_length BE] [payload fragment]
|
|
5
|
+
*
|
|
6
|
+
* flags bit 0: first fragment
|
|
7
|
+
* flags bit 1: last fragment
|
|
8
|
+
*/
|
|
9
|
+
export declare const DEFAULT_FRAME_PAYLOAD = 509;
|
|
10
|
+
export declare const MIN_FRAME_PAYLOAD = 20;
|
|
11
|
+
export declare const BLE_SERVICE_UUID = "e3a10001-7770-4270-8000-000077700001";
|
|
12
|
+
export declare const BLE_WRITE_CHAR_UUID = "e3a10002-7770-4270-8000-000077700001";
|
|
13
|
+
export declare const BLE_NOTIFY_CHAR_UUID = "e3a10003-7770-4270-8000-000077700001";
|
|
14
|
+
/** Split a JSON string into BLE frames. */
|
|
15
|
+
export declare function frameMessage(jsonStr: string, maxPayload?: number): Uint8Array[];
|
|
16
|
+
/** Accumulates BLE frames and emits complete JSON strings. */
|
|
17
|
+
export declare class Defragmenter {
|
|
18
|
+
private buffer;
|
|
19
|
+
private offset;
|
|
20
|
+
push(data: Uint8Array): string | null;
|
|
21
|
+
reset(): void;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=framing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framing.d.ts","sourceRoot":"","sources":["../../src/ble/framing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,eAAO,MAAM,gBAAgB,yCAAyC,CAAC;AACvE,eAAO,MAAM,mBAAmB,yCAAyC,CAAC;AAC1E,eAAO,MAAM,oBAAoB,yCAAyC,CAAC;AAE3E,2CAA2C;AAC3C,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,SAAwB,GACjC,UAAU,EAAE,CA6Bd;AAED,8DAA8D;AAC9D,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAK;IAEnB,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IAoCrC,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLE message framing per WalletPair Protocol Section 19.5.
|
|
3
|
+
*
|
|
4
|
+
* Frame format: [1 byte flags] [2 bytes total_length BE] [payload fragment]
|
|
5
|
+
*
|
|
6
|
+
* flags bit 0: first fragment
|
|
7
|
+
* flags bit 1: last fragment
|
|
8
|
+
*/
|
|
9
|
+
const FLAG_FIRST = 0x01;
|
|
10
|
+
const FLAG_LAST = 0x02;
|
|
11
|
+
export const DEFAULT_FRAME_PAYLOAD = 509;
|
|
12
|
+
export const MIN_FRAME_PAYLOAD = 20;
|
|
13
|
+
export const BLE_SERVICE_UUID = 'e3a10001-7770-4270-8000-000077700001';
|
|
14
|
+
export const BLE_WRITE_CHAR_UUID = 'e3a10002-7770-4270-8000-000077700001';
|
|
15
|
+
export const BLE_NOTIFY_CHAR_UUID = 'e3a10003-7770-4270-8000-000077700001';
|
|
16
|
+
/** Split a JSON string into BLE frames. */
|
|
17
|
+
export function frameMessage(jsonStr, maxPayload = DEFAULT_FRAME_PAYLOAD) {
|
|
18
|
+
const payload = new TextEncoder().encode(jsonStr);
|
|
19
|
+
const frames = [];
|
|
20
|
+
if (payload.length === 0) {
|
|
21
|
+
const frame = new Uint8Array(3);
|
|
22
|
+
frame[0] = FLAG_FIRST | FLAG_LAST;
|
|
23
|
+
return [frame];
|
|
24
|
+
}
|
|
25
|
+
const chunkSize = Math.max(maxPayload, MIN_FRAME_PAYLOAD);
|
|
26
|
+
for (let offset = 0; offset < payload.length; offset += chunkSize) {
|
|
27
|
+
const isFirst = offset === 0;
|
|
28
|
+
const end = Math.min(offset + chunkSize, payload.length);
|
|
29
|
+
const isLast = end === payload.length;
|
|
30
|
+
const fragment = payload.subarray(offset, end);
|
|
31
|
+
const frame = new Uint8Array(3 + fragment.length);
|
|
32
|
+
frame[0] = (isFirst ? FLAG_FIRST : 0) | (isLast ? FLAG_LAST : 0);
|
|
33
|
+
if (isFirst) {
|
|
34
|
+
frame[1] = (payload.length >> 8) & 0xff;
|
|
35
|
+
frame[2] = payload.length & 0xff;
|
|
36
|
+
}
|
|
37
|
+
frame.set(fragment, 3);
|
|
38
|
+
frames.push(frame);
|
|
39
|
+
}
|
|
40
|
+
return frames;
|
|
41
|
+
}
|
|
42
|
+
/** Accumulates BLE frames and emits complete JSON strings. */
|
|
43
|
+
export class Defragmenter {
|
|
44
|
+
buffer = null;
|
|
45
|
+
offset = 0;
|
|
46
|
+
push(data) {
|
|
47
|
+
if (data.length < 3)
|
|
48
|
+
return null;
|
|
49
|
+
const flags = data[0];
|
|
50
|
+
const isFirst = !!(flags & FLAG_FIRST);
|
|
51
|
+
const isLast = !!(flags & FLAG_LAST);
|
|
52
|
+
const fragment = data.subarray(3);
|
|
53
|
+
if (isFirst) {
|
|
54
|
+
const totalLength = (data[1] << 8) | data[2];
|
|
55
|
+
this.buffer = new Uint8Array(totalLength || fragment.length);
|
|
56
|
+
this.offset = 0;
|
|
57
|
+
}
|
|
58
|
+
if (this.buffer) {
|
|
59
|
+
if (this.offset + fragment.length <= this.buffer.length) {
|
|
60
|
+
this.buffer.set(fragment, this.offset);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const grown = new Uint8Array(this.offset + fragment.length);
|
|
64
|
+
grown.set(this.buffer.subarray(0, this.offset));
|
|
65
|
+
grown.set(fragment, this.offset);
|
|
66
|
+
this.buffer = grown;
|
|
67
|
+
}
|
|
68
|
+
this.offset += fragment.length;
|
|
69
|
+
}
|
|
70
|
+
if (isLast && this.buffer) {
|
|
71
|
+
const result = new TextDecoder().decode(this.buffer.subarray(0, this.offset));
|
|
72
|
+
this.buffer = null;
|
|
73
|
+
this.offset = 0;
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
reset() {
|
|
79
|
+
this.buffer = null;
|
|
80
|
+
this.offset = 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=framing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framing.js","sourceRoot":"","sources":["../../src/ble/framing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLE transport exports.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports framing utilities and provides the Web Bluetooth Central transport.
|
|
5
|
+
* Safe to import on any platform — Web Bluetooth availability is checked at runtime.
|
|
6
|
+
*/
|
|
7
|
+
export { frameMessage, Defragmenter, DEFAULT_FRAME_PAYLOAD, MIN_FRAME_PAYLOAD, BLE_SERVICE_UUID, BLE_WRITE_CHAR_UUID, BLE_NOTIFY_CHAR_UUID, } from './framing.js';
|
|
8
|
+
export { WebBleCentralTransport, isWebBleSupported } from './web-ble-transport.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ble/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLE transport exports.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports framing utilities and provides the Web Bluetooth Central transport.
|
|
5
|
+
* Safe to import on any platform — Web Bluetooth availability is checked at runtime.
|
|
6
|
+
*/
|
|
7
|
+
export { frameMessage, Defragmenter, DEFAULT_FRAME_PAYLOAD, MIN_FRAME_PAYLOAD, BLE_SERVICE_UUID, BLE_WRITE_CHAR_UUID, BLE_NOTIFY_CHAR_UUID, } from './framing.js';
|
|
8
|
+
export { WebBleCentralTransport, isWebBleSupported } from './web-ble-transport.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ble/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Bluetooth Central transport for dApp side.
|
|
3
|
+
*
|
|
4
|
+
* The dApp acts as BLE Central and connects to the wallet's GATT Peripheral.
|
|
5
|
+
* Safe to import anywhere — checks Web Bluetooth availability at runtime.
|
|
6
|
+
*/
|
|
7
|
+
import type { Transport, TransportState, ProtocolMessage } from '../types.js';
|
|
8
|
+
export declare function isWebBleSupported(): boolean;
|
|
9
|
+
export declare class WebBleCentralTransport implements Transport {
|
|
10
|
+
state: TransportState;
|
|
11
|
+
private device;
|
|
12
|
+
private writeChar;
|
|
13
|
+
private notifyChar;
|
|
14
|
+
private defrag;
|
|
15
|
+
private mtuPayload;
|
|
16
|
+
private messageHandler;
|
|
17
|
+
private closeHandler;
|
|
18
|
+
private openHandler;
|
|
19
|
+
onMessage(handler: (msg: ProtocolMessage) => void): void;
|
|
20
|
+
onClose(handler: () => void): void;
|
|
21
|
+
onOpen(handler: () => void): void;
|
|
22
|
+
connect(): Promise<void>;
|
|
23
|
+
send(msg: ProtocolMessage): void;
|
|
24
|
+
disconnect(): void;
|
|
25
|
+
private onNotification;
|
|
26
|
+
private onDisconnect;
|
|
27
|
+
private cleanup;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=web-ble-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-ble-transport.d.ts","sourceRoot":"","sources":["../../src/ble/web-ble-transport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAS9E,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,qBAAa,sBAAuB,YAAW,SAAS;IACtD,KAAK,EAAE,cAAc,CAAkB;IAEvC,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,SAAS,CAAkD;IACnE,OAAO,CAAC,UAAU,CAAkD;IACpE,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,UAAU,CAAO;IAEzB,OAAO,CAAC,cAAc,CAAiD;IACvE,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,WAAW,CAA6B;IAEhD,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IACxD,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAClC,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAE3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B9B,IAAI,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAUhC,UAAU,IAAI,IAAI;IAOlB,OAAO,CAAC,cAAc,CAQpB;IAEF,OAAO,CAAC,YAAY,CAGlB;IAEF,OAAO,CAAC,OAAO;CAahB"}
|