@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
package/src/move/sui.ts
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sui stealth address implementation
|
|
3
|
+
*
|
|
4
|
+
* Sui uses ed25519 for signatures, similar to Aptos, Solana, and NEAR.
|
|
5
|
+
* This module provides stealth address generation and address format conversion for Sui.
|
|
6
|
+
*
|
|
7
|
+
* Key differences from Aptos:
|
|
8
|
+
* - Sui addresses are derived via BLAKE2b-256(0x00 || pubkey)
|
|
9
|
+
* - 32-byte addresses encoded as hex with 0x prefix
|
|
10
|
+
* - Signature scheme flag byte (0x00) comes BEFORE public key
|
|
11
|
+
*
|
|
12
|
+
* @see https://docs.sui.io/concepts/cryptography/transaction-auth/signatures
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { ed25519 } from '@noble/curves/ed25519'
|
|
16
|
+
import { BLAKE2b } from '@noble/hashes/blake2b'
|
|
17
|
+
import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
|
|
18
|
+
import type { HexString, StealthMetaAddress, StealthAddress } from '@sip-protocol/types'
|
|
19
|
+
import { ValidationError } from '../errors'
|
|
20
|
+
import { isValidHex, isValidEd25519PublicKey } from '../validation'
|
|
21
|
+
import {
|
|
22
|
+
generateEd25519StealthAddress,
|
|
23
|
+
deriveEd25519StealthPrivateKey,
|
|
24
|
+
checkEd25519StealthAddress,
|
|
25
|
+
} from '../stealth'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Result of Sui stealth address generation
|
|
29
|
+
*/
|
|
30
|
+
export interface SuiStealthResult {
|
|
31
|
+
/** Sui address in 0x-prefixed 64-character hex format */
|
|
32
|
+
stealthAddress: string
|
|
33
|
+
/** Raw 32-byte ed25519 stealth public key (hex) */
|
|
34
|
+
stealthPublicKey: HexString
|
|
35
|
+
/** Ephemeral public key for recipient scanning (hex) */
|
|
36
|
+
ephemeralPublicKey: HexString
|
|
37
|
+
/** View tag for efficient scanning (0-255) */
|
|
38
|
+
viewTag: number
|
|
39
|
+
/** Shared secret hash (for verification) */
|
|
40
|
+
sharedSecret: HexString
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Sui signature scheme flag
|
|
45
|
+
* 0x00 = ED25519 signature
|
|
46
|
+
*/
|
|
47
|
+
const SUI_ED25519_SCHEME = 0x00
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Convert an ed25519 public key to a Sui address
|
|
51
|
+
*
|
|
52
|
+
* Sui address derivation:
|
|
53
|
+
* 1. Take the 32-byte ed25519 public key
|
|
54
|
+
* 2. Prepend the scheme byte (0x00 for ED25519)
|
|
55
|
+
* 3. Hash with BLAKE2b-256: address = blake2b_256(0x00 || pubkey)
|
|
56
|
+
* 4. Encode as 0x-prefixed hex string (64 characters)
|
|
57
|
+
*
|
|
58
|
+
* @param publicKey - 32-byte ed25519 public key as hex string (with 0x prefix)
|
|
59
|
+
* @returns Sui address (0x-prefixed, 64 hex characters)
|
|
60
|
+
* @throws {ValidationError} If public key is invalid
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const suiAddress = ed25519PublicKeyToSuiAddress('0xabc123...')
|
|
65
|
+
* // Returns: "0x1234...abcd" (64 hex chars)
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function ed25519PublicKeyToSuiAddress(publicKey: HexString): string {
|
|
69
|
+
// Validate input
|
|
70
|
+
if (!isValidHex(publicKey)) {
|
|
71
|
+
throw new ValidationError(
|
|
72
|
+
'publicKey must be a valid hex string with 0x prefix',
|
|
73
|
+
'publicKey'
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!isValidEd25519PublicKey(publicKey)) {
|
|
78
|
+
throw new ValidationError(
|
|
79
|
+
'publicKey must be 32 bytes (64 hex characters)',
|
|
80
|
+
'publicKey'
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Convert hex to bytes (remove 0x prefix)
|
|
85
|
+
const publicKeyBytes = hexToBytes(publicKey.slice(2))
|
|
86
|
+
|
|
87
|
+
// Prepend signature scheme byte (0x00 for ED25519)
|
|
88
|
+
const addressInput = new Uint8Array(publicKeyBytes.length + 1)
|
|
89
|
+
addressInput[0] = SUI_ED25519_SCHEME
|
|
90
|
+
addressInput.set(publicKeyBytes, 1)
|
|
91
|
+
|
|
92
|
+
// Hash with BLAKE2b-256 to get the address
|
|
93
|
+
const hasher = new BLAKE2b({ dkLen: 32 })
|
|
94
|
+
hasher.update(addressInput)
|
|
95
|
+
const addressHash = hasher.digest()
|
|
96
|
+
|
|
97
|
+
// Return as 0x-prefixed hex string
|
|
98
|
+
return `0x${bytesToHex(addressHash)}`
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Validate a Sui address format
|
|
103
|
+
*
|
|
104
|
+
* Checks that the address:
|
|
105
|
+
* - Is a valid hex string with 0x prefix
|
|
106
|
+
* - Is exactly 32 bytes (64 hex characters)
|
|
107
|
+
* - Contains only valid hex characters
|
|
108
|
+
*
|
|
109
|
+
* Note: This does NOT verify if the address exists on-chain or is derived correctly.
|
|
110
|
+
* It only validates the format.
|
|
111
|
+
*
|
|
112
|
+
* @param address - Sui address to validate
|
|
113
|
+
* @returns true if format is valid, false otherwise
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* isValidSuiAddress('0x1234...abcd') // true (64 hex chars)
|
|
118
|
+
* isValidSuiAddress('0x123') // false (too short)
|
|
119
|
+
* isValidSuiAddress('1234abcd...') // false (no 0x prefix)
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export function isValidSuiAddress(address: string): boolean {
|
|
123
|
+
if (typeof address !== 'string' || address.length === 0) {
|
|
124
|
+
return false
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Must start with 0x
|
|
128
|
+
if (!address.startsWith('0x')) {
|
|
129
|
+
return false
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Must be exactly 64 hex characters after 0x (32 bytes)
|
|
133
|
+
const hexPart = address.slice(2)
|
|
134
|
+
if (hexPart.length !== 64) {
|
|
135
|
+
return false
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Must be valid hex
|
|
139
|
+
return /^[0-9a-fA-F]{64}$/.test(hexPart)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Normalize a Sui address to lowercase
|
|
144
|
+
*
|
|
145
|
+
* @param address - Sui address (0x-prefixed hex string)
|
|
146
|
+
* @returns Normalized address as HexString
|
|
147
|
+
* @throws {ValidationError} If address format is invalid
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* const normalized = normalizeSuiAddress('0x1234...ABCD')
|
|
152
|
+
* // Returns: "0x1234...abcd" (lowercase)
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export function normalizeSuiAddress(address: string): HexString {
|
|
156
|
+
if (!isValidSuiAddress(address)) {
|
|
157
|
+
throw new ValidationError(
|
|
158
|
+
'Invalid Sui address format (must be 0x-prefixed 64 hex characters)',
|
|
159
|
+
'address'
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Normalize to lowercase
|
|
164
|
+
return address.toLowerCase() as HexString
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Generate a stealth address for Sui
|
|
169
|
+
*
|
|
170
|
+
* Uses the existing ed25519 stealth address generation logic and converts
|
|
171
|
+
* the resulting ed25519 public key to Sui address format.
|
|
172
|
+
*
|
|
173
|
+
* @param recipientMetaAddress - Recipient's stealth meta-address (must be chain: 'sui')
|
|
174
|
+
* @returns Sui stealth address result with all necessary data
|
|
175
|
+
* @throws {ValidationError} If meta-address is invalid or not for Sui
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* const metaAddress = {
|
|
180
|
+
* spendingKey: '0x...',
|
|
181
|
+
* viewingKey: '0x...',
|
|
182
|
+
* chain: 'sui'
|
|
183
|
+
* }
|
|
184
|
+
* const result = generateSuiStealthAddress(metaAddress)
|
|
185
|
+
* console.log(result.stealthAddress) // "0x1234...abcd"
|
|
186
|
+
* console.log(result.viewTag) // 42
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export function generateSuiStealthAddress(
|
|
190
|
+
recipientMetaAddress: StealthMetaAddress,
|
|
191
|
+
): SuiStealthResult {
|
|
192
|
+
// Validate chain
|
|
193
|
+
if (recipientMetaAddress.chain !== 'sui') {
|
|
194
|
+
throw new ValidationError(
|
|
195
|
+
`Expected chain 'sui', got '${recipientMetaAddress.chain}'`,
|
|
196
|
+
'recipientMetaAddress.chain'
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Generate ed25519 stealth address using existing logic
|
|
201
|
+
const { stealthAddress, sharedSecret } = generateEd25519StealthAddress(recipientMetaAddress)
|
|
202
|
+
|
|
203
|
+
// Convert the ed25519 public key to Sui address format
|
|
204
|
+
const suiAddress = ed25519PublicKeyToSuiAddress(stealthAddress.address)
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
stealthAddress: suiAddress,
|
|
208
|
+
stealthPublicKey: stealthAddress.address,
|
|
209
|
+
ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
|
|
210
|
+
viewTag: stealthAddress.viewTag,
|
|
211
|
+
sharedSecret,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Derive the private key for a Sui stealth address
|
|
217
|
+
*
|
|
218
|
+
* This allows the recipient to claim funds sent to a stealth address.
|
|
219
|
+
* Uses the standard ed25519 stealth key derivation.
|
|
220
|
+
*
|
|
221
|
+
* @param stealthAddress - The stealth address data (from announcement)
|
|
222
|
+
* @param spendingPrivateKey - Recipient's spending private key
|
|
223
|
+
* @param viewingPrivateKey - Recipient's viewing private key
|
|
224
|
+
* @returns Derived private key (raw scalar, little-endian format)
|
|
225
|
+
* @throws {ValidationError} If any input is invalid
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```typescript
|
|
229
|
+
* const recovery = deriveSuiStealthPrivateKey(
|
|
230
|
+
* stealthAddress,
|
|
231
|
+
* spendingPrivKey,
|
|
232
|
+
* viewingPrivKey
|
|
233
|
+
* )
|
|
234
|
+
* // Use recovery.privateKey to sign transactions
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
export function deriveSuiStealthPrivateKey(
|
|
238
|
+
stealthAddress: StealthAddress,
|
|
239
|
+
spendingPrivateKey: HexString,
|
|
240
|
+
viewingPrivateKey: HexString,
|
|
241
|
+
): {
|
|
242
|
+
stealthAddress: HexString
|
|
243
|
+
ephemeralPublicKey: HexString
|
|
244
|
+
privateKey: HexString
|
|
245
|
+
suiAddress: string
|
|
246
|
+
} {
|
|
247
|
+
// Use standard ed25519 derivation
|
|
248
|
+
const recovery = deriveEd25519StealthPrivateKey(
|
|
249
|
+
stealthAddress,
|
|
250
|
+
spendingPrivateKey,
|
|
251
|
+
viewingPrivateKey
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
// Convert the stealth public key to Sui address
|
|
255
|
+
const suiAddress = ed25519PublicKeyToSuiAddress(recovery.stealthAddress)
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
...recovery,
|
|
259
|
+
suiAddress,
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Check if a stealth address belongs to this recipient
|
|
265
|
+
*
|
|
266
|
+
* Uses view tag for efficient filtering before full computation.
|
|
267
|
+
* This is the same as the standard ed25519 check since Sui stealth
|
|
268
|
+
* addresses use ed25519 stealth public keys.
|
|
269
|
+
*
|
|
270
|
+
* @param stealthAddress - Stealth address to check
|
|
271
|
+
* @param spendingPrivateKey - Recipient's spending private key
|
|
272
|
+
* @param viewingPrivateKey - Recipient's viewing private key
|
|
273
|
+
* @returns true if this address belongs to the recipient
|
|
274
|
+
* @throws {ValidationError} If any input is invalid
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* const isMine = checkSuiStealthAddress(
|
|
279
|
+
* stealthAddress,
|
|
280
|
+
* mySpendingPrivKey,
|
|
281
|
+
* myViewingPrivKey
|
|
282
|
+
* )
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
export function checkSuiStealthAddress(
|
|
286
|
+
stealthAddress: StealthAddress,
|
|
287
|
+
spendingPrivateKey: HexString,
|
|
288
|
+
viewingPrivateKey: HexString,
|
|
289
|
+
): boolean {
|
|
290
|
+
// Use standard ed25519 check
|
|
291
|
+
return checkEd25519StealthAddress(
|
|
292
|
+
stealthAddress,
|
|
293
|
+
spendingPrivateKey,
|
|
294
|
+
viewingPrivateKey
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Sui Stealth Service
|
|
300
|
+
*
|
|
301
|
+
* Provides a convenient class-based interface for Sui stealth address operations.
|
|
302
|
+
* This is useful when you need to perform multiple operations or want to encapsulate
|
|
303
|
+
* the logic in a service object.
|
|
304
|
+
*/
|
|
305
|
+
export class SuiStealthService {
|
|
306
|
+
/**
|
|
307
|
+
* Generate a stealth address for a Sui recipient
|
|
308
|
+
*
|
|
309
|
+
* @param recipientMetaAddress - Recipient's stealth meta-address
|
|
310
|
+
* @returns Complete stealth address result
|
|
311
|
+
*/
|
|
312
|
+
generateStealthAddress(recipientMetaAddress: StealthMetaAddress): SuiStealthResult {
|
|
313
|
+
return generateSuiStealthAddress(recipientMetaAddress)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Convert an ed25519 public key to Sui address format
|
|
318
|
+
*
|
|
319
|
+
* @param publicKey - 32-byte ed25519 public key
|
|
320
|
+
* @returns Sui address string
|
|
321
|
+
*/
|
|
322
|
+
stealthKeyToSuiAddress(publicKey: HexString): string {
|
|
323
|
+
return ed25519PublicKeyToSuiAddress(publicKey)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Derive the private key for a stealth address
|
|
328
|
+
*
|
|
329
|
+
* @param stealthAddress - Stealth address data
|
|
330
|
+
* @param spendingPrivateKey - Recipient's spending private key
|
|
331
|
+
* @param viewingPrivateKey - Recipient's viewing private key
|
|
332
|
+
* @returns Recovery data with derived private key
|
|
333
|
+
*/
|
|
334
|
+
deriveStealthPrivateKey(
|
|
335
|
+
stealthAddress: StealthAddress,
|
|
336
|
+
spendingPrivateKey: HexString,
|
|
337
|
+
viewingPrivateKey: HexString,
|
|
338
|
+
) {
|
|
339
|
+
return deriveSuiStealthPrivateKey(stealthAddress, spendingPrivateKey, viewingPrivateKey)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Check if a stealth address belongs to this recipient
|
|
344
|
+
*
|
|
345
|
+
* @param stealthAddress - Stealth address to check
|
|
346
|
+
* @param spendingPrivateKey - Recipient's spending private key
|
|
347
|
+
* @param viewingPrivateKey - Recipient's viewing private key
|
|
348
|
+
* @returns true if the address belongs to this recipient
|
|
349
|
+
*/
|
|
350
|
+
checkStealthAddress(
|
|
351
|
+
stealthAddress: StealthAddress,
|
|
352
|
+
spendingPrivateKey: HexString,
|
|
353
|
+
viewingPrivateKey: HexString,
|
|
354
|
+
): boolean {
|
|
355
|
+
return checkSuiStealthAddress(stealthAddress, spendingPrivateKey, viewingPrivateKey)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Validate a Sui address format
|
|
360
|
+
*
|
|
361
|
+
* @param address - Address to validate
|
|
362
|
+
* @returns true if valid format
|
|
363
|
+
*/
|
|
364
|
+
isValidAddress(address: string): boolean {
|
|
365
|
+
return isValidSuiAddress(address)
|
|
366
|
+
}
|
|
367
|
+
}
|
package/src/oracle/types.ts
CHANGED
|
@@ -254,4 +254,12 @@ export const CHAIN_NUMERIC_IDS: Record<ChainId, number> = {
|
|
|
254
254
|
solana: 501, // Non-standard, SIP-specific
|
|
255
255
|
near: 502, // Non-standard, SIP-specific
|
|
256
256
|
zcash: 503, // Non-standard, SIP-specific
|
|
257
|
+
aptos: 504, // Non-standard, SIP-specific
|
|
258
|
+
sui: 505, // Non-standard, SIP-specific
|
|
259
|
+
cosmos: 506, // Non-standard, SIP-specific (Cosmos Hub)
|
|
260
|
+
osmosis: 507, // Non-standard, SIP-specific
|
|
261
|
+
injective: 508, // Non-standard, SIP-specific
|
|
262
|
+
celestia: 509, // Non-standard, SIP-specific
|
|
263
|
+
sei: 510, // Non-standard, SIP-specific
|
|
264
|
+
dydx: 511, // Non-standard, SIP-specific
|
|
257
265
|
}
|
|
@@ -108,6 +108,14 @@ const DEFAULT_GAS_FEES: Record<ChainId, bigint> = {
|
|
|
108
108
|
optimism: 21000000n, // 21k gas * 0.001 gwei ETH = 21 gwei = 21e6 wei
|
|
109
109
|
base: 2100000000n, // 21k gas * 0.1 gwei ETH = 2100 gwei = 2.1e9 wei
|
|
110
110
|
bitcoin: 10000n, // 10000 sats = 0.0001 BTC (estimate for 1 input, 2 outputs)
|
|
111
|
+
aptos: 100n, // 0.000001 APT in octas (gas units)
|
|
112
|
+
sui: 1000n, // 0.000001 SUI in MIST
|
|
113
|
+
cosmos: 5000n, // 0.005 ATOM in uatom
|
|
114
|
+
osmosis: 5000n, // 0.005 OSMO in uosmo
|
|
115
|
+
injective: 5000n, // 0.000005 INJ in inj (18 decimals)
|
|
116
|
+
celestia: 5000n, // 0.005 TIA in utia
|
|
117
|
+
sei: 5000n, // 0.005 SEI in usei
|
|
118
|
+
dydx: 5000n, // 0.000005 DYDX in dydx (18 decimals)
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
/**
|
package/src/stealth.ts
CHANGED
|
@@ -54,7 +54,7 @@ export function generateStealthMetaAddress(
|
|
|
54
54
|
// Validate chain
|
|
55
55
|
if (!isValidChainId(chain)) {
|
|
56
56
|
throw new ValidationError(
|
|
57
|
-
`invalid chain '${chain}', must be one of: solana, ethereum, near, zcash, polygon, arbitrum, optimism, base`,
|
|
57
|
+
`invalid chain '${chain}', must be one of: solana, ethereum, near, zcash, polygon, arbitrum, optimism, base, bitcoin, aptos, sui, cosmos, osmosis, injective, celestia, sei, dydx`,
|
|
58
58
|
'chain'
|
|
59
59
|
)
|
|
60
60
|
}
|
|
@@ -554,7 +554,7 @@ const ED25519_ORDER = 2n ** 252n + 27742317777372353535851937790883648493n
|
|
|
554
554
|
/**
|
|
555
555
|
* Chains that use ed25519 for stealth addresses
|
|
556
556
|
*/
|
|
557
|
-
const ED25519_CHAINS: ChainId[] = ['solana', 'near']
|
|
557
|
+
const ED25519_CHAINS: ChainId[] = ['solana', 'near', 'aptos', 'sui']
|
|
558
558
|
|
|
559
559
|
/**
|
|
560
560
|
* Check if a chain uses ed25519 for stealth addresses
|
|
@@ -726,7 +726,7 @@ export function generateEd25519StealthMetaAddress(
|
|
|
726
726
|
// Validate chain
|
|
727
727
|
if (!isValidChainId(chain)) {
|
|
728
728
|
throw new ValidationError(
|
|
729
|
-
`invalid chain '${chain}', must be one of: solana, ethereum, near, zcash, polygon, arbitrum, optimism, base`,
|
|
729
|
+
`invalid chain '${chain}', must be one of: solana, ethereum, near, zcash, polygon, arbitrum, optimism, base, bitcoin, aptos, sui, cosmos, osmosis, injective, celestia, sei, dydx`,
|
|
730
730
|
'chain'
|
|
731
731
|
)
|
|
732
732
|
}
|
package/src/validation.ts
CHANGED
|
@@ -29,6 +29,15 @@ const VALID_CHAIN_IDS: readonly ChainId[] = [
|
|
|
29
29
|
'arbitrum',
|
|
30
30
|
'optimism',
|
|
31
31
|
'base',
|
|
32
|
+
'bitcoin',
|
|
33
|
+
'aptos',
|
|
34
|
+
'sui',
|
|
35
|
+
'cosmos',
|
|
36
|
+
'osmosis',
|
|
37
|
+
'injective',
|
|
38
|
+
'celestia',
|
|
39
|
+
'sei',
|
|
40
|
+
'dydx',
|
|
32
41
|
] as const
|
|
33
42
|
|
|
34
43
|
/**
|
|
@@ -414,10 +423,25 @@ export function isValidNearAddressFormat(address: string): boolean {
|
|
|
414
423
|
return true
|
|
415
424
|
}
|
|
416
425
|
|
|
426
|
+
/**
|
|
427
|
+
* Check if an address is a valid Cosmos bech32 address
|
|
428
|
+
*/
|
|
429
|
+
export function isValidCosmosAddressFormat(address: string): boolean {
|
|
430
|
+
if (typeof address !== 'string') return false
|
|
431
|
+
|
|
432
|
+
// Bech32 addresses follow pattern: prefix1[alphanumeric]
|
|
433
|
+
// Typical length: 39-90 characters
|
|
434
|
+
if (address.length < 39 || address.length > 90) return false
|
|
435
|
+
|
|
436
|
+
// Check for valid bech32 format: prefix + '1' + data
|
|
437
|
+
const bech32Pattern = /^[a-z]+1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38,}$/
|
|
438
|
+
return bech32Pattern.test(address)
|
|
439
|
+
}
|
|
440
|
+
|
|
417
441
|
/**
|
|
418
442
|
* Get the expected address format for a chain
|
|
419
443
|
*/
|
|
420
|
-
export function getChainAddressType(chain: ChainId): 'evm' | 'solana' | 'near' | 'zcash' | 'unknown' {
|
|
444
|
+
export function getChainAddressType(chain: ChainId): 'evm' | 'solana' | 'near' | 'zcash' | 'cosmos' | 'unknown' {
|
|
421
445
|
switch (chain) {
|
|
422
446
|
case 'ethereum':
|
|
423
447
|
case 'polygon':
|
|
@@ -431,6 +455,13 @@ export function getChainAddressType(chain: ChainId): 'evm' | 'solana' | 'near' |
|
|
|
431
455
|
return 'near'
|
|
432
456
|
case 'zcash':
|
|
433
457
|
return 'zcash'
|
|
458
|
+
case 'cosmos':
|
|
459
|
+
case 'osmosis':
|
|
460
|
+
case 'injective':
|
|
461
|
+
case 'celestia':
|
|
462
|
+
case 'sei':
|
|
463
|
+
case 'dydx':
|
|
464
|
+
return 'cosmos'
|
|
434
465
|
default:
|
|
435
466
|
return 'unknown'
|
|
436
467
|
}
|
|
@@ -485,6 +516,16 @@ export function validateAddressForChain(address: string, chain: ChainId, field:
|
|
|
485
516
|
)
|
|
486
517
|
}
|
|
487
518
|
break
|
|
519
|
+
case 'cosmos':
|
|
520
|
+
// Cosmos chains use bech32 encoding - validate basic format
|
|
521
|
+
if (!isValidCosmosAddressFormat(address)) {
|
|
522
|
+
throw new ValidationError(
|
|
523
|
+
`Invalid address format for ${chain}. Expected Cosmos bech32 address, got: ${address.slice(0, 20)}...`,
|
|
524
|
+
field,
|
|
525
|
+
{ chain, expectedFormat: 'bech32' }
|
|
526
|
+
)
|
|
527
|
+
}
|
|
528
|
+
break
|
|
488
529
|
default:
|
|
489
530
|
// Unknown chain - skip validation
|
|
490
531
|
break
|