@sip-protocol/sdk 0.7.2 → 0.7.3

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 (50) hide show
  1. package/dist/browser.d.mts +1 -1
  2. package/dist/browser.d.ts +1 -1
  3. package/dist/browser.js +2926 -341
  4. package/dist/browser.mjs +48 -2
  5. package/dist/chunk-2XIVXWHA.mjs +1930 -0
  6. package/dist/chunk-3M3HNQCW.mjs +18253 -0
  7. package/dist/chunk-7RFRWDCW.mjs +1504 -0
  8. package/dist/chunk-F6F73W35.mjs +16166 -0
  9. package/dist/chunk-OFDBEIEK.mjs +16166 -0
  10. package/dist/chunk-SF7YSLF5.mjs +1515 -0
  11. package/dist/chunk-WWUSGOXE.mjs +17129 -0
  12. package/dist/index-8MQz13eJ.d.mts +13746 -0
  13. package/dist/index-B71aXVzk.d.ts +13264 -0
  14. package/dist/index-DIBZHOOQ.d.ts +13746 -0
  15. package/dist/index-pOIIuwfV.d.mts +13264 -0
  16. package/dist/index.d.mts +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +2911 -326
  19. package/dist/index.mjs +48 -2
  20. package/dist/solana-4O4K45VU.mjs +46 -0
  21. package/dist/solana-NDABAZ6P.mjs +56 -0
  22. package/dist/solana-ZYO63LY5.mjs +46 -0
  23. package/package.json +2 -2
  24. package/src/chains/solana/index.ts +24 -0
  25. package/src/chains/solana/providers/generic.ts +160 -0
  26. package/src/chains/solana/providers/helius.ts +249 -0
  27. package/src/chains/solana/providers/index.ts +54 -0
  28. package/src/chains/solana/providers/interface.ts +178 -0
  29. package/src/chains/solana/providers/webhook.ts +519 -0
  30. package/src/chains/solana/scan.ts +88 -8
  31. package/src/chains/solana/types.ts +20 -1
  32. package/src/compliance/index.ts +14 -0
  33. package/src/compliance/range-sas.ts +591 -0
  34. package/src/index.ts +99 -0
  35. package/src/privacy-backends/index.ts +86 -0
  36. package/src/privacy-backends/interface.ts +263 -0
  37. package/src/privacy-backends/privacycash-types.ts +278 -0
  38. package/src/privacy-backends/privacycash.ts +460 -0
  39. package/src/privacy-backends/registry.ts +278 -0
  40. package/src/privacy-backends/router.ts +346 -0
  41. package/src/privacy-backends/sip-native.ts +253 -0
  42. package/src/proofs/noir.ts +1 -1
  43. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  44. package/src/surveillance/algorithms/cluster.ts +247 -0
  45. package/src/surveillance/algorithms/exchange.ts +295 -0
  46. package/src/surveillance/algorithms/temporal.ts +337 -0
  47. package/src/surveillance/analyzer.ts +442 -0
  48. package/src/surveillance/index.ts +64 -0
  49. package/src/surveillance/scoring.ts +372 -0
  50. package/src/surveillance/types.ts +264 -0
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Helius RPC Provider
3
+ *
4
+ * Leverages Helius DAS (Digital Asset Standard) API for efficient
5
+ * token balance queries and asset metadata.
6
+ *
7
+ * @see https://docs.helius.dev/solana-apis/digital-asset-standard-das-api
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { HeliusProvider } from '@sip-protocol/sdk'
12
+ *
13
+ * const helius = new HeliusProvider({
14
+ * apiKey: process.env.HELIUS_API_KEY!,
15
+ * cluster: 'devnet'
16
+ * })
17
+ *
18
+ * const assets = await helius.getAssetsByOwner('7xK9...')
19
+ * console.log(assets) // [{ mint: '...', amount: 1000000n, decimals: 6, symbol: 'USDC' }]
20
+ * ```
21
+ */
22
+
23
+ import type { SolanaRPCProvider, TokenAsset, ProviderConfig } from './interface'
24
+
25
+ /**
26
+ * Helius API response types
27
+ */
28
+ interface HeliusDASAsset {
29
+ id: string
30
+ interface: string
31
+ content?: {
32
+ metadata?: {
33
+ name?: string
34
+ symbol?: string
35
+ }
36
+ links?: {
37
+ image?: string
38
+ }
39
+ }
40
+ token_info?: {
41
+ /** Balance as string to preserve precision for large values */
42
+ balance?: string | number
43
+ decimals?: number
44
+ symbol?: string
45
+ token_program?: string
46
+ mint_authority?: string
47
+ freeze_authority?: string
48
+ }
49
+ ownership?: {
50
+ owner: string
51
+ }
52
+ }
53
+
54
+ interface HeliusDASResponse {
55
+ jsonrpc: string
56
+ result?: {
57
+ items: HeliusDASAsset[]
58
+ total: number
59
+ limit: number
60
+ page: number
61
+ cursor?: string
62
+ }
63
+ error?: {
64
+ code: number
65
+ message: string
66
+ }
67
+ id: string
68
+ }
69
+
70
+ interface HeliusBalancesResponse {
71
+ tokens: Array<{
72
+ mint: string
73
+ amount: number
74
+ decimals: number
75
+ tokenAccount: string
76
+ }>
77
+ nativeBalance: number
78
+ }
79
+
80
+ /**
81
+ * Helius provider configuration
82
+ */
83
+ export interface HeliusProviderConfig extends ProviderConfig {
84
+ /** Helius API key (required) */
85
+ apiKey: string
86
+ /** Solana cluster (default: mainnet-beta) */
87
+ cluster?: 'mainnet-beta' | 'devnet'
88
+ }
89
+
90
+ /**
91
+ * Helius RPC Provider implementation
92
+ *
93
+ * Uses Helius DAS API for efficient token queries.
94
+ * Recommended for production deployments.
95
+ */
96
+ export class HeliusProvider implements SolanaRPCProvider {
97
+ readonly name = 'helius'
98
+ private apiKey: string
99
+ private cluster: 'mainnet-beta' | 'devnet'
100
+ private rpcUrl: string
101
+ private restUrl: string
102
+
103
+ constructor(config: HeliusProviderConfig) {
104
+ if (!config.apiKey) {
105
+ throw new Error('Helius API key is required. Get one at https://dev.helius.xyz')
106
+ }
107
+
108
+ this.apiKey = config.apiKey
109
+ this.cluster = config.cluster ?? 'mainnet-beta'
110
+
111
+ // RPC endpoint for DAS API
112
+ this.rpcUrl = this.cluster === 'devnet'
113
+ ? `https://devnet.helius-rpc.com/?api-key=${this.apiKey}`
114
+ : `https://mainnet.helius-rpc.com/?api-key=${this.apiKey}`
115
+
116
+ // REST endpoint for balances API
117
+ this.restUrl = this.cluster === 'devnet'
118
+ ? `https://api-devnet.helius.xyz/v0`
119
+ : `https://api.helius.xyz/v0`
120
+ }
121
+
122
+ /**
123
+ * Get all token assets owned by an address using DAS API
124
+ *
125
+ * Uses getAssetsByOwner for comprehensive asset information including
126
+ * NFTs and fungible tokens with metadata.
127
+ */
128
+ async getAssetsByOwner(owner: string): Promise<TokenAsset[]> {
129
+ const assets: TokenAsset[] = []
130
+ let page = 1
131
+ const limit = 1000
132
+ let hasMore = true
133
+
134
+ while (hasMore) {
135
+ const response = await fetch(this.rpcUrl, {
136
+ method: 'POST',
137
+ headers: { 'Content-Type': 'application/json' },
138
+ body: JSON.stringify({
139
+ jsonrpc: '2.0',
140
+ id: `sip-${Date.now()}`,
141
+ method: 'getAssetsByOwner',
142
+ params: {
143
+ ownerAddress: owner,
144
+ page,
145
+ limit,
146
+ displayOptions: {
147
+ showFungible: true,
148
+ showNativeBalance: false,
149
+ },
150
+ },
151
+ }),
152
+ })
153
+
154
+ if (!response.ok) {
155
+ throw new Error(`Helius API error: ${response.status} ${response.statusText}`)
156
+ }
157
+
158
+ const data = (await response.json()) as HeliusDASResponse
159
+
160
+ // Handle JSON-RPC errors
161
+ if (data.error) {
162
+ throw new Error(`Helius RPC error: ${data.error.message} (code: ${data.error.code})`)
163
+ }
164
+
165
+ if (data.result?.items) {
166
+ for (const item of data.result.items) {
167
+ // Skip NFTs (interface !== 'FungibleToken' and 'FungibleAsset')
168
+ if (item.interface !== 'FungibleToken' && item.interface !== 'FungibleAsset') {
169
+ continue
170
+ }
171
+
172
+ // Extract token info
173
+ const tokenInfo = item.token_info
174
+ if (!tokenInfo?.balance) continue
175
+
176
+ // Convert balance to BigInt, handling both string and number types
177
+ // String is preferred for large values to preserve precision
178
+ const balanceValue = typeof tokenInfo.balance === 'string'
179
+ ? BigInt(tokenInfo.balance)
180
+ : BigInt(Math.floor(tokenInfo.balance))
181
+
182
+ assets.push({
183
+ mint: item.id,
184
+ amount: balanceValue,
185
+ decimals: tokenInfo.decimals ?? 0,
186
+ symbol: tokenInfo.symbol ?? item.content?.metadata?.symbol,
187
+ name: item.content?.metadata?.name,
188
+ logoUri: item.content?.links?.image,
189
+ })
190
+ }
191
+ }
192
+
193
+ // Check if there are more pages
194
+ hasMore = data.result?.items?.length === limit
195
+ page++
196
+
197
+ // Safety limit to prevent infinite loops
198
+ if (page > 100) {
199
+ console.warn('[HeliusProvider] Reached page limit (100), stopping pagination')
200
+ break
201
+ }
202
+ }
203
+
204
+ return assets
205
+ }
206
+
207
+ /**
208
+ * Get token balance for a specific mint using Balances API
209
+ *
210
+ * More efficient than getAssetsByOwner when you only need one token's balance.
211
+ */
212
+ async getTokenBalance(owner: string, mint: string): Promise<bigint> {
213
+ try {
214
+ const url = `${this.restUrl}/addresses/${owner}/balances?api-key=${this.apiKey}`
215
+
216
+ const response = await fetch(url)
217
+
218
+ if (!response.ok) {
219
+ // Fallback to DAS if balances API fails
220
+ const assets = await this.getAssetsByOwner(owner)
221
+ const asset = assets.find((a) => a.mint === mint)
222
+ return asset?.amount ?? 0n
223
+ }
224
+
225
+ const data = (await response.json()) as HeliusBalancesResponse
226
+
227
+ const token = data.tokens?.find((t) => t.mint === mint)
228
+ return token ? BigInt(token.amount) : 0n
229
+ } catch (error) {
230
+ console.warn('[HeliusProvider] getTokenBalance error, falling back to DAS:', error)
231
+ const assets = await this.getAssetsByOwner(owner)
232
+ const asset = assets.find((a) => a.mint === mint)
233
+ return asset?.amount ?? 0n
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Check if provider supports real-time subscriptions
239
+ *
240
+ * Helius supports webhooks for real-time notifications,
241
+ * but that requires server-side setup. Client-side subscriptions
242
+ * are not directly supported.
243
+ */
244
+ supportsSubscriptions(): boolean {
245
+ // Helius has webhooks but not client-side subscriptions
246
+ // Return false for now, can be enhanced with webhook integration later
247
+ return false
248
+ }
249
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Solana RPC Providers
3
+ *
4
+ * SIP is RPC-provider-agnostic — developers choose their preferred provider.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { createProvider, scanForPayments } from '@sip-protocol/sdk'
9
+ *
10
+ * // Helius — efficient DAS queries (recommended for production)
11
+ * const helius = createProvider('helius', {
12
+ * apiKey: process.env.HELIUS_API_KEY!
13
+ * })
14
+ *
15
+ * // Generic — standard RPC, no API key needed
16
+ * const generic = createProvider('generic', {
17
+ * endpoint: 'https://api.devnet.solana.com'
18
+ * })
19
+ *
20
+ * // Same API, different backends
21
+ * const payments = await scanForPayments({
22
+ * provider: helius,
23
+ * viewingPrivateKey,
24
+ * spendingPublicKey,
25
+ * })
26
+ * ```
27
+ *
28
+ * @packageDocumentation
29
+ */
30
+
31
+ // Interface and factory
32
+ export {
33
+ createProvider,
34
+ type SolanaRPCProvider,
35
+ type TokenAsset,
36
+ type ProviderConfig,
37
+ type ProviderType,
38
+ type GenericProviderConfig,
39
+ } from './interface'
40
+
41
+ // Provider implementations
42
+ export { HeliusProvider, type HeliusProviderConfig } from './helius'
43
+ export { GenericProvider } from './generic'
44
+
45
+ // Webhook handler for real-time scanning
46
+ export {
47
+ createWebhookHandler,
48
+ processWebhookTransaction,
49
+ type HeliusWebhookTransaction,
50
+ type HeliusEnhancedTransaction,
51
+ type HeliusWebhookPayload,
52
+ type WebhookHandlerConfig,
53
+ type WebhookProcessResult,
54
+ } from './webhook'
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Solana RPC Provider Interface
3
+ *
4
+ * SIP is RPC-provider-agnostic — developers choose their preferred provider.
5
+ * Each provider has unique moats we leverage through this unified interface.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { createProvider, scanForPayments } from '@sip-protocol/sdk'
10
+ *
11
+ * // Helius — efficient DAS queries (recommended for production)
12
+ * const helius = createProvider('helius', { apiKey: process.env.HELIUS_API_KEY })
13
+ *
14
+ * // Generic — standard RPC, no API key needed
15
+ * const generic = createProvider('generic', { connection })
16
+ *
17
+ * // Same API, different backends
18
+ * const payments = await scanForPayments({
19
+ * provider: helius,
20
+ * viewingPrivateKey,
21
+ * spendingPublicKey,
22
+ * })
23
+ * ```
24
+ *
25
+ * @packageDocumentation
26
+ */
27
+
28
+ import { HeliusProvider, type HeliusProviderConfig } from './helius'
29
+ import { GenericProvider } from './generic'
30
+
31
+ /**
32
+ * Token asset information returned by providers
33
+ */
34
+ export interface TokenAsset {
35
+ /** SPL token mint address */
36
+ mint: string
37
+ /** Token amount in smallest units */
38
+ amount: bigint
39
+ /** Token decimals */
40
+ decimals: number
41
+ /** Token symbol (e.g., 'USDC') */
42
+ symbol?: string
43
+ /** Token name (e.g., 'USD Coin') */
44
+ name?: string
45
+ /** Token logo URI */
46
+ logoUri?: string
47
+ }
48
+
49
+ /**
50
+ * Configuration for RPC providers
51
+ */
52
+ export interface ProviderConfig {
53
+ /** API key for premium providers (Helius, QuickNode) */
54
+ apiKey?: string
55
+ /** Custom RPC endpoint */
56
+ endpoint?: string
57
+ /** Solana cluster */
58
+ cluster?: 'mainnet-beta' | 'devnet' | 'testnet'
59
+ }
60
+
61
+ /**
62
+ * Unified interface for Solana RPC providers
63
+ *
64
+ * All provider adapters must implement this interface to ensure
65
+ * consistent behavior across different RPC backends.
66
+ */
67
+ export interface SolanaRPCProvider {
68
+ /** Provider name for logging/debugging */
69
+ readonly name: string
70
+
71
+ /**
72
+ * Get all token assets owned by an address
73
+ *
74
+ * @param owner - Solana address (base58)
75
+ * @returns Array of token assets with balances
76
+ */
77
+ getAssetsByOwner(owner: string): Promise<TokenAsset[]>
78
+
79
+ /**
80
+ * Get token balance for a specific mint
81
+ *
82
+ * @param owner - Solana address (base58)
83
+ * @param mint - SPL token mint address (base58)
84
+ * @returns Token balance in smallest units, 0n if no balance
85
+ */
86
+ getTokenBalance(owner: string, mint: string): Promise<bigint>
87
+
88
+ /**
89
+ * Check if provider supports real-time subscriptions
90
+ *
91
+ * @returns true if subscribeToTransfers is available
92
+ */
93
+ supportsSubscriptions(): boolean
94
+
95
+ /**
96
+ * Subscribe to token transfers for an address (optional)
97
+ *
98
+ * Only available if supportsSubscriptions() returns true.
99
+ *
100
+ * @param address - Solana address to watch
101
+ * @param callback - Called when a transfer is detected
102
+ * @returns Unsubscribe function
103
+ */
104
+ subscribeToTransfers?(
105
+ address: string,
106
+ callback: (asset: TokenAsset) => void
107
+ ): Promise<() => void>
108
+ }
109
+
110
+ /**
111
+ * Provider type for factory function
112
+ */
113
+ export type ProviderType = 'helius' | 'quicknode' | 'triton' | 'generic'
114
+
115
+ /**
116
+ * Extended config for generic provider that accepts a Connection
117
+ */
118
+ export interface GenericProviderConfig extends ProviderConfig {
119
+ /** Existing Solana Connection object */
120
+ connection?: unknown // Typed as unknown to avoid @solana/web3.js dependency in interface
121
+ }
122
+
123
+ /**
124
+ * Create an RPC provider instance
125
+ *
126
+ * @param type - Provider type ('helius', 'quicknode', 'triton', 'generic')
127
+ * @param config - Provider configuration
128
+ * @returns Configured provider instance
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // Helius with API key
133
+ * const helius = createProvider('helius', {
134
+ * apiKey: process.env.HELIUS_API_KEY,
135
+ * cluster: 'devnet'
136
+ * })
137
+ *
138
+ * // Generic with existing connection
139
+ * const generic = createProvider('generic', { connection })
140
+ *
141
+ * // Generic with endpoint
142
+ * const devnet = createProvider('generic', {
143
+ * endpoint: 'https://api.devnet.solana.com'
144
+ * })
145
+ * ```
146
+ */
147
+ export function createProvider(
148
+ type: 'helius',
149
+ config: ProviderConfig & { apiKey: string }
150
+ ): SolanaRPCProvider
151
+ export function createProvider(
152
+ type: 'generic',
153
+ config: GenericProviderConfig
154
+ ): SolanaRPCProvider
155
+ export function createProvider(
156
+ type: ProviderType,
157
+ config: ProviderConfig | GenericProviderConfig
158
+ ): SolanaRPCProvider
159
+ export function createProvider(
160
+ type: ProviderType,
161
+ config: ProviderConfig | GenericProviderConfig
162
+ ): SolanaRPCProvider {
163
+ switch (type) {
164
+ case 'helius':
165
+ return new HeliusProvider(config as HeliusProviderConfig)
166
+ case 'generic':
167
+ return new GenericProvider(config as GenericProviderConfig)
168
+ case 'quicknode':
169
+ case 'triton':
170
+ throw new Error(
171
+ `Provider '${type}' is not yet implemented. ` +
172
+ `Use 'helius' or 'generic' for now. ` +
173
+ `See https://github.com/sip-protocol/sip-protocol/issues/${type === 'quicknode' ? '494' : '495'}`
174
+ )
175
+ default:
176
+ throw new Error(`Unknown provider type: ${type}`)
177
+ }
178
+ }