@sip-protocol/sdk 0.7.3 → 0.7.4

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 (264) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  4. package/dist/browser.d.mts +10 -4
  5. package/dist/browser.d.ts +10 -4
  6. package/dist/browser.js +47556 -19603
  7. package/dist/browser.mjs +628 -48
  8. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  9. package/dist/chunk-5D7A3L3W.mjs +717 -0
  10. package/dist/chunk-64AYA5F5.mjs +7834 -0
  11. package/dist/chunk-GMDGB22A.mjs +379 -0
  12. package/dist/chunk-I534WKN7.mjs +328 -0
  13. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  14. package/dist/chunk-PRRZAWJE.mjs +223 -0
  15. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  16. package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
  17. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  18. package/dist/constants-LHAAUC2T.mjs +51 -0
  19. package/dist/dist-2OGQ7FED.mjs +3957 -0
  20. package/dist/dist-IFHPYLDX.mjs +254 -0
  21. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  22. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  23. package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
  24. package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48396 -19623
  28. package/dist/index.mjs +537 -19
  29. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  30. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  31. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  32. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  33. package/dist/proofs/halo2.d.mts +151 -0
  34. package/dist/proofs/halo2.d.ts +151 -0
  35. package/dist/proofs/halo2.js +350 -0
  36. package/dist/proofs/halo2.mjs +11 -0
  37. package/dist/proofs/kimchi.d.mts +160 -0
  38. package/dist/proofs/kimchi.d.ts +160 -0
  39. package/dist/proofs/kimchi.js +431 -0
  40. package/dist/proofs/kimchi.mjs +13 -0
  41. package/dist/proofs/noir.d.mts +1 -1
  42. package/dist/proofs/noir.d.ts +1 -1
  43. package/dist/proofs/noir.js +74 -18
  44. package/dist/proofs/noir.mjs +84 -24
  45. package/dist/solana-U3MEGU7W.mjs +280 -0
  46. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  47. package/package.json +54 -21
  48. package/src/adapters/index.ts +41 -0
  49. package/src/adapters/jupiter.ts +571 -0
  50. package/src/adapters/near-intents.ts +135 -0
  51. package/src/advisor/advisor.ts +653 -0
  52. package/src/advisor/index.ts +54 -0
  53. package/src/advisor/tools.ts +303 -0
  54. package/src/advisor/types.ts +164 -0
  55. package/src/chains/ethereum/announcement.ts +536 -0
  56. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  57. package/src/chains/ethereum/commitment.ts +522 -0
  58. package/src/chains/ethereum/constants.ts +462 -0
  59. package/src/chains/ethereum/deployment.ts +596 -0
  60. package/src/chains/ethereum/gas-estimation.ts +538 -0
  61. package/src/chains/ethereum/index.ts +268 -0
  62. package/src/chains/ethereum/optimizations.ts +614 -0
  63. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  64. package/src/chains/ethereum/registry.ts +584 -0
  65. package/src/chains/ethereum/rpc.ts +905 -0
  66. package/src/chains/ethereum/stealth.ts +491 -0
  67. package/src/chains/ethereum/token.ts +790 -0
  68. package/src/chains/ethereum/transfer.ts +637 -0
  69. package/src/chains/ethereum/types.ts +456 -0
  70. package/src/chains/ethereum/viewing-key.ts +455 -0
  71. package/src/chains/near/commitment.ts +608 -0
  72. package/src/chains/near/constants.ts +284 -0
  73. package/src/chains/near/function-call.ts +871 -0
  74. package/src/chains/near/history.ts +654 -0
  75. package/src/chains/near/implicit-account.ts +840 -0
  76. package/src/chains/near/index.ts +393 -0
  77. package/src/chains/near/native-transfer.ts +658 -0
  78. package/src/chains/near/nep141.ts +775 -0
  79. package/src/chains/near/privacy-adapter.ts +889 -0
  80. package/src/chains/near/resolver.ts +971 -0
  81. package/src/chains/near/rpc.ts +1016 -0
  82. package/src/chains/near/stealth.ts +419 -0
  83. package/src/chains/near/types.ts +317 -0
  84. package/src/chains/near/viewing-key.ts +876 -0
  85. package/src/chains/solana/anchor-transfer.ts +386 -0
  86. package/src/chains/solana/commitment.ts +577 -0
  87. package/src/chains/solana/constants.ts +126 -12
  88. package/src/chains/solana/ephemeral-keys.ts +543 -0
  89. package/src/chains/solana/index.ts +252 -1
  90. package/src/chains/solana/key-derivation.ts +418 -0
  91. package/src/chains/solana/kit-compat.ts +334 -0
  92. package/src/chains/solana/optimizations.ts +560 -0
  93. package/src/chains/solana/privacy-adapter.ts +605 -0
  94. package/src/chains/solana/providers/generic.ts +47 -6
  95. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  96. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  97. package/src/chains/solana/providers/helius.ts +186 -33
  98. package/src/chains/solana/providers/index.ts +31 -0
  99. package/src/chains/solana/providers/interface.ts +61 -18
  100. package/src/chains/solana/providers/quicknode.ts +409 -0
  101. package/src/chains/solana/providers/triton.ts +426 -0
  102. package/src/chains/solana/providers/webhook.ts +338 -67
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +83 -66
  105. package/src/chains/solana/sol-transfer.ts +732 -0
  106. package/src/chains/solana/spl-transfer.ts +886 -0
  107. package/src/chains/solana/stealth-scanner.ts +703 -0
  108. package/src/chains/solana/sunspot-verifier.ts +453 -0
  109. package/src/chains/solana/transaction-builder.ts +755 -0
  110. package/src/chains/solana/transfer.ts +74 -5
  111. package/src/chains/solana/types.ts +57 -6
  112. package/src/chains/solana/utils.ts +110 -0
  113. package/src/chains/solana/viewing-key.ts +807 -0
  114. package/src/compliance/fireblocks.ts +921 -0
  115. package/src/compliance/index.ts +23 -0
  116. package/src/compliance/range-sas.ts +398 -33
  117. package/src/config/endpoints.ts +100 -0
  118. package/src/crypto.ts +11 -8
  119. package/src/errors.ts +82 -0
  120. package/src/evm/erc4337-relayer.ts +830 -0
  121. package/src/evm/index.ts +47 -0
  122. package/src/fees/calculator.ts +396 -0
  123. package/src/fees/index.ts +87 -0
  124. package/src/fees/near-contract.ts +429 -0
  125. package/src/fees/types.ts +268 -0
  126. package/src/index.ts +686 -1
  127. package/src/intent.ts +6 -3
  128. package/src/logger.ts +324 -0
  129. package/src/network/index.ts +80 -0
  130. package/src/network/proxy.ts +691 -0
  131. package/src/optimizations/index.ts +541 -0
  132. package/src/oracle/types.ts +1 -0
  133. package/src/privacy-backends/arcium-types.ts +727 -0
  134. package/src/privacy-backends/arcium.ts +719 -0
  135. package/src/privacy-backends/combined-privacy.ts +866 -0
  136. package/src/privacy-backends/cspl-token.ts +595 -0
  137. package/src/privacy-backends/cspl-types.ts +512 -0
  138. package/src/privacy-backends/cspl.ts +907 -0
  139. package/src/privacy-backends/health.ts +488 -0
  140. package/src/privacy-backends/inco-types.ts +323 -0
  141. package/src/privacy-backends/inco.ts +616 -0
  142. package/src/privacy-backends/index.ts +254 -4
  143. package/src/privacy-backends/interface.ts +649 -6
  144. package/src/privacy-backends/lru-cache.ts +343 -0
  145. package/src/privacy-backends/magicblock.ts +458 -0
  146. package/src/privacy-backends/mock.ts +258 -0
  147. package/src/privacy-backends/privacycash.ts +13 -17
  148. package/src/privacy-backends/private-swap.ts +570 -0
  149. package/src/privacy-backends/rate-limiter.ts +683 -0
  150. package/src/privacy-backends/registry.ts +414 -2
  151. package/src/privacy-backends/router.ts +283 -3
  152. package/src/privacy-backends/shadowwire.ts +449 -0
  153. package/src/privacy-backends/sip-native.ts +3 -0
  154. package/src/privacy-logger.ts +191 -0
  155. package/src/production-safety.ts +373 -0
  156. package/src/proofs/aggregator.ts +1029 -0
  157. package/src/proofs/browser-composer.ts +1150 -0
  158. package/src/proofs/browser.ts +113 -25
  159. package/src/proofs/cache/index.ts +127 -0
  160. package/src/proofs/cache/interface.ts +545 -0
  161. package/src/proofs/cache/key-generator.ts +188 -0
  162. package/src/proofs/cache/lru-cache.ts +481 -0
  163. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  164. package/src/proofs/cache/persistent-cache.ts +788 -0
  165. package/src/proofs/compliance-proof.ts +872 -0
  166. package/src/proofs/composer/base.ts +923 -0
  167. package/src/proofs/composer/index.ts +25 -0
  168. package/src/proofs/composer/interface.ts +518 -0
  169. package/src/proofs/composer/types.ts +383 -0
  170. package/src/proofs/converters/halo2.ts +452 -0
  171. package/src/proofs/converters/index.ts +208 -0
  172. package/src/proofs/converters/interface.ts +363 -0
  173. package/src/proofs/converters/kimchi.ts +462 -0
  174. package/src/proofs/converters/noir.ts +451 -0
  175. package/src/proofs/fallback.ts +888 -0
  176. package/src/proofs/halo2.ts +42 -0
  177. package/src/proofs/index.ts +471 -0
  178. package/src/proofs/interface.ts +13 -0
  179. package/src/proofs/kimchi.ts +42 -0
  180. package/src/proofs/lazy.ts +1004 -0
  181. package/src/proofs/mock.ts +25 -1
  182. package/src/proofs/noir.ts +110 -29
  183. package/src/proofs/orchestrator.ts +960 -0
  184. package/src/proofs/parallel/concurrency.ts +297 -0
  185. package/src/proofs/parallel/dependency-graph.ts +602 -0
  186. package/src/proofs/parallel/executor.ts +420 -0
  187. package/src/proofs/parallel/index.ts +131 -0
  188. package/src/proofs/parallel/interface.ts +685 -0
  189. package/src/proofs/parallel/worker-pool.ts +644 -0
  190. package/src/proofs/providers/halo2.ts +560 -0
  191. package/src/proofs/providers/index.ts +34 -0
  192. package/src/proofs/providers/kimchi.ts +641 -0
  193. package/src/proofs/validator.ts +881 -0
  194. package/src/proofs/verifier.ts +867 -0
  195. package/src/quantum/index.ts +112 -0
  196. package/src/quantum/winternitz-vault.ts +639 -0
  197. package/src/quantum/wots.ts +611 -0
  198. package/src/settlement/backends/direct-chain.ts +1 -0
  199. package/src/settlement/index.ts +9 -0
  200. package/src/settlement/router.ts +732 -46
  201. package/src/solana/index.ts +72 -0
  202. package/src/solana/jito-relayer.ts +687 -0
  203. package/src/solana/noir-verifier-types.ts +430 -0
  204. package/src/solana/noir-verifier.ts +816 -0
  205. package/src/stealth/address-derivation.ts +193 -0
  206. package/src/stealth/ed25519.ts +431 -0
  207. package/src/stealth/index.ts +233 -0
  208. package/src/stealth/meta-address.ts +221 -0
  209. package/src/stealth/secp256k1.ts +368 -0
  210. package/src/stealth/utils.ts +194 -0
  211. package/src/stealth.ts +50 -1504
  212. package/src/sync/index.ts +106 -0
  213. package/src/sync/manager.ts +504 -0
  214. package/src/sync/mock-provider.ts +318 -0
  215. package/src/sync/oblivious.ts +625 -0
  216. package/src/tokens/index.ts +15 -0
  217. package/src/tokens/registry.ts +301 -0
  218. package/src/utils/deprecation.ts +94 -0
  219. package/src/utils/index.ts +9 -0
  220. package/src/wallet/ethereum/index.ts +68 -0
  221. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  222. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  223. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  224. package/src/wallet/ethereum/types.ts +3 -1
  225. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  226. package/src/wallet/hardware/index.ts +10 -0
  227. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  228. package/src/wallet/index.ts +71 -0
  229. package/src/wallet/near/adapter.ts +626 -0
  230. package/src/wallet/near/index.ts +86 -0
  231. package/src/wallet/near/meteor-wallet.ts +1153 -0
  232. package/src/wallet/near/my-near-wallet.ts +790 -0
  233. package/src/wallet/near/wallet-selector.ts +702 -0
  234. package/src/wallet/solana/adapter.ts +6 -4
  235. package/src/wallet/solana/index.ts +13 -0
  236. package/src/wallet/solana/privacy-adapter.ts +567 -0
  237. package/src/wallet/sui/types.ts +6 -4
  238. package/src/zcash/rpc-client.ts +13 -6
  239. package/dist/chunk-2XIVXWHA.mjs +0 -1930
  240. package/dist/chunk-3INS3PR5.mjs +0 -884
  241. package/dist/chunk-3OVABDRH.mjs +0 -17096
  242. package/dist/chunk-7RFRWDCW.mjs +0 -1504
  243. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  244. package/dist/chunk-E6SZWREQ.mjs +0 -57
  245. package/dist/chunk-F6F73W35.mjs +0 -16166
  246. package/dist/chunk-G33LB27A.mjs +0 -16166
  247. package/dist/chunk-HGU6HZRC.mjs +0 -231
  248. package/dist/chunk-L2K34JCU.mjs +0 -1496
  249. package/dist/chunk-OFDBEIEK.mjs +0 -16166
  250. package/dist/chunk-SF7YSLF5.mjs +0 -1515
  251. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  252. package/dist/chunk-WWUSGOXE.mjs +0 -17129
  253. package/dist/constants-VOI7BSLK.mjs +0 -27
  254. package/dist/index-B71aXVzk.d.ts +0 -13264
  255. package/dist/index-BYZbDjal.d.ts +0 -11390
  256. package/dist/index-CHB3KuOB.d.mts +0 -11859
  257. package/dist/index-CzWPI6Le.d.ts +0 -11859
  258. package/dist/index-pOIIuwfV.d.mts +0 -13264
  259. package/dist/index-xbWjohNq.d.mts +0 -11390
  260. package/dist/solana-4O4K45VU.mjs +0 -46
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-NDABAZ6P.mjs +0 -56
  263. package/dist/solana-Q4NAVBTS.mjs +0 -46
  264. package/dist/solana-ZYO63LY5.mjs +0 -46
@@ -0,0 +1,426 @@
1
+ /**
2
+ * Triton RPC Provider
3
+ *
4
+ * Leverages Triton's high-performance Solana RPC for queries and
5
+ * Dragon's Mouth gRPC (Yellowstone) for real-time streaming.
6
+ *
7
+ * Triton is known for ultra-low latency (~400ms advantage over WebSocket)
8
+ * and multi-region failover for high availability.
9
+ *
10
+ * @see https://docs.triton.one/chains/solana
11
+ * @see https://docs.triton.one/project-yellowstone/dragons-mouth-grpc-subscriptions
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { TritonProvider } from '@sip-protocol/sdk'
16
+ *
17
+ * const triton = new TritonProvider({
18
+ * xToken: process.env.TRITON_TOKEN!,
19
+ * cluster: 'mainnet-beta'
20
+ * })
21
+ *
22
+ * // Query assets (standard RPC)
23
+ * const assets = await triton.getAssetsByOwner('7xK9...')
24
+ *
25
+ * // Real-time subscriptions (Dragon's Mouth gRPC)
26
+ * if (triton.supportsSubscriptions()) {
27
+ * const unsubscribe = await triton.subscribeToTransfers('7xK9...', (asset) => {
28
+ * console.log('Transfer received:', asset)
29
+ * })
30
+ * }
31
+ * ```
32
+ */
33
+
34
+ import {
35
+ Connection,
36
+ PublicKey,
37
+ } from '@solana/web3.js'
38
+ import {
39
+ TOKEN_PROGRAM_ID,
40
+ getAssociatedTokenAddress,
41
+ getAccount,
42
+ getMint,
43
+ } from '@solana/spl-token'
44
+ import Client, {
45
+ CommitmentLevel,
46
+ type SubscribeRequest,
47
+ type SubscribeUpdate,
48
+ } from '@triton-one/yellowstone-grpc'
49
+ import type { ClientDuplexStream } from '@grpc/grpc-js'
50
+ import { base58 } from '@scure/base'
51
+ import type { SolanaRPCProvider, TokenAsset, ProviderConfig } from './interface'
52
+
53
+ /**
54
+ * Type alias for Yellowstone gRPC subscription stream
55
+ */
56
+ type GrpcSubscriptionStream = ClientDuplexStream<SubscribeRequest, SubscribeUpdate>
57
+
58
+ import { ValidationError, ErrorCode } from '../../../errors'
59
+
60
+ /**
61
+ * Triton provider configuration
62
+ */
63
+ export interface TritonProviderConfig extends ProviderConfig {
64
+ /**
65
+ * Triton x-token for authentication
66
+ */
67
+ xToken: string
68
+ /**
69
+ * Custom RPC endpoint (optional)
70
+ * Default: https://mainnet.rpcpool.com or https://devnet.rpcpool.com
71
+ */
72
+ endpoint?: string
73
+ /**
74
+ * Custom gRPC endpoint (optional)
75
+ * Default: https://grpc.rpcpool.com:443
76
+ */
77
+ grpcEndpoint?: string
78
+ /**
79
+ * Solana cluster (default: mainnet-beta)
80
+ */
81
+ cluster?: 'mainnet-beta' | 'devnet'
82
+ /**
83
+ * Enable Dragon's Mouth gRPC for real-time subscriptions
84
+ * @default true
85
+ */
86
+ enableGrpc?: boolean
87
+ }
88
+
89
+ /**
90
+ * Default Triton endpoints by cluster
91
+ */
92
+ const TRITON_RPC_ENDPOINTS: Record<string, string> = {
93
+ 'mainnet-beta': 'https://mainnet.rpcpool.com',
94
+ devnet: 'https://devnet.rpcpool.com',
95
+ }
96
+
97
+ /**
98
+ * Default Triton gRPC endpoints by cluster
99
+ */
100
+ const TRITON_GRPC_ENDPOINTS: Record<string, string> = {
101
+ 'mainnet-beta': 'https://grpc.rpcpool.com:443',
102
+ devnet: 'https://grpc-devnet.rpcpool.com:443',
103
+ }
104
+
105
+ /**
106
+ * Validate a Solana address (base58)
107
+ * @throws Error if address is invalid
108
+ */
109
+ function validateSolanaAddress(address: string, paramName: string): PublicKey {
110
+ try {
111
+ return new PublicKey(address)
112
+ } catch {
113
+ throw new ValidationError('invalid Solana address format', paramName, undefined, ErrorCode.INVALID_ADDRESS)
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Triton RPC Provider implementation
119
+ *
120
+ * Uses Triton's high-performance RPC for queries and Dragon's Mouth
121
+ * gRPC for real-time subscriptions. Known for ultra-low latency and
122
+ * high availability, ideal for DeFi and trading applications.
123
+ */
124
+ export class TritonProvider implements SolanaRPCProvider {
125
+ readonly name = 'triton'
126
+ private connection: Connection
127
+ private grpcEndpoint: string
128
+ private xToken: string
129
+ private grpcEnabled: boolean
130
+ private grpcClient: Client | null = null
131
+ /** Active gRPC subscription streams */
132
+ private activeStreams: Set<GrpcSubscriptionStream> = new Set()
133
+ /** Cache for mint decimals to avoid repeated RPC calls */
134
+ private mintDecimalsCache: Map<string, number> = new Map()
135
+
136
+ constructor(config: TritonProviderConfig) {
137
+ if (!config.xToken) {
138
+ throw new ValidationError(
139
+ 'x-token is required. Get one at https://triton.one/',
140
+ 'xToken',
141
+ undefined,
142
+ ErrorCode.MISSING_REQUIRED
143
+ )
144
+ }
145
+
146
+ const cluster = config.cluster ?? 'mainnet-beta'
147
+ const rpcEndpoint = config.endpoint ?? TRITON_RPC_ENDPOINTS[cluster]
148
+
149
+ // Append x-token to RPC endpoint
150
+ const normalizedEndpoint = rpcEndpoint.replace(/\/$/, '') // Remove trailing slash
151
+ const rpcUrl = normalizedEndpoint.includes('?')
152
+ ? `${normalizedEndpoint}&x-token=${config.xToken}`
153
+ : `${normalizedEndpoint}/${config.xToken}`
154
+
155
+ this.connection = new Connection(rpcUrl, 'confirmed')
156
+ this.grpcEndpoint = config.grpcEndpoint ?? TRITON_GRPC_ENDPOINTS[cluster]
157
+ this.xToken = config.xToken
158
+ this.grpcEnabled = config.enableGrpc !== false
159
+ }
160
+
161
+ /**
162
+ * Get all token assets owned by an address using standard RPC
163
+ *
164
+ * Uses getParsedTokenAccountsByOwner for comprehensive asset information.
165
+ */
166
+ async getAssetsByOwner(owner: string): Promise<TokenAsset[]> {
167
+ const ownerPubkey = validateSolanaAddress(owner, 'owner')
168
+
169
+ const accounts = await this.connection.getParsedTokenAccountsByOwner(
170
+ ownerPubkey,
171
+ { programId: TOKEN_PROGRAM_ID }
172
+ )
173
+
174
+ const assets: TokenAsset[] = []
175
+
176
+ for (const { account } of accounts.value) {
177
+ const parsed = account.data.parsed
178
+ if (parsed.type !== 'account') continue
179
+
180
+ const info = parsed.info
181
+ const amount = BigInt(info.tokenAmount.amount)
182
+
183
+ // Skip zero balances
184
+ if (amount === 0n) continue
185
+
186
+ assets.push({
187
+ mint: info.mint,
188
+ amount,
189
+ decimals: info.tokenAmount.decimals,
190
+ // Standard RPC doesn't provide symbol/name, those need metadata lookup
191
+ symbol: undefined,
192
+ name: undefined,
193
+ logoUri: undefined,
194
+ })
195
+ }
196
+
197
+ return assets
198
+ }
199
+
200
+ /**
201
+ * Get token balance for a specific mint
202
+ *
203
+ * Uses getAccount on the associated token address.
204
+ */
205
+ async getTokenBalance(owner: string, mint: string): Promise<bigint> {
206
+ const ownerPubkey = validateSolanaAddress(owner, 'owner')
207
+ const mintPubkey = validateSolanaAddress(mint, 'mint')
208
+
209
+ try {
210
+ const ata = await getAssociatedTokenAddress(
211
+ mintPubkey,
212
+ ownerPubkey,
213
+ true // allowOwnerOffCurve for PDAs
214
+ )
215
+
216
+ const account = await getAccount(this.connection, ata)
217
+ return account.amount
218
+ } catch {
219
+ // Account doesn't exist or other RPC error
220
+ return 0n
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Check if provider supports real-time subscriptions
226
+ *
227
+ * Triton supports Dragon's Mouth gRPC (Yellowstone) for
228
+ * real-time streaming with ~400ms latency advantage.
229
+ */
230
+ supportsSubscriptions(): boolean {
231
+ return this.grpcEnabled
232
+ }
233
+
234
+ /**
235
+ * Get token decimals from mint metadata with caching
236
+ *
237
+ * @param mint - Token mint address (base58)
238
+ * @returns Token decimals (0-18), defaults to 9 if fetch fails
239
+ */
240
+ private async getMintDecimals(mint: string): Promise<number> {
241
+ // Check cache first
242
+ const cached = this.mintDecimalsCache.get(mint)
243
+ if (cached !== undefined) {
244
+ return cached
245
+ }
246
+
247
+ try {
248
+ const mintPubkey = new PublicKey(mint)
249
+ const mintInfo = await getMint(this.connection, mintPubkey)
250
+ const decimals = mintInfo.decimals
251
+ this.mintDecimalsCache.set(mint, decimals)
252
+ return decimals
253
+ } catch {
254
+ // Default to 9 (SOL decimals) if fetch fails
255
+ // This is a safe fallback since most Solana tokens use 9 decimals
256
+ return 9
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Initialize gRPC client lazily
262
+ */
263
+ private async getGrpcClient(): Promise<Client> {
264
+ if (!this.grpcEnabled) {
265
+ throw new ValidationError(
266
+ 'gRPC subscriptions are disabled. Set enableGrpc: true in config',
267
+ 'enableGrpc',
268
+ undefined,
269
+ ErrorCode.INVALID_INPUT
270
+ )
271
+ }
272
+
273
+ if (!this.grpcClient) {
274
+ // Triton uses x-token for gRPC authentication
275
+ this.grpcClient = new Client(this.grpcEndpoint, this.xToken, {})
276
+ }
277
+
278
+ return this.grpcClient
279
+ }
280
+
281
+ /**
282
+ * Subscribe to token transfers for an address
283
+ *
284
+ * Uses Dragon's Mouth gRPC to receive real-time notifications when
285
+ * tokens are transferred to the specified address.
286
+ *
287
+ * Dragon's Mouth provides ~400ms latency advantage over WebSocket,
288
+ * making it ideal for DeFi and trading applications.
289
+ *
290
+ * @param address - Solana address to watch for incoming transfers
291
+ * @param callback - Called when a transfer is detected
292
+ * @returns Unsubscribe function
293
+ */
294
+ async subscribeToTransfers(
295
+ address: string,
296
+ callback: (asset: TokenAsset) => void
297
+ ): Promise<() => void> {
298
+ validateSolanaAddress(address, 'address')
299
+
300
+ const client = await this.getGrpcClient()
301
+ const stream = await client.subscribe()
302
+
303
+ this.activeStreams.add(stream)
304
+
305
+ // Handle incoming data
306
+ stream.on('data', (update) => {
307
+ // Check for account update
308
+ if (update.account?.account) {
309
+ const accountData = update.account.account
310
+
311
+ // Only process token account updates
312
+ if (accountData.owner?.toString() === TOKEN_PROGRAM_ID.toBase58()) {
313
+ try {
314
+ // Parse SPL Token account data
315
+ // Token account structure: mint (32) + owner (32) + amount (8) + ...
316
+ const data = accountData.data
317
+ if (data && data.length >= 72) {
318
+ const mint = new PublicKey(data.slice(0, 32)).toBase58()
319
+ const amount = BigInt(
320
+ '0x' + Buffer.from(data.slice(64, 72)).reverse().toString('hex')
321
+ )
322
+
323
+ if (amount > 0n) {
324
+ // Fetch decimals asynchronously and invoke callback
325
+ this.getMintDecimals(mint).then((decimals) => {
326
+ callback({
327
+ mint,
328
+ amount,
329
+ decimals,
330
+ symbol: undefined,
331
+ name: undefined,
332
+ logoUri: undefined,
333
+ })
334
+ }).catch(() => {
335
+ // Still invoke callback with default decimals on error
336
+ callback({
337
+ mint,
338
+ amount,
339
+ decimals: 9,
340
+ symbol: undefined,
341
+ name: undefined,
342
+ logoUri: undefined,
343
+ })
344
+ })
345
+ }
346
+ }
347
+ } catch {
348
+ // Skip malformed account data
349
+ }
350
+ }
351
+ }
352
+ })
353
+
354
+ stream.on('error', (err) => {
355
+ console.error('[TritonProvider] gRPC stream error:', err.message)
356
+ this.activeStreams.delete(stream)
357
+ })
358
+
359
+ stream.on('end', () => {
360
+ this.activeStreams.delete(stream)
361
+ })
362
+
363
+ // Create subscription request for token accounts owned by address
364
+ const request: SubscribeRequest = {
365
+ accounts: {
366
+ stealth: {
367
+ account: [],
368
+ owner: [TOKEN_PROGRAM_ID.toBase58()],
369
+ filters: [
370
+ {
371
+ memcmp: {
372
+ offset: '32', // Owner field offset in token account
373
+ bytes: new Uint8Array(base58.decode(address)),
374
+ },
375
+ },
376
+ ],
377
+ },
378
+ },
379
+ commitment: CommitmentLevel.CONFIRMED,
380
+ accountsDataSlice: [],
381
+ slots: {},
382
+ transactions: {},
383
+ transactionsStatus: {},
384
+ blocks: {},
385
+ blocksMeta: {},
386
+ entry: {},
387
+ }
388
+
389
+ // Send subscription request
390
+ await new Promise<void>((resolve, reject) => {
391
+ stream.write(request, (err: Error | null | undefined) => {
392
+ if (err) {
393
+ reject(err)
394
+ } else {
395
+ resolve()
396
+ }
397
+ })
398
+ })
399
+
400
+ // Return unsubscribe function
401
+ return () => {
402
+ stream.end()
403
+ this.activeStreams.delete(stream)
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Get the underlying Connection object
409
+ *
410
+ * Useful for advanced operations that need direct RPC access.
411
+ */
412
+ getConnection(): Connection {
413
+ return this.connection
414
+ }
415
+
416
+ /**
417
+ * Close all active subscriptions and cleanup resources
418
+ */
419
+ async close(): Promise<void> {
420
+ for (const stream of this.activeStreams) {
421
+ stream.end()
422
+ }
423
+ this.activeStreams.clear()
424
+ this.grpcClient = null
425
+ }
426
+ }