@sip-protocol/sdk 0.3.1 → 0.4.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.
Files changed (49) hide show
  1. package/dist/browser.d.mts +2 -2
  2. package/dist/browser.d.ts +2 -2
  3. package/dist/browser.js +1028 -146
  4. package/dist/browser.mjs +49 -1
  5. package/dist/chunk-AOZIY3GU.mjs +12995 -0
  6. package/dist/chunk-BCLIX5T2.mjs +12940 -0
  7. package/dist/chunk-EU4UEWWG.mjs +12164 -0
  8. package/dist/chunk-FKXPHKYD.mjs +12955 -0
  9. package/dist/chunk-OPQ2GQIO.mjs +13013 -0
  10. package/dist/index-BcWNakUD.d.ts +7990 -0
  11. package/dist/index-BsKY3Hr0.d.mts +7990 -0
  12. package/dist/index.d.mts +2 -2
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +999 -117
  15. package/dist/index.mjs +49 -1
  16. package/package.json +2 -1
  17. package/src/adapters/near-intents.ts +8 -0
  18. package/src/bitcoin/index.ts +51 -0
  19. package/src/bitcoin/silent-payments.ts +865 -0
  20. package/src/bitcoin/taproot.ts +590 -0
  21. package/src/cosmos/ibc-stealth.ts +825 -0
  22. package/src/cosmos/index.ts +83 -0
  23. package/src/cosmos/stealth.ts +487 -0
  24. package/src/index.ts +51 -0
  25. package/src/move/aptos.ts +369 -0
  26. package/src/move/index.ts +35 -0
  27. package/src/move/sui.ts +367 -0
  28. package/src/oracle/types.ts +8 -0
  29. package/src/settlement/backends/direct-chain.ts +8 -0
  30. package/src/settlement/backends/near-intents.ts +11 -0
  31. package/src/stealth.ts +3 -3
  32. package/src/validation.ts +42 -1
  33. package/src/wallet/aptos/adapter.ts +422 -0
  34. package/src/wallet/aptos/index.ts +10 -0
  35. package/src/wallet/aptos/mock.ts +410 -0
  36. package/src/wallet/aptos/types.ts +278 -0
  37. package/src/wallet/bitcoin/adapter.ts +470 -0
  38. package/src/wallet/bitcoin/index.ts +38 -0
  39. package/src/wallet/bitcoin/mock.ts +516 -0
  40. package/src/wallet/bitcoin/types.ts +274 -0
  41. package/src/wallet/cosmos/adapter.ts +484 -0
  42. package/src/wallet/cosmos/index.ts +63 -0
  43. package/src/wallet/cosmos/mock.ts +596 -0
  44. package/src/wallet/cosmos/types.ts +462 -0
  45. package/src/wallet/index.ts +127 -0
  46. package/src/wallet/sui/adapter.ts +471 -0
  47. package/src/wallet/sui/index.ts +10 -0
  48. package/src/wallet/sui/mock.ts +439 -0
  49. package/src/wallet/sui/types.ts +245 -0
@@ -0,0 +1,470 @@
1
+ /**
2
+ * Bitcoin Wallet Adapter
3
+ *
4
+ * Implementation of WalletAdapter for Bitcoin.
5
+ * Supports Unisat, Xverse, Leather, and OKX wallets.
6
+ */
7
+
8
+ import type {
9
+ HexString,
10
+ Asset,
11
+ Signature,
12
+ UnsignedTransaction,
13
+ SignedTransaction,
14
+ TransactionReceipt,
15
+ } from '@sip-protocol/types'
16
+ import { WalletErrorCode } from '@sip-protocol/types'
17
+ import { BaseWalletAdapter } from '../base-adapter'
18
+ import { WalletError } from '../errors'
19
+ import type {
20
+ UnisatAPI,
21
+ BitcoinAdapterConfig,
22
+ BitcoinWalletName,
23
+ BitcoinNetwork,
24
+ BitcoinAddress,
25
+ BitcoinBalance,
26
+ SignPsbtOptions,
27
+ } from './types'
28
+ import {
29
+ getBitcoinProvider,
30
+ bitcoinPublicKeyToHex,
31
+ isValidTaprootAddress,
32
+ } from './types'
33
+
34
+ /**
35
+ * Bitcoin wallet adapter
36
+ *
37
+ * Provides SIP-compatible wallet interface for Bitcoin.
38
+ * Works with Unisat, OKX, Xverse, and Leather wallets.
39
+ *
40
+ * @example Browser usage with Unisat
41
+ * ```typescript
42
+ * const wallet = new BitcoinWalletAdapter({ wallet: 'unisat' })
43
+ * await wallet.connect()
44
+ *
45
+ * const balance = await wallet.getBalance()
46
+ * console.log(`Balance: ${balance} sats`)
47
+ *
48
+ * // Sign a message
49
+ * const sig = await wallet.signMessage(new TextEncoder().encode('Hello Bitcoin'))
50
+ * ```
51
+ *
52
+ * @example With custom network
53
+ * ```typescript
54
+ * const wallet = new BitcoinWalletAdapter({
55
+ * wallet: 'unisat',
56
+ * network: 'testnet',
57
+ * })
58
+ * ```
59
+ */
60
+ export class BitcoinWalletAdapter extends BaseWalletAdapter {
61
+ readonly chain = 'bitcoin' as const
62
+ readonly name: string
63
+
64
+ private provider: UnisatAPI | undefined
65
+ private walletName: BitcoinWalletName
66
+ private network: BitcoinNetwork
67
+
68
+ constructor(config: BitcoinAdapterConfig = {}) {
69
+ super()
70
+ this.walletName = config.wallet ?? 'unisat'
71
+ this.name = `bitcoin-${this.walletName}`
72
+ this.network = config.network ?? 'livenet'
73
+
74
+ // Allow injecting provider for testing
75
+ if (config.provider) {
76
+ this.provider = config.provider
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Get the current Bitcoin network
82
+ */
83
+ getNetwork(): BitcoinNetwork {
84
+ return this.network
85
+ }
86
+
87
+ /**
88
+ * Set the Bitcoin network
89
+ */
90
+ async setNetwork(network: BitcoinNetwork): Promise<void> {
91
+ if (!this.provider) {
92
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
93
+ }
94
+
95
+ try {
96
+ await this.provider.switchNetwork(network)
97
+ this.network = network
98
+ } catch (error) {
99
+ const message = error instanceof Error ? error.message : 'Failed to switch network'
100
+ throw new WalletError(message, WalletErrorCode.UNKNOWN, { cause: error as Error })
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Connect to the wallet
106
+ */
107
+ async connect(): Promise<void> {
108
+ this._connectionState = 'connecting'
109
+
110
+ try {
111
+ // Get provider if not already set
112
+ if (!this.provider) {
113
+ this.provider = getBitcoinProvider(this.walletName)
114
+ }
115
+
116
+ if (!this.provider) {
117
+ this.setError(
118
+ WalletErrorCode.NOT_INSTALLED,
119
+ `${this.walletName} wallet is not installed`
120
+ )
121
+ throw new WalletError(
122
+ `${this.walletName} wallet is not installed`,
123
+ WalletErrorCode.NOT_INSTALLED
124
+ )
125
+ }
126
+
127
+ // Request account access
128
+ const accounts = await this.provider.requestAccounts()
129
+
130
+ if (!accounts || accounts.length === 0) {
131
+ throw new WalletError(
132
+ 'No accounts returned from wallet',
133
+ WalletErrorCode.CONNECTION_FAILED
134
+ )
135
+ }
136
+
137
+ // Get the first account (Taproot address)
138
+ const address = accounts[0]
139
+
140
+ // Validate Taproot address format
141
+ if (!isValidTaprootAddress(address, this.network)) {
142
+ throw new WalletError(
143
+ `Invalid Taproot address format: ${address}`,
144
+ WalletErrorCode.CONNECTION_FAILED
145
+ )
146
+ }
147
+
148
+ // Get public key
149
+ const publicKey = await this.provider.getPublicKey()
150
+ const hexPubKey = bitcoinPublicKeyToHex(publicKey)
151
+
152
+ // Update state
153
+ this.setConnected(address, hexPubKey)
154
+ } catch (error) {
155
+ const message = error instanceof Error ? error.message : 'Connection failed'
156
+
157
+ // Check if user rejected
158
+ if (message.includes('User rejected') || message.includes('rejected') || message.includes('cancelled')) {
159
+ this.setError(WalletErrorCode.CONNECTION_REJECTED, message)
160
+ throw new WalletError(message, WalletErrorCode.CONNECTION_REJECTED)
161
+ }
162
+
163
+ this.setError(WalletErrorCode.CONNECTION_FAILED, message)
164
+ throw error instanceof WalletError
165
+ ? error
166
+ : new WalletError(message, WalletErrorCode.CONNECTION_FAILED, { cause: error as Error })
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Disconnect from the wallet
172
+ */
173
+ async disconnect(): Promise<void> {
174
+ this.setDisconnected('User disconnected')
175
+ // Note: Unisat doesn't have a disconnect method
176
+ // The wallet remains accessible but we clear our state
177
+ }
178
+
179
+ /**
180
+ * Sign a message
181
+ *
182
+ * Uses BIP-322 simple signature format by default
183
+ */
184
+ async signMessage(message: Uint8Array): Promise<Signature> {
185
+ this.requireConnected()
186
+
187
+ if (!this.provider) {
188
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
189
+ }
190
+
191
+ try {
192
+ // Convert message to string (Unisat expects string)
193
+ const messageStr = new TextDecoder().decode(message)
194
+
195
+ // Sign using BIP-322 simple format (preferred for Taproot)
196
+ const signature = await this.provider.signMessage(messageStr, 'bip322-simple')
197
+
198
+ // Signature is returned as base64, convert to hex
199
+ const sigBytes = Buffer.from(signature, 'base64')
200
+
201
+ return {
202
+ signature: ('0x' + sigBytes.toString('hex')) as HexString,
203
+ publicKey: this._publicKey as HexString,
204
+ }
205
+ } catch (error) {
206
+ const message = error instanceof Error ? error.message : 'Signing failed'
207
+
208
+ if (message.includes('User rejected') || message.includes('rejected') || message.includes('cancelled')) {
209
+ throw new WalletError(message, WalletErrorCode.SIGNING_REJECTED)
210
+ }
211
+
212
+ throw new WalletError(message, WalletErrorCode.SIGNING_FAILED, {
213
+ cause: error as Error,
214
+ })
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Sign a PSBT (Partially Signed Bitcoin Transaction)
220
+ *
221
+ * The transaction data should be a PSBT in hex format
222
+ */
223
+ async signTransaction(tx: UnsignedTransaction): Promise<SignedTransaction> {
224
+ this.requireConnected()
225
+
226
+ if (!this.provider) {
227
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
228
+ }
229
+
230
+ try {
231
+ // Extract PSBT from transaction data
232
+ const psbtHex = tx.data as string
233
+ const options = tx.metadata?.signPsbtOptions as SignPsbtOptions | undefined
234
+
235
+ // Sign PSBT
236
+ const signedPsbt = await this.provider.signPsbt(psbtHex, options)
237
+
238
+ return {
239
+ unsigned: tx,
240
+ signatures: [
241
+ {
242
+ signature: ('0x' + signedPsbt) as HexString,
243
+ publicKey: this._publicKey as HexString,
244
+ },
245
+ ],
246
+ serialized: ('0x' + signedPsbt) as HexString,
247
+ }
248
+ } catch (error) {
249
+ const message = error instanceof Error ? error.message : 'Signing failed'
250
+
251
+ if (message.includes('User rejected') || message.includes('rejected') || message.includes('cancelled')) {
252
+ throw new WalletError(message, WalletErrorCode.SIGNING_REJECTED)
253
+ }
254
+
255
+ throw new WalletError(message, WalletErrorCode.SIGNING_FAILED, {
256
+ cause: error as Error,
257
+ })
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Sign and send a PSBT
263
+ *
264
+ * Note: This signs the PSBT and broadcasts the finalized transaction
265
+ */
266
+ async signAndSendTransaction(tx: UnsignedTransaction): Promise<TransactionReceipt> {
267
+ this.requireConnected()
268
+
269
+ if (!this.provider) {
270
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
271
+ }
272
+
273
+ try {
274
+ // First, sign the transaction
275
+ const signed = await this.signTransaction(tx)
276
+
277
+ // Extract the signed PSBT hex (without 0x prefix)
278
+ const signedPsbt = signed.serialized.slice(2)
279
+
280
+ // If PSBT is not finalized, we need to finalize it
281
+ // For now, assume it's finalized (autoFinalized: true in options)
282
+ // TODO: Add PSBT finalization logic here
283
+
284
+ // Broadcast the transaction
285
+ const txid = await this.provider.pushTx(signedPsbt)
286
+
287
+ return {
288
+ txHash: ('0x' + txid) as HexString,
289
+ status: 'pending', // Transaction is broadcast but not confirmed
290
+ timestamp: Date.now(),
291
+ }
292
+ } catch (error) {
293
+ const message = error instanceof Error ? error.message : 'Transaction failed'
294
+
295
+ if (message.includes('User rejected') || message.includes('rejected') || message.includes('cancelled')) {
296
+ throw new WalletError(message, WalletErrorCode.TRANSACTION_REJECTED)
297
+ }
298
+
299
+ if (message.includes('insufficient') || message.includes('Insufficient')) {
300
+ throw new WalletError(message, WalletErrorCode.INSUFFICIENT_FUNDS)
301
+ }
302
+
303
+ throw new WalletError(message, WalletErrorCode.TRANSACTION_FAILED, {
304
+ cause: error as Error,
305
+ })
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Get native BTC balance
311
+ */
312
+ async getBalance(): Promise<bigint> {
313
+ this.requireConnected()
314
+
315
+ if (!this.provider) {
316
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
317
+ }
318
+
319
+ try {
320
+ const balance = await this.provider.getBalance()
321
+ return BigInt(balance.total)
322
+ } catch (error) {
323
+ throw new WalletError(
324
+ 'Failed to get balance',
325
+ WalletErrorCode.UNKNOWN,
326
+ { cause: error as Error }
327
+ )
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Get token balance
333
+ *
334
+ * For Bitcoin, this would return balance of inscriptions or BRC-20 tokens
335
+ * Not implemented yet - returns 0
336
+ */
337
+ async getTokenBalance(asset: Asset): Promise<bigint> {
338
+ this.requireConnected()
339
+
340
+ if (asset.chain !== 'bitcoin') {
341
+ throw new WalletError(
342
+ `Asset chain ${asset.chain} not supported by Bitcoin adapter`,
343
+ WalletErrorCode.UNSUPPORTED_CHAIN
344
+ )
345
+ }
346
+
347
+ // TODO: Implement BRC-20 token balance query
348
+ // For now, return 0
349
+ return 0n
350
+ }
351
+
352
+ /**
353
+ * Get Bitcoin addresses
354
+ *
355
+ * Returns the current Taproot address with metadata
356
+ */
357
+ async getAddresses(): Promise<BitcoinAddress[]> {
358
+ this.requireConnected()
359
+
360
+ if (!this.provider) {
361
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
362
+ }
363
+
364
+ try {
365
+ const accounts = await this.provider.getAccounts()
366
+ const publicKey = await this.provider.getPublicKey()
367
+
368
+ return accounts.map((address) => ({
369
+ address,
370
+ publicKey,
371
+ type: 'p2tr' as const, // Unisat uses Taproot by default
372
+ }))
373
+ } catch (error) {
374
+ throw new WalletError(
375
+ 'Failed to get addresses',
376
+ WalletErrorCode.UNKNOWN,
377
+ { cause: error as Error }
378
+ )
379
+ }
380
+ }
381
+
382
+ /**
383
+ * Get detailed balance information
384
+ */
385
+ async getBalanceDetails(): Promise<BitcoinBalance> {
386
+ this.requireConnected()
387
+
388
+ if (!this.provider) {
389
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
390
+ }
391
+
392
+ try {
393
+ const balance = await this.provider.getBalance()
394
+ return {
395
+ confirmed: BigInt(balance.confirmed),
396
+ unconfirmed: BigInt(balance.unconfirmed),
397
+ total: BigInt(balance.total),
398
+ }
399
+ } catch (error) {
400
+ throw new WalletError(
401
+ 'Failed to get balance details',
402
+ WalletErrorCode.UNKNOWN,
403
+ { cause: error as Error }
404
+ )
405
+ }
406
+ }
407
+
408
+ /**
409
+ * Sign a PSBT directly
410
+ *
411
+ * Bitcoin-specific method for PSBT signing with options
412
+ */
413
+ async signPsbt(psbtHex: string, options?: SignPsbtOptions): Promise<string> {
414
+ this.requireConnected()
415
+
416
+ if (!this.provider) {
417
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
418
+ }
419
+
420
+ try {
421
+ return await this.provider.signPsbt(psbtHex, options)
422
+ } catch (error) {
423
+ const message = error instanceof Error ? error.message : 'PSBT signing failed'
424
+
425
+ if (message.includes('User rejected') || message.includes('rejected') || message.includes('cancelled')) {
426
+ throw new WalletError(message, WalletErrorCode.SIGNING_REJECTED)
427
+ }
428
+
429
+ throw new WalletError(message, WalletErrorCode.SIGNING_FAILED, {
430
+ cause: error as Error,
431
+ })
432
+ }
433
+ }
434
+
435
+ /**
436
+ * Push a raw transaction to the network
437
+ *
438
+ * Bitcoin-specific method for broadcasting transactions
439
+ */
440
+ async pushTx(rawTx: string): Promise<string> {
441
+ this.requireConnected()
442
+
443
+ if (!this.provider) {
444
+ throw new WalletError('Provider not available', WalletErrorCode.NOT_CONNECTED)
445
+ }
446
+
447
+ try {
448
+ return await this.provider.pushTx(rawTx)
449
+ } catch (error) {
450
+ const message = error instanceof Error ? error.message : 'Transaction broadcast failed'
451
+
452
+ if (message.includes('insufficient') || message.includes('Insufficient')) {
453
+ throw new WalletError(message, WalletErrorCode.INSUFFICIENT_FUNDS)
454
+ }
455
+
456
+ throw new WalletError(message, WalletErrorCode.TRANSACTION_FAILED, {
457
+ cause: error as Error,
458
+ })
459
+ }
460
+ }
461
+ }
462
+
463
+ /**
464
+ * Create a Bitcoin wallet adapter with default configuration
465
+ */
466
+ export function createBitcoinAdapter(
467
+ config: BitcoinAdapterConfig = {}
468
+ ): BitcoinWalletAdapter {
469
+ return new BitcoinWalletAdapter(config)
470
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Bitcoin Wallet Module
3
+ *
4
+ * Bitcoin wallet adapter for SIP Protocol.
5
+ * Supports Unisat, Xverse, Leather, and OKX wallets.
6
+ */
7
+
8
+ // Adapter
9
+ export { BitcoinWalletAdapter, createBitcoinAdapter } from './adapter'
10
+
11
+ // Mock adapter
12
+ export {
13
+ MockBitcoinAdapter,
14
+ createMockBitcoinAdapter,
15
+ createMockBitcoinProvider,
16
+ type MockBitcoinAdapterConfig,
17
+ } from './mock'
18
+
19
+ // Types and utilities
20
+ export {
21
+ getBitcoinProvider,
22
+ detectBitcoinWallets,
23
+ bitcoinAddressToHex,
24
+ bitcoinPublicKeyToHex,
25
+ isValidTaprootAddress,
26
+ } from './types'
27
+
28
+ export type {
29
+ BitcoinAddressType,
30
+ BitcoinNetwork,
31
+ BitcoinAddress,
32
+ BitcoinBalance,
33
+ SignPsbtOptions,
34
+ ToSignInput,
35
+ BitcoinWalletName,
36
+ BitcoinAdapterConfig,
37
+ UnisatAPI,
38
+ } from './types'