@sip-protocol/sdk 0.3.2 → 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.
- package/dist/browser.d.mts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +1019 -146
- package/dist/browser.mjs +49 -1
- package/dist/chunk-AOZIY3GU.mjs +12995 -0
- package/dist/chunk-BCLIX5T2.mjs +12940 -0
- package/dist/chunk-FKXPHKYD.mjs +12955 -0
- package/dist/chunk-OPQ2GQIO.mjs +13013 -0
- package/dist/index-BcWNakUD.d.ts +7990 -0
- package/dist/index-BsKY3Hr0.d.mts +7990 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +990 -117
- package/dist/index.mjs +49 -1
- package/package.json +2 -1
- package/src/adapters/near-intents.ts +8 -0
- package/src/bitcoin/index.ts +51 -0
- package/src/bitcoin/silent-payments.ts +865 -0
- package/src/bitcoin/taproot.ts +590 -0
- package/src/cosmos/ibc-stealth.ts +825 -0
- package/src/cosmos/index.ts +83 -0
- package/src/cosmos/stealth.ts +487 -0
- package/src/index.ts +51 -0
- package/src/move/aptos.ts +369 -0
- package/src/move/index.ts +35 -0
- package/src/move/sui.ts +367 -0
- package/src/oracle/types.ts +8 -0
- package/src/settlement/backends/direct-chain.ts +8 -0
- package/src/stealth.ts +3 -3
- package/src/validation.ts +42 -1
- package/src/wallet/aptos/adapter.ts +422 -0
- package/src/wallet/aptos/index.ts +10 -0
- package/src/wallet/aptos/mock.ts +410 -0
- package/src/wallet/aptos/types.ts +278 -0
- package/src/wallet/bitcoin/adapter.ts +470 -0
- package/src/wallet/bitcoin/index.ts +38 -0
- package/src/wallet/bitcoin/mock.ts +516 -0
- package/src/wallet/bitcoin/types.ts +274 -0
- package/src/wallet/cosmos/adapter.ts +484 -0
- package/src/wallet/cosmos/index.ts +63 -0
- package/src/wallet/cosmos/mock.ts +596 -0
- package/src/wallet/cosmos/types.ts +462 -0
- package/src/wallet/index.ts +127 -0
- package/src/wallet/sui/adapter.ts +471 -0
- package/src/wallet/sui/index.ts +10 -0
- package/src/wallet/sui/mock.ts +439 -0
- package/src/wallet/sui/types.ts +245 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cosmos Chain Support
|
|
3
|
+
*
|
|
4
|
+
* Stealth address generation and IBC cross-chain transfers for Cosmos ecosystem.
|
|
5
|
+
*
|
|
6
|
+
* Supported chains:
|
|
7
|
+
* - Cosmos Hub (cosmos)
|
|
8
|
+
* - Osmosis (osmo)
|
|
9
|
+
* - Injective (inj)
|
|
10
|
+
* - Celestia (celestia)
|
|
11
|
+
* - Sei (sei)
|
|
12
|
+
* - dYdX (dydx)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import {
|
|
17
|
+
* CosmosStealthService,
|
|
18
|
+
* CosmosIBCStealthService,
|
|
19
|
+
* generateCosmosStealthAddress,
|
|
20
|
+
* createStealthIBCTransfer
|
|
21
|
+
* } from '@sip-protocol/sdk/cosmos'
|
|
22
|
+
*
|
|
23
|
+
* // Stealth addresses
|
|
24
|
+
* const service = new CosmosStealthService()
|
|
25
|
+
* const { metaAddress, spendingPrivateKey, viewingPrivateKey } =
|
|
26
|
+
* service.generateStealthMetaAddress('cosmos', 'My Wallet')
|
|
27
|
+
*
|
|
28
|
+
* // IBC stealth transfers
|
|
29
|
+
* const ibcService = new CosmosIBCStealthService()
|
|
30
|
+
* const transfer = ibcService.createStealthIBCTransfer({
|
|
31
|
+
* sourceChain: 'cosmos',
|
|
32
|
+
* destChain: 'osmosis',
|
|
33
|
+
* recipientMetaAddress: metaAddress,
|
|
34
|
+
* amount: 1000000n,
|
|
35
|
+
* denom: 'uatom'
|
|
36
|
+
* })
|
|
37
|
+
* console.log(transfer.stealthAddress) // "osmo1..."
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
// ─── Stealth Addresses ─────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
// Service class
|
|
45
|
+
CosmosStealthService,
|
|
46
|
+
|
|
47
|
+
// Standalone functions
|
|
48
|
+
generateCosmosStealthMetaAddress,
|
|
49
|
+
generateCosmosStealthAddress,
|
|
50
|
+
stealthKeyToCosmosAddress,
|
|
51
|
+
isValidCosmosAddress,
|
|
52
|
+
|
|
53
|
+
// Types
|
|
54
|
+
type CosmosChainId,
|
|
55
|
+
type CosmosStealthResult,
|
|
56
|
+
|
|
57
|
+
// Constants
|
|
58
|
+
CHAIN_PREFIXES,
|
|
59
|
+
} from './stealth'
|
|
60
|
+
|
|
61
|
+
// ─── IBC Stealth Transfers ─────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
// Service class
|
|
65
|
+
CosmosIBCStealthService,
|
|
66
|
+
|
|
67
|
+
// Standalone functions
|
|
68
|
+
createStealthIBCTransfer,
|
|
69
|
+
buildIBCMsgTransfer,
|
|
70
|
+
scanIBCTransfers,
|
|
71
|
+
getIBCChannel,
|
|
72
|
+
|
|
73
|
+
// Types
|
|
74
|
+
type IBCChannel,
|
|
75
|
+
type StealthIBCTransferParams,
|
|
76
|
+
type StealthIBCTransfer,
|
|
77
|
+
type IBCMsgTransfer,
|
|
78
|
+
type IncomingIBCTransfer,
|
|
79
|
+
type ReceivedStealthTransfer,
|
|
80
|
+
|
|
81
|
+
// Constants
|
|
82
|
+
IBC_CHANNELS,
|
|
83
|
+
} from './ibc-stealth'
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cosmos Stealth Address Implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements stealth addresses for Cosmos chains (secp256k1-based chains like
|
|
5
|
+
* Cosmos Hub, Osmosis, Injective, Celestia, Sei, dYdX).
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - Reuses core secp256k1 stealth logic from ../stealth.ts
|
|
9
|
+
* - Adds Cosmos-specific bech32 address encoding
|
|
10
|
+
* - Supports multiple chain prefixes (cosmos, osmo, inj, celestia, sei, dydx)
|
|
11
|
+
*
|
|
12
|
+
* Address Format:
|
|
13
|
+
* - Cosmos addresses use bech32 encoding with chain-specific prefixes
|
|
14
|
+
* - Address derivation: bech32(prefix, ripemd160(sha256(compressed_pubkey)))
|
|
15
|
+
*
|
|
16
|
+
* @see https://docs.cosmos.network/main/learn/beginner/accounts
|
|
17
|
+
* @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki (bech32)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { secp256k1 } from '@noble/curves/secp256k1'
|
|
21
|
+
import { sha256 } from '@noble/hashes/sha256'
|
|
22
|
+
import { ripemd160 } from '@noble/hashes/ripemd160'
|
|
23
|
+
import { hexToBytes, bytesToHex } from '@noble/hashes/utils'
|
|
24
|
+
import { bech32 } from '@scure/base'
|
|
25
|
+
import {
|
|
26
|
+
generateStealthMetaAddress,
|
|
27
|
+
generateStealthAddress as generateSecp256k1StealthAddress,
|
|
28
|
+
deriveStealthPrivateKey as deriveSecp256k1StealthPrivateKey,
|
|
29
|
+
} from '../stealth'
|
|
30
|
+
import type {
|
|
31
|
+
StealthMetaAddress,
|
|
32
|
+
StealthAddress,
|
|
33
|
+
StealthAddressRecovery,
|
|
34
|
+
HexString,
|
|
35
|
+
} from '@sip-protocol/types'
|
|
36
|
+
import { ValidationError } from '../errors'
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Supported Cosmos chain identifiers
|
|
40
|
+
*/
|
|
41
|
+
export type CosmosChainId =
|
|
42
|
+
| 'cosmos'
|
|
43
|
+
| 'osmosis'
|
|
44
|
+
| 'injective'
|
|
45
|
+
| 'celestia'
|
|
46
|
+
| 'sei'
|
|
47
|
+
| 'dydx'
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Bech32 address prefixes for Cosmos chains
|
|
51
|
+
*/
|
|
52
|
+
export const CHAIN_PREFIXES: Record<CosmosChainId, string> = {
|
|
53
|
+
cosmos: 'cosmos',
|
|
54
|
+
osmosis: 'osmo',
|
|
55
|
+
injective: 'inj',
|
|
56
|
+
celestia: 'celestia',
|
|
57
|
+
sei: 'sei',
|
|
58
|
+
dydx: 'dydx',
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Result of Cosmos stealth address generation
|
|
63
|
+
*/
|
|
64
|
+
export interface CosmosStealthResult {
|
|
65
|
+
/** Bech32-encoded Cosmos address */
|
|
66
|
+
stealthAddress: string
|
|
67
|
+
/** Raw stealth public key (33-byte compressed secp256k1) */
|
|
68
|
+
stealthPublicKey: HexString
|
|
69
|
+
/** Ephemeral public key for recipient to derive private key */
|
|
70
|
+
ephemeralPublicKey: HexString
|
|
71
|
+
/** View tag for efficient scanning (0-255) */
|
|
72
|
+
viewTag: number
|
|
73
|
+
/** View key hash for compliance */
|
|
74
|
+
viewKeyHash: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Cosmos Stealth Address Service
|
|
79
|
+
*
|
|
80
|
+
* Provides stealth address generation and key derivation for Cosmos chains.
|
|
81
|
+
* Reuses secp256k1 logic from core stealth module, adding Cosmos-specific
|
|
82
|
+
* address formatting.
|
|
83
|
+
*/
|
|
84
|
+
export class CosmosStealthService {
|
|
85
|
+
/**
|
|
86
|
+
* Generate a stealth meta-address for a Cosmos chain
|
|
87
|
+
*
|
|
88
|
+
* @param chain - Cosmos chain identifier
|
|
89
|
+
* @param label - Optional human-readable label
|
|
90
|
+
* @returns Stealth meta-address and private keys
|
|
91
|
+
* @throws {ValidationError} If chain is invalid
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const service = new CosmosStealthService()
|
|
96
|
+
* const { metaAddress, spendingPrivateKey, viewingPrivateKey } =
|
|
97
|
+
* service.generateStealthMetaAddress('cosmos', 'My Cosmos Wallet')
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
generateStealthMetaAddress(
|
|
101
|
+
chain: CosmosChainId,
|
|
102
|
+
label?: string,
|
|
103
|
+
): {
|
|
104
|
+
metaAddress: StealthMetaAddress
|
|
105
|
+
spendingPrivateKey: HexString
|
|
106
|
+
viewingPrivateKey: HexString
|
|
107
|
+
} {
|
|
108
|
+
// Validate chain
|
|
109
|
+
if (!this.isValidCosmosChain(chain)) {
|
|
110
|
+
throw new ValidationError(
|
|
111
|
+
`invalid Cosmos chain '${chain}', must be one of: ${Object.keys(CHAIN_PREFIXES).join(', ')}`,
|
|
112
|
+
'chain'
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Use core secp256k1 stealth generation (Cosmos uses secp256k1, not 'cosmos' as ChainId)
|
|
117
|
+
// We'll use 'ethereum' as the underlying chain for secp256k1 generation
|
|
118
|
+
const result = generateStealthMetaAddress('ethereum', label)
|
|
119
|
+
|
|
120
|
+
// Override chain with actual Cosmos chain ID
|
|
121
|
+
// Note: This is a workaround since the core types don't include Cosmos chains yet
|
|
122
|
+
return {
|
|
123
|
+
...result,
|
|
124
|
+
metaAddress: {
|
|
125
|
+
...result.metaAddress,
|
|
126
|
+
chain: chain as any, // Will be updated in types package
|
|
127
|
+
},
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Generate a one-time stealth address for a Cosmos chain
|
|
133
|
+
*
|
|
134
|
+
* @param spendingPubKey - Recipient's spending public key (33-byte compressed)
|
|
135
|
+
* @param viewingPubKey - Recipient's viewing public key (33-byte compressed)
|
|
136
|
+
* @param chain - Cosmos chain identifier
|
|
137
|
+
* @returns Cosmos stealth address with bech32 encoding
|
|
138
|
+
* @throws {ValidationError} If keys or chain are invalid
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* const service = new CosmosStealthService()
|
|
143
|
+
* const result = service.generateStealthAddress(
|
|
144
|
+
* spendingKey,
|
|
145
|
+
* viewingKey,
|
|
146
|
+
* 'osmosis'
|
|
147
|
+
* )
|
|
148
|
+
* console.log(result.stealthAddress) // "osmo1..."
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
generateStealthAddress(
|
|
152
|
+
spendingPubKey: Uint8Array,
|
|
153
|
+
viewingPubKey: Uint8Array,
|
|
154
|
+
chain: CosmosChainId,
|
|
155
|
+
): CosmosStealthResult {
|
|
156
|
+
// Validate chain
|
|
157
|
+
if (!this.isValidCosmosChain(chain)) {
|
|
158
|
+
throw new ValidationError(
|
|
159
|
+
`invalid Cosmos chain '${chain}', must be one of: ${Object.keys(CHAIN_PREFIXES).join(', ')}`,
|
|
160
|
+
'chain'
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Validate keys (33-byte compressed secp256k1)
|
|
165
|
+
if (spendingPubKey.length !== 33) {
|
|
166
|
+
throw new ValidationError(
|
|
167
|
+
'spendingPubKey must be 33 bytes (compressed secp256k1)',
|
|
168
|
+
'spendingPubKey'
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (viewingPubKey.length !== 33) {
|
|
173
|
+
throw new ValidationError(
|
|
174
|
+
'viewingPubKey must be 33 bytes (compressed secp256k1)',
|
|
175
|
+
'viewingPubKey'
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Create meta-address for core stealth generation
|
|
180
|
+
const metaAddress: StealthMetaAddress = {
|
|
181
|
+
spendingKey: `0x${bytesToHex(spendingPubKey)}` as HexString,
|
|
182
|
+
viewingKey: `0x${bytesToHex(viewingPubKey)}` as HexString,
|
|
183
|
+
chain: 'ethereum', // Use ethereum for secp256k1 generation
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Generate stealth address using core secp256k1 logic
|
|
187
|
+
const { stealthAddress, sharedSecret } = generateSecp256k1StealthAddress(metaAddress)
|
|
188
|
+
|
|
189
|
+
// Convert stealth public key to Cosmos bech32 address
|
|
190
|
+
const cosmosAddress = this.stealthKeyToCosmosAddress(
|
|
191
|
+
hexToBytes(stealthAddress.address.slice(2)),
|
|
192
|
+
CHAIN_PREFIXES[chain]
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
stealthAddress: cosmosAddress,
|
|
197
|
+
stealthPublicKey: stealthAddress.address,
|
|
198
|
+
ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
|
|
199
|
+
viewTag: stealthAddress.viewTag,
|
|
200
|
+
viewKeyHash: sharedSecret,
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Generate stealth address from StealthMetaAddress
|
|
206
|
+
*
|
|
207
|
+
* Convenience method that accepts a StealthMetaAddress directly.
|
|
208
|
+
*
|
|
209
|
+
* @param recipientMetaAddress - Recipient's stealth meta-address
|
|
210
|
+
* @param chain - Cosmos chain identifier
|
|
211
|
+
* @returns Cosmos stealth address with bech32 encoding
|
|
212
|
+
* @throws {ValidationError} If meta-address or chain are invalid
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* const service = new CosmosStealthService()
|
|
217
|
+
* const result = service.generateStealthAddressFromMeta(metaAddress, 'cosmos')
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
generateStealthAddressFromMeta(
|
|
221
|
+
recipientMetaAddress: StealthMetaAddress,
|
|
222
|
+
chain: CosmosChainId,
|
|
223
|
+
): CosmosStealthResult {
|
|
224
|
+
const spendingPubKey = hexToBytes(recipientMetaAddress.spendingKey.slice(2))
|
|
225
|
+
const viewingPubKey = hexToBytes(recipientMetaAddress.viewingKey.slice(2))
|
|
226
|
+
|
|
227
|
+
return this.generateStealthAddress(spendingPubKey, viewingPubKey, chain)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Convert stealth public key to Cosmos bech32 address
|
|
232
|
+
*
|
|
233
|
+
* Algorithm:
|
|
234
|
+
* 1. SHA256 hash of compressed public key
|
|
235
|
+
* 2. RIPEMD160 hash of SHA256 hash
|
|
236
|
+
* 3. Bech32 encode with chain prefix
|
|
237
|
+
*
|
|
238
|
+
* @param publicKey - Compressed secp256k1 public key (33 bytes)
|
|
239
|
+
* @param prefix - Bech32 address prefix (e.g., "cosmos", "osmo")
|
|
240
|
+
* @returns Bech32-encoded address
|
|
241
|
+
* @throws {ValidationError} If public key is invalid
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* const service = new CosmosStealthService()
|
|
246
|
+
* const address = service.stealthKeyToCosmosAddress(pubKey, 'cosmos')
|
|
247
|
+
* // Returns: "cosmos1abc..."
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
stealthKeyToCosmosAddress(publicKey: Uint8Array, prefix: string): string {
|
|
251
|
+
// Validate public key
|
|
252
|
+
if (publicKey.length !== 33) {
|
|
253
|
+
throw new ValidationError(
|
|
254
|
+
'public key must be 33 bytes (compressed secp256k1)',
|
|
255
|
+
'publicKey'
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Cosmos address derivation: bech32(prefix, ripemd160(sha256(pubkey)))
|
|
260
|
+
const sha256Hash = sha256(publicKey)
|
|
261
|
+
const hash160 = ripemd160(sha256Hash)
|
|
262
|
+
|
|
263
|
+
// Bech32 encode
|
|
264
|
+
const words = bech32.toWords(hash160)
|
|
265
|
+
return bech32.encode(prefix, words)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Derive stealth private key for recipient to claim funds
|
|
270
|
+
*
|
|
271
|
+
* @param stealthAddress - The stealth address to recover (as StealthAddress)
|
|
272
|
+
* @param spendingPrivateKey - Recipient's spending private key
|
|
273
|
+
* @param viewingPrivateKey - Recipient's viewing private key
|
|
274
|
+
* @returns Recovery data with derived private key
|
|
275
|
+
* @throws {ValidationError} If any input is invalid
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```typescript
|
|
279
|
+
* const service = new CosmosStealthService()
|
|
280
|
+
* const recovery = service.deriveStealthPrivateKey(
|
|
281
|
+
* stealthAddress,
|
|
282
|
+
* spendingPrivKey,
|
|
283
|
+
* viewingPrivKey
|
|
284
|
+
* )
|
|
285
|
+
* // Use recovery.privateKey to spend funds
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
deriveStealthPrivateKey(
|
|
289
|
+
stealthAddress: StealthAddress,
|
|
290
|
+
spendingPrivateKey: HexString,
|
|
291
|
+
viewingPrivateKey: HexString,
|
|
292
|
+
): StealthAddressRecovery {
|
|
293
|
+
// Use core secp256k1 derivation logic
|
|
294
|
+
return deriveSecp256k1StealthPrivateKey(
|
|
295
|
+
stealthAddress,
|
|
296
|
+
spendingPrivateKey,
|
|
297
|
+
viewingPrivateKey
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Check if a string is a valid Cosmos chain identifier
|
|
303
|
+
*/
|
|
304
|
+
private isValidCosmosChain(chain: string): chain is CosmosChainId {
|
|
305
|
+
return chain in CHAIN_PREFIXES
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Decode a Cosmos bech32 address to raw hash
|
|
310
|
+
*
|
|
311
|
+
* @param address - Bech32-encoded address
|
|
312
|
+
* @returns Decoded address hash (20 bytes)
|
|
313
|
+
* @throws {ValidationError} If address is invalid
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```typescript
|
|
317
|
+
* const service = new CosmosStealthService()
|
|
318
|
+
* const { prefix, hash } = service.decodeBech32Address('cosmos1abc...')
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
decodeBech32Address(address: string): { prefix: string; hash: Uint8Array } {
|
|
322
|
+
try {
|
|
323
|
+
const decoded = bech32.decode(address as `${string}1${string}`)
|
|
324
|
+
const hash = bech32.fromWords(decoded.words)
|
|
325
|
+
|
|
326
|
+
if (hash.length !== 20) {
|
|
327
|
+
throw new ValidationError(
|
|
328
|
+
`invalid address hash length: ${hash.length}, expected 20`,
|
|
329
|
+
'address'
|
|
330
|
+
)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
prefix: decoded.prefix,
|
|
335
|
+
hash: new Uint8Array(hash),
|
|
336
|
+
}
|
|
337
|
+
} catch (error) {
|
|
338
|
+
if (error instanceof ValidationError) {
|
|
339
|
+
throw error
|
|
340
|
+
}
|
|
341
|
+
throw new ValidationError(
|
|
342
|
+
`invalid bech32 address: ${error instanceof Error ? error.message : 'unknown error'}`,
|
|
343
|
+
'address'
|
|
344
|
+
)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Validate a Cosmos bech32 address format
|
|
350
|
+
*
|
|
351
|
+
* @param address - Address to validate
|
|
352
|
+
* @param expectedChain - Optional chain to validate prefix against
|
|
353
|
+
* @returns true if valid, false otherwise
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* ```typescript
|
|
357
|
+
* const service = new CosmosStealthService()
|
|
358
|
+
* service.isValidCosmosAddress('cosmos1abc...', 'cosmos') // true
|
|
359
|
+
* service.isValidCosmosAddress('osmo1xyz...', 'cosmos') // false (wrong prefix)
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
isValidCosmosAddress(address: string, expectedChain?: CosmosChainId): boolean {
|
|
363
|
+
try {
|
|
364
|
+
const { prefix, hash } = this.decodeBech32Address(address)
|
|
365
|
+
|
|
366
|
+
// Check hash is correct length (20 bytes for Cosmos)
|
|
367
|
+
if (hash.length !== 20) {
|
|
368
|
+
return false
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// If expected chain provided, validate prefix matches
|
|
372
|
+
if (expectedChain) {
|
|
373
|
+
return prefix === CHAIN_PREFIXES[expectedChain]
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Otherwise, check if prefix is any known Cosmos chain
|
|
377
|
+
return Object.values(CHAIN_PREFIXES).includes(prefix)
|
|
378
|
+
} catch {
|
|
379
|
+
return false
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Get the chain ID from a bech32 address prefix
|
|
385
|
+
*
|
|
386
|
+
* @param address - Bech32-encoded address
|
|
387
|
+
* @returns Chain ID or null if unknown prefix
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```typescript
|
|
391
|
+
* const service = new CosmosStealthService()
|
|
392
|
+
* service.getChainFromAddress('cosmos1abc...') // 'cosmos'
|
|
393
|
+
* service.getChainFromAddress('osmo1xyz...') // 'osmosis'
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
getChainFromAddress(address: string): CosmosChainId | null {
|
|
397
|
+
try {
|
|
398
|
+
const { prefix } = this.decodeBech32Address(address)
|
|
399
|
+
|
|
400
|
+
for (const [chain, chainPrefix] of Object.entries(CHAIN_PREFIXES)) {
|
|
401
|
+
if (chainPrefix === prefix) {
|
|
402
|
+
return chain as CosmosChainId
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return null
|
|
407
|
+
} catch {
|
|
408
|
+
return null
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// ─── Standalone Functions ──────────────────────────────────────────────────
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Generate a stealth meta-address for a Cosmos chain
|
|
417
|
+
*
|
|
418
|
+
* Convenience function that creates a CosmosStealthService instance.
|
|
419
|
+
*
|
|
420
|
+
* @param chain - Cosmos chain identifier
|
|
421
|
+
* @param label - Optional human-readable label
|
|
422
|
+
* @returns Stealth meta-address and private keys
|
|
423
|
+
*/
|
|
424
|
+
export function generateCosmosStealthMetaAddress(
|
|
425
|
+
chain: CosmosChainId,
|
|
426
|
+
label?: string,
|
|
427
|
+
): {
|
|
428
|
+
metaAddress: StealthMetaAddress
|
|
429
|
+
spendingPrivateKey: HexString
|
|
430
|
+
viewingPrivateKey: HexString
|
|
431
|
+
} {
|
|
432
|
+
const service = new CosmosStealthService()
|
|
433
|
+
return service.generateStealthMetaAddress(chain, label)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Generate a one-time stealth address for a Cosmos chain
|
|
438
|
+
*
|
|
439
|
+
* Convenience function that creates a CosmosStealthService instance.
|
|
440
|
+
*
|
|
441
|
+
* @param spendingPubKey - Recipient's spending public key
|
|
442
|
+
* @param viewingPubKey - Recipient's viewing public key
|
|
443
|
+
* @param chain - Cosmos chain identifier
|
|
444
|
+
* @returns Cosmos stealth address with bech32 encoding
|
|
445
|
+
*/
|
|
446
|
+
export function generateCosmosStealthAddress(
|
|
447
|
+
spendingPubKey: Uint8Array,
|
|
448
|
+
viewingPubKey: Uint8Array,
|
|
449
|
+
chain: CosmosChainId,
|
|
450
|
+
): CosmosStealthResult {
|
|
451
|
+
const service = new CosmosStealthService()
|
|
452
|
+
return service.generateStealthAddress(spendingPubKey, viewingPubKey, chain)
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Convert stealth public key to Cosmos bech32 address
|
|
457
|
+
*
|
|
458
|
+
* Convenience function that creates a CosmosStealthService instance.
|
|
459
|
+
*
|
|
460
|
+
* @param publicKey - Compressed secp256k1 public key (33 bytes)
|
|
461
|
+
* @param prefix - Bech32 address prefix
|
|
462
|
+
* @returns Bech32-encoded address
|
|
463
|
+
*/
|
|
464
|
+
export function stealthKeyToCosmosAddress(
|
|
465
|
+
publicKey: Uint8Array,
|
|
466
|
+
prefix: string,
|
|
467
|
+
): string {
|
|
468
|
+
const service = new CosmosStealthService()
|
|
469
|
+
return service.stealthKeyToCosmosAddress(publicKey, prefix)
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Validate a Cosmos bech32 address
|
|
474
|
+
*
|
|
475
|
+
* Convenience function that creates a CosmosStealthService instance.
|
|
476
|
+
*
|
|
477
|
+
* @param address - Address to validate
|
|
478
|
+
* @param expectedChain - Optional chain to validate prefix against
|
|
479
|
+
* @returns true if valid, false otherwise
|
|
480
|
+
*/
|
|
481
|
+
export function isValidCosmosAddress(
|
|
482
|
+
address: string,
|
|
483
|
+
expectedChain?: CosmosChainId,
|
|
484
|
+
): boolean {
|
|
485
|
+
const service = new CosmosStealthService()
|
|
486
|
+
return service.isValidCosmosAddress(address, expectedChain)
|
|
487
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -93,6 +93,34 @@ export {
|
|
|
93
93
|
|
|
94
94
|
export type { StealthCurve } from './stealth'
|
|
95
95
|
|
|
96
|
+
// Move blockchain stealth addresses (Aptos)
|
|
97
|
+
export {
|
|
98
|
+
AptosStealthService,
|
|
99
|
+
generateAptosStealthAddress,
|
|
100
|
+
deriveAptosStealthPrivateKey,
|
|
101
|
+
checkAptosStealthAddress,
|
|
102
|
+
ed25519PublicKeyToAptosAddress,
|
|
103
|
+
aptosAddressToAuthKey,
|
|
104
|
+
isValidAptosAddress,
|
|
105
|
+
} from './move'
|
|
106
|
+
|
|
107
|
+
export type { AptosStealthResult } from './move'
|
|
108
|
+
|
|
109
|
+
// Cosmos blockchain stealth addresses
|
|
110
|
+
export {
|
|
111
|
+
CosmosStealthService,
|
|
112
|
+
generateCosmosStealthMetaAddress,
|
|
113
|
+
generateCosmosStealthAddress,
|
|
114
|
+
stealthKeyToCosmosAddress,
|
|
115
|
+
isValidCosmosAddress,
|
|
116
|
+
CHAIN_PREFIXES as COSMOS_CHAIN_PREFIXES,
|
|
117
|
+
} from './cosmos'
|
|
118
|
+
|
|
119
|
+
export type {
|
|
120
|
+
CosmosChainId,
|
|
121
|
+
CosmosStealthResult,
|
|
122
|
+
} from './cosmos'
|
|
123
|
+
|
|
96
124
|
// Privacy utilities
|
|
97
125
|
export {
|
|
98
126
|
getPrivacyConfig,
|
|
@@ -453,6 +481,29 @@ export type {
|
|
|
453
481
|
ZcashNetworkInfo,
|
|
454
482
|
} from '@sip-protocol/types'
|
|
455
483
|
|
|
484
|
+
// Bitcoin Taproot (BIP-340/341)
|
|
485
|
+
export {
|
|
486
|
+
// BIP-340 Schnorr signatures
|
|
487
|
+
schnorrSign,
|
|
488
|
+
schnorrVerify,
|
|
489
|
+
schnorrSignHex,
|
|
490
|
+
schnorrVerifyHex,
|
|
491
|
+
// BIP-341 Taproot
|
|
492
|
+
getXOnlyPublicKey,
|
|
493
|
+
computeTweakedKey,
|
|
494
|
+
createTaprootOutput,
|
|
495
|
+
createKeySpendOnlyOutput,
|
|
496
|
+
taprootAddress,
|
|
497
|
+
decodeTaprootAddress,
|
|
498
|
+
isValidTaprootAddress,
|
|
499
|
+
} from './bitcoin'
|
|
500
|
+
|
|
501
|
+
export type {
|
|
502
|
+
TaprootOutput,
|
|
503
|
+
TapScript,
|
|
504
|
+
BitcoinNetwork,
|
|
505
|
+
} from './bitcoin'
|
|
506
|
+
|
|
456
507
|
// Private Payments
|
|
457
508
|
export {
|
|
458
509
|
PaymentBuilder,
|