@sip-protocol/sdk 0.7.2 → 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 (262) 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 +48874 -18336
  7. package/dist/browser.mjs +674 -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-YWGJ77A2.mjs +33806 -0
  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-DXh2IGkz.d.ts +24681 -0
  24. package/dist/index-DeE1ZzA4.d.mts +24681 -0
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48676 -17318
  28. package/dist/index.mjs +583 -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 +276 -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 +201 -0
  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 +402 -0
  98. package/src/chains/solana/providers/index.ts +85 -0
  99. package/src/chains/solana/providers/interface.ts +221 -0
  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 +790 -0
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +170 -73
  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 +77 -7
  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 +37 -0
  116. package/src/compliance/range-sas.ts +956 -0
  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 +785 -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 +336 -0
  143. package/src/privacy-backends/interface.ts +906 -0
  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-types.ts +278 -0
  148. package/src/privacy-backends/privacycash.ts +456 -0
  149. package/src/privacy-backends/private-swap.ts +570 -0
  150. package/src/privacy-backends/rate-limiter.ts +683 -0
  151. package/src/privacy-backends/registry.ts +690 -0
  152. package/src/privacy-backends/router.ts +626 -0
  153. package/src/privacy-backends/shadowwire.ts +449 -0
  154. package/src/privacy-backends/sip-native.ts +256 -0
  155. package/src/privacy-logger.ts +191 -0
  156. package/src/production-safety.ts +373 -0
  157. package/src/proofs/aggregator.ts +1029 -0
  158. package/src/proofs/browser-composer.ts +1150 -0
  159. package/src/proofs/browser.ts +113 -25
  160. package/src/proofs/cache/index.ts +127 -0
  161. package/src/proofs/cache/interface.ts +545 -0
  162. package/src/proofs/cache/key-generator.ts +188 -0
  163. package/src/proofs/cache/lru-cache.ts +481 -0
  164. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  165. package/src/proofs/cache/persistent-cache.ts +788 -0
  166. package/src/proofs/compliance-proof.ts +872 -0
  167. package/src/proofs/composer/base.ts +923 -0
  168. package/src/proofs/composer/index.ts +25 -0
  169. package/src/proofs/composer/interface.ts +518 -0
  170. package/src/proofs/composer/types.ts +383 -0
  171. package/src/proofs/converters/halo2.ts +452 -0
  172. package/src/proofs/converters/index.ts +208 -0
  173. package/src/proofs/converters/interface.ts +363 -0
  174. package/src/proofs/converters/kimchi.ts +462 -0
  175. package/src/proofs/converters/noir.ts +451 -0
  176. package/src/proofs/fallback.ts +888 -0
  177. package/src/proofs/halo2.ts +42 -0
  178. package/src/proofs/index.ts +471 -0
  179. package/src/proofs/interface.ts +13 -0
  180. package/src/proofs/kimchi.ts +42 -0
  181. package/src/proofs/lazy.ts +1004 -0
  182. package/src/proofs/mock.ts +25 -1
  183. package/src/proofs/noir.ts +111 -30
  184. package/src/proofs/orchestrator.ts +960 -0
  185. package/src/proofs/parallel/concurrency.ts +297 -0
  186. package/src/proofs/parallel/dependency-graph.ts +602 -0
  187. package/src/proofs/parallel/executor.ts +420 -0
  188. package/src/proofs/parallel/index.ts +131 -0
  189. package/src/proofs/parallel/interface.ts +685 -0
  190. package/src/proofs/parallel/worker-pool.ts +644 -0
  191. package/src/proofs/providers/halo2.ts +560 -0
  192. package/src/proofs/providers/index.ts +34 -0
  193. package/src/proofs/providers/kimchi.ts +641 -0
  194. package/src/proofs/validator.ts +881 -0
  195. package/src/proofs/verifier.ts +867 -0
  196. package/src/quantum/index.ts +112 -0
  197. package/src/quantum/winternitz-vault.ts +639 -0
  198. package/src/quantum/wots.ts +611 -0
  199. package/src/settlement/backends/direct-chain.ts +1 -0
  200. package/src/settlement/index.ts +9 -0
  201. package/src/settlement/router.ts +732 -46
  202. package/src/solana/index.ts +72 -0
  203. package/src/solana/jito-relayer.ts +687 -0
  204. package/src/solana/noir-verifier-types.ts +430 -0
  205. package/src/solana/noir-verifier.ts +816 -0
  206. package/src/stealth/address-derivation.ts +193 -0
  207. package/src/stealth/ed25519.ts +431 -0
  208. package/src/stealth/index.ts +233 -0
  209. package/src/stealth/meta-address.ts +221 -0
  210. package/src/stealth/secp256k1.ts +368 -0
  211. package/src/stealth/utils.ts +194 -0
  212. package/src/stealth.ts +50 -1504
  213. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  214. package/src/surveillance/algorithms/cluster.ts +247 -0
  215. package/src/surveillance/algorithms/exchange.ts +295 -0
  216. package/src/surveillance/algorithms/temporal.ts +337 -0
  217. package/src/surveillance/analyzer.ts +442 -0
  218. package/src/surveillance/index.ts +64 -0
  219. package/src/surveillance/scoring.ts +372 -0
  220. package/src/surveillance/types.ts +264 -0
  221. package/src/sync/index.ts +106 -0
  222. package/src/sync/manager.ts +504 -0
  223. package/src/sync/mock-provider.ts +318 -0
  224. package/src/sync/oblivious.ts +625 -0
  225. package/src/tokens/index.ts +15 -0
  226. package/src/tokens/registry.ts +301 -0
  227. package/src/utils/deprecation.ts +94 -0
  228. package/src/utils/index.ts +9 -0
  229. package/src/wallet/ethereum/index.ts +68 -0
  230. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  231. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  232. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  233. package/src/wallet/ethereum/types.ts +3 -1
  234. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  235. package/src/wallet/hardware/index.ts +10 -0
  236. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  237. package/src/wallet/index.ts +71 -0
  238. package/src/wallet/near/adapter.ts +626 -0
  239. package/src/wallet/near/index.ts +86 -0
  240. package/src/wallet/near/meteor-wallet.ts +1153 -0
  241. package/src/wallet/near/my-near-wallet.ts +790 -0
  242. package/src/wallet/near/wallet-selector.ts +702 -0
  243. package/src/wallet/solana/adapter.ts +6 -4
  244. package/src/wallet/solana/index.ts +13 -0
  245. package/src/wallet/solana/privacy-adapter.ts +567 -0
  246. package/src/wallet/sui/types.ts +6 -4
  247. package/src/zcash/rpc-client.ts +13 -6
  248. package/dist/chunk-3INS3PR5.mjs +0 -884
  249. package/dist/chunk-3OVABDRH.mjs +0 -17096
  250. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  251. package/dist/chunk-E6SZWREQ.mjs +0 -57
  252. package/dist/chunk-G33LB27A.mjs +0 -16166
  253. package/dist/chunk-HGU6HZRC.mjs +0 -231
  254. package/dist/chunk-L2K34JCU.mjs +0 -1496
  255. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  256. package/dist/constants-VOI7BSLK.mjs +0 -27
  257. package/dist/index-BYZbDjal.d.ts +0 -11390
  258. package/dist/index-CHB3KuOB.d.mts +0 -11859
  259. package/dist/index-CzWPI6Le.d.ts +0 -11859
  260. package/dist/index-xbWjohNq.d.mts +0 -11390
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
@@ -0,0 +1,790 @@
1
+ /**
2
+ * MyNearWallet Privacy Integration
3
+ *
4
+ * Specific integration for MyNearWallet with privacy transaction support.
5
+ * Handles URL-based transaction signing and callback processing.
6
+ *
7
+ * @example Basic usage
8
+ * ```typescript
9
+ * import { MyNearWalletPrivacy } from '@sip-protocol/sdk'
10
+ *
11
+ * const wallet = new MyNearWalletPrivacy({
12
+ * network: 'mainnet',
13
+ * callbackUrl: 'https://myapp.com/callback',
14
+ * })
15
+ *
16
+ * // Connect to wallet
17
+ * await wallet.connect()
18
+ *
19
+ * // Send private transfer (redirects to MyNearWallet)
20
+ * await wallet.sendPrivateTransfer({
21
+ * recipientMetaAddress: 'sip:near:0x...',
22
+ * amount: '1000000000000000000000000',
23
+ * })
24
+ * ```
25
+ *
26
+ * @packageDocumentation
27
+ */
28
+
29
+ import { sha256 } from '@noble/hashes/sha2'
30
+ import { bytesToHex } from '@noble/hashes/utils'
31
+ import { ed25519 } from '@noble/curves/ed25519'
32
+ import type { HexString, StealthMetaAddress, StealthAddress } from '@sip-protocol/types'
33
+ import type { NEARNetwork } from '../../chains/near/constants'
34
+ import {
35
+ generateNEARStealthAddress,
36
+ deriveNEARStealthPrivateKey,
37
+ checkNEARStealthAddress,
38
+ encodeNEARStealthMetaAddress,
39
+ parseNEARStealthMetaAddress,
40
+ } from '../../chains/near/stealth'
41
+ import { buildPrivateTransfer } from '../../chains/near/implicit-account'
42
+
43
+ // ─── Constants ────────────────────────────────────────────────────────────────
44
+
45
+ /** MyNearWallet mainnet URL */
46
+ export const MY_NEAR_WALLET_MAINNET = 'https://app.mynearwallet.com'
47
+
48
+ /** MyNearWallet testnet URL */
49
+ export const MY_NEAR_WALLET_TESTNET = 'https://testnet.mynearwallet.com'
50
+
51
+ // ─── Types ────────────────────────────────────────────────────────────────────
52
+
53
+ /**
54
+ * MyNearWallet configuration
55
+ */
56
+ export interface MyNearWalletConfig {
57
+ /** NEAR network */
58
+ network: NEARNetwork
59
+ /** Callback URL after signing */
60
+ callbackUrl: string
61
+ /** Custom wallet URL (optional) */
62
+ walletUrl?: string
63
+ /** Contract ID for function calls (optional) */
64
+ contractId?: string
65
+ }
66
+
67
+ /**
68
+ * Connection state
69
+ */
70
+ export type MyNearWalletConnectionState =
71
+ | 'disconnected'
72
+ | 'connecting'
73
+ | 'connected'
74
+ | 'signing'
75
+ | 'error'
76
+
77
+ /**
78
+ * Privacy key pair
79
+ */
80
+ export interface MyNearWalletPrivacyKeys {
81
+ spendingPrivateKey: HexString
82
+ spendingPublicKey: HexString
83
+ viewingPrivateKey: HexString
84
+ viewingPublicKey: HexString
85
+ derivationLabel: string
86
+ }
87
+
88
+ /**
89
+ * Stealth address with metadata
90
+ */
91
+ export interface MyNearWalletStealthAddress {
92
+ stealthAddress: StealthAddress
93
+ stealthAccountId: string
94
+ ephemeralPublicKey: HexString
95
+ createdAt: number
96
+ label?: string
97
+ }
98
+
99
+ /**
100
+ * Private transfer parameters
101
+ */
102
+ export interface MyNearWalletPrivateTransferParams {
103
+ /** Recipient's stealth meta-address */
104
+ recipientMetaAddress: string | StealthMetaAddress
105
+ /** Amount in yoctoNEAR */
106
+ amount: string | bigint
107
+ /** Optional memo */
108
+ memo?: string
109
+ /** Optional label for tracking */
110
+ label?: string
111
+ }
112
+
113
+ /**
114
+ * Transaction preview data
115
+ */
116
+ export interface TransactionPreview {
117
+ /** Sender account ID */
118
+ senderId: string
119
+ /** Receiver (stealth account ID) */
120
+ receiverId: string
121
+ /** Amount in NEAR (formatted) */
122
+ amountNEAR: string
123
+ /** Amount in yoctoNEAR */
124
+ amountYocto: string
125
+ /** Is this a privacy transaction */
126
+ isPrivate: true
127
+ /** Stealth address info */
128
+ stealthInfo: {
129
+ stealthAccountId: string
130
+ announcementMemo: string
131
+ viewTag: number
132
+ }
133
+ /** Actions to execute */
134
+ actions: Array<{
135
+ type: string
136
+ params: Record<string, unknown>
137
+ }>
138
+ }
139
+
140
+ /**
141
+ * Callback result from MyNearWallet
142
+ */
143
+ export interface MyNearWalletCallbackResult {
144
+ /** Transaction hash (if successful) */
145
+ transactionHashes?: string
146
+ /** Error code (if failed) */
147
+ errorCode?: string
148
+ /** Error message (if failed) */
149
+ errorMessage?: string
150
+ /** Account ID that signed */
151
+ accountId?: string
152
+ }
153
+
154
+ /**
155
+ * Viewing key export
156
+ */
157
+ export interface MyNearWalletViewingKeyExport {
158
+ network: NEARNetwork
159
+ viewingPublicKey: HexString
160
+ viewingPrivateKey: HexString
161
+ spendingPublicKey: HexString
162
+ accountId: string
163
+ createdAt: number
164
+ label?: string
165
+ walletType: 'mynearwallet'
166
+ }
167
+
168
+ /**
169
+ * Ledger integration status
170
+ */
171
+ export interface LedgerStatus {
172
+ isLedger: boolean
173
+ ledgerPath?: string
174
+ requiresLedgerConfirmation: boolean
175
+ }
176
+
177
+ // ─── MyNearWallet Privacy Class ───────────────────────────────────────────────
178
+
179
+ /**
180
+ * MyNearWallet Privacy Integration
181
+ *
182
+ * Provides privacy transaction support for MyNearWallet.
183
+ */
184
+ export class MyNearWalletPrivacy {
185
+ private config: MyNearWalletConfig
186
+ private walletUrl: string
187
+ private connectionState: MyNearWalletConnectionState = 'disconnected'
188
+ private accountId: string | null = null
189
+ private publicKey: string | null = null
190
+ private privacyKeys: MyNearWalletPrivacyKeys | null = null
191
+ private stealthAddresses: Map<string, MyNearWalletStealthAddress> = new Map()
192
+ private isLedger: boolean = false
193
+
194
+ constructor(config: MyNearWalletConfig) {
195
+ this.config = config
196
+ this.walletUrl = config.walletUrl ?? (
197
+ config.network === 'mainnet'
198
+ ? MY_NEAR_WALLET_MAINNET
199
+ : MY_NEAR_WALLET_TESTNET
200
+ )
201
+ }
202
+
203
+ // ─── Connection ─────────────────────────────────────────────────────────────
204
+
205
+ /**
206
+ * Get wallet URL for signing in
207
+ */
208
+ getSignInUrl(options?: {
209
+ successUrl?: string
210
+ failureUrl?: string
211
+ }): string {
212
+ const params = new URLSearchParams({
213
+ success_url: options?.successUrl ?? this.config.callbackUrl,
214
+ failure_url: options?.failureUrl ?? this.config.callbackUrl,
215
+ })
216
+
217
+ if (this.config.contractId) {
218
+ params.set('contract_id', this.config.contractId)
219
+ }
220
+
221
+ return `${this.walletUrl}/login?${params.toString()}`
222
+ }
223
+
224
+ /**
225
+ * Connect by redirecting to MyNearWallet
226
+ */
227
+ connect(options?: {
228
+ successUrl?: string
229
+ failureUrl?: string
230
+ }): void {
231
+ this.connectionState = 'connecting'
232
+
233
+ if (typeof window !== 'undefined') {
234
+ window.location.href = this.getSignInUrl(options)
235
+ } else {
236
+ throw new Error('MyNearWallet connect requires browser environment')
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Handle callback from MyNearWallet login
242
+ */
243
+ handleLoginCallback(callbackParams: URLSearchParams): boolean {
244
+ const accountId = callbackParams.get('account_id')
245
+ const publicKey = callbackParams.get('public_key')
246
+ const allKeys = callbackParams.get('all_keys')
247
+
248
+ if (accountId) {
249
+ this.accountId = accountId
250
+ this.publicKey = publicKey
251
+ this.connectionState = 'connected'
252
+
253
+ // Check if using Ledger
254
+ if (allKeys) {
255
+ try {
256
+ const keys = JSON.parse(allKeys)
257
+ this.isLedger = keys.some((k: string) => k.includes('ledger'))
258
+ } catch {
259
+ this.isLedger = false
260
+ }
261
+ }
262
+
263
+ return true
264
+ }
265
+
266
+ this.connectionState = 'error'
267
+ return false
268
+ }
269
+
270
+ /**
271
+ * Set connection from stored credentials
272
+ */
273
+ setConnection(accountId: string, publicKey?: string): void {
274
+ this.accountId = accountId
275
+ this.publicKey = publicKey ?? null
276
+ this.connectionState = 'connected'
277
+ }
278
+
279
+ /**
280
+ * Disconnect
281
+ */
282
+ disconnect(): void {
283
+ this.accountId = null
284
+ this.publicKey = null
285
+ this.privacyKeys = null
286
+ this.stealthAddresses.clear()
287
+ this.connectionState = 'disconnected'
288
+ this.isLedger = false
289
+ }
290
+
291
+ /**
292
+ * Get connection state
293
+ */
294
+ getConnectionState(): MyNearWalletConnectionState {
295
+ return this.connectionState
296
+ }
297
+
298
+ /**
299
+ * Check if connected
300
+ */
301
+ isConnected(): boolean {
302
+ return this.connectionState === 'connected' && this.accountId !== null
303
+ }
304
+
305
+ /**
306
+ * Get account ID
307
+ */
308
+ getAccountId(): string | null {
309
+ return this.accountId
310
+ }
311
+
312
+ /**
313
+ * Get public key
314
+ */
315
+ getPublicKey(): string | null {
316
+ return this.publicKey
317
+ }
318
+
319
+ /**
320
+ * Get Ledger status
321
+ */
322
+ getLedgerStatus(): LedgerStatus {
323
+ return {
324
+ isLedger: this.isLedger,
325
+ requiresLedgerConfirmation: this.isLedger,
326
+ }
327
+ }
328
+
329
+ // ─── Privacy Key Management ─────────────────────────────────────────────────
330
+
331
+ /**
332
+ * Derive privacy keys
333
+ *
334
+ * Note: MyNearWallet doesn't support message signing directly,
335
+ * so we use a deterministic derivation from account ID + secret.
336
+ */
337
+ derivePrivacyKeys(secret: string, label: string = 'default'): MyNearWalletPrivacyKeys {
338
+ if (!this.accountId) {
339
+ throw new Error('Not connected to MyNearWallet')
340
+ }
341
+
342
+ // Create deterministic entropy from account + secret + label
343
+ const derivationPath = `sip/mynearwallet/${this.config.network}/${this.accountId}/${label}`
344
+ const entropy = sha256(
345
+ new TextEncoder().encode(`${derivationPath}:${secret}`)
346
+ )
347
+
348
+ // Derive spending key
349
+ const spendingEntropy = sha256(new Uint8Array([...entropy, 0x01]))
350
+ const spendingPrivateKey = clampScalar(spendingEntropy)
351
+ const spendingPublicKey = ed25519.getPublicKey(spendingPrivateKey)
352
+
353
+ // Derive viewing key
354
+ const viewingEntropy = sha256(new Uint8Array([...entropy, 0x02]))
355
+ const viewingPrivateKey = clampScalar(viewingEntropy)
356
+ const viewingPublicKey = ed25519.getPublicKey(viewingPrivateKey)
357
+
358
+ const keys: MyNearWalletPrivacyKeys = {
359
+ spendingPrivateKey: `0x${bytesToHex(spendingPrivateKey)}` as HexString,
360
+ spendingPublicKey: `0x${bytesToHex(spendingPublicKey)}` as HexString,
361
+ viewingPrivateKey: `0x${bytesToHex(viewingPrivateKey)}` as HexString,
362
+ viewingPublicKey: `0x${bytesToHex(viewingPublicKey)}` as HexString,
363
+ derivationLabel: label,
364
+ }
365
+
366
+ this.privacyKeys = keys
367
+ return keys
368
+ }
369
+
370
+ /**
371
+ * Check if privacy keys are derived
372
+ */
373
+ hasPrivacyKeys(): boolean {
374
+ return this.privacyKeys !== null
375
+ }
376
+
377
+ /**
378
+ * Get privacy keys
379
+ */
380
+ getPrivacyKeys(): MyNearWalletPrivacyKeys | null {
381
+ return this.privacyKeys
382
+ }
383
+
384
+ // ─── Stealth Address Operations ─────────────────────────────────────────────
385
+
386
+ /**
387
+ * Generate stealth meta-address
388
+ */
389
+ generateStealthMetaAddress(label?: string): {
390
+ metaAddress: StealthMetaAddress
391
+ encoded: string
392
+ viewingPrivateKey: HexString
393
+ spendingPrivateKey: HexString
394
+ } {
395
+ if (!this.privacyKeys) {
396
+ throw new Error('Privacy keys not derived. Call derivePrivacyKeys first.')
397
+ }
398
+
399
+ const metaAddress: StealthMetaAddress = {
400
+ chain: 'near',
401
+ spendingKey: this.privacyKeys.spendingPublicKey,
402
+ viewingKey: this.privacyKeys.viewingPublicKey,
403
+ label,
404
+ }
405
+
406
+ const encoded = encodeNEARStealthMetaAddress(metaAddress)
407
+
408
+ return {
409
+ metaAddress,
410
+ encoded,
411
+ viewingPrivateKey: this.privacyKeys.viewingPrivateKey,
412
+ spendingPrivateKey: this.privacyKeys.spendingPrivateKey,
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Generate stealth address for receiving
418
+ */
419
+ generateStealthAddress(
420
+ metaAddress: string | StealthMetaAddress,
421
+ label?: string
422
+ ): MyNearWalletStealthAddress {
423
+ const meta = typeof metaAddress === 'string'
424
+ ? parseNEARStealthMetaAddress(metaAddress)
425
+ : metaAddress
426
+
427
+ const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(meta)
428
+
429
+ const result: MyNearWalletStealthAddress = {
430
+ stealthAddress,
431
+ stealthAccountId: implicitAccountId,
432
+ ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
433
+ createdAt: Date.now(),
434
+ label,
435
+ }
436
+
437
+ this.stealthAddresses.set(implicitAccountId, result)
438
+ return result
439
+ }
440
+
441
+ /**
442
+ * Check stealth address ownership
443
+ */
444
+ checkStealthAddress(stealthAddress: StealthAddress): boolean {
445
+ if (!this.privacyKeys) {
446
+ throw new Error('Privacy keys not derived')
447
+ }
448
+
449
+ return checkNEARStealthAddress(
450
+ stealthAddress,
451
+ this.privacyKeys.spendingPrivateKey,
452
+ this.privacyKeys.viewingPrivateKey
453
+ )
454
+ }
455
+
456
+ /**
457
+ * Derive stealth private key
458
+ */
459
+ deriveStealthPrivateKey(stealthAddress: StealthAddress): HexString {
460
+ if (!this.privacyKeys) {
461
+ throw new Error('Privacy keys not derived')
462
+ }
463
+
464
+ const isOwner = this.checkStealthAddress(stealthAddress)
465
+ if (!isOwner) {
466
+ throw new Error('Stealth address does not belong to this wallet')
467
+ }
468
+
469
+ const recovery = deriveNEARStealthPrivateKey(
470
+ stealthAddress,
471
+ this.privacyKeys.spendingPrivateKey,
472
+ this.privacyKeys.viewingPrivateKey
473
+ )
474
+
475
+ return recovery.privateKey
476
+ }
477
+
478
+ // ─── Transaction Preview ────────────────────────────────────────────────────
479
+
480
+ /**
481
+ * Preview a private transfer before signing
482
+ */
483
+ previewPrivateTransfer(params: MyNearWalletPrivateTransferParams): TransactionPreview {
484
+ if (!this.accountId) {
485
+ throw new Error('Not connected to MyNearWallet')
486
+ }
487
+
488
+ const recipientMeta = typeof params.recipientMetaAddress === 'string'
489
+ ? parseNEARStealthMetaAddress(params.recipientMetaAddress)
490
+ : params.recipientMetaAddress
491
+
492
+ const amount = typeof params.amount === 'string' ? BigInt(params.amount) : params.amount
493
+ const transfer = buildPrivateTransfer(recipientMeta, amount)
494
+
495
+ // Format amount in NEAR
496
+ const amountNEAR = formatNearAmount(amount)
497
+
498
+ return {
499
+ senderId: this.accountId,
500
+ receiverId: transfer.stealthAccountId,
501
+ amountNEAR,
502
+ amountYocto: amount.toString(),
503
+ isPrivate: true,
504
+ stealthInfo: {
505
+ stealthAccountId: transfer.stealthAccountId,
506
+ announcementMemo: transfer.announcementMemo,
507
+ viewTag: transfer.stealthAddress.viewTag,
508
+ },
509
+ actions: transfer.actions.map((action) => ({
510
+ type: action.type,
511
+ params: serializeParams(action.params as unknown as Record<string, unknown>),
512
+ })),
513
+ }
514
+ }
515
+
516
+ // ─── Private Transfers ──────────────────────────────────────────────────────
517
+
518
+ /**
519
+ * Get URL for private transfer signing
520
+ */
521
+ getPrivateTransferUrl(params: MyNearWalletPrivateTransferParams): string {
522
+ if (!this.accountId) {
523
+ throw new Error('Not connected to MyNearWallet')
524
+ }
525
+
526
+ const recipientMeta = typeof params.recipientMetaAddress === 'string'
527
+ ? parseNEARStealthMetaAddress(params.recipientMetaAddress)
528
+ : params.recipientMetaAddress
529
+
530
+ const amount = typeof params.amount === 'string' ? BigInt(params.amount) : params.amount
531
+ const transfer = buildPrivateTransfer(recipientMeta, amount)
532
+
533
+ // Build transaction URL
534
+ const urlParams = new URLSearchParams({
535
+ signerId: this.accountId,
536
+ receiverId: transfer.stealthAccountId,
537
+ callbackUrl: this.config.callbackUrl,
538
+ })
539
+
540
+ // Encode actions
541
+ const encodedActions = transfer.actions.map((action) => ({
542
+ type: action.type,
543
+ ...serializeParams(action.params as unknown as Record<string, unknown>),
544
+ }))
545
+
546
+ urlParams.set('actions', JSON.stringify(encodedActions))
547
+
548
+ // Add privacy metadata
549
+ urlParams.set('meta', JSON.stringify({
550
+ isPrivate: true,
551
+ stealthAccountId: transfer.stealthAccountId,
552
+ announcementMemo: transfer.announcementMemo,
553
+ label: params.label,
554
+ }))
555
+
556
+ return `${this.walletUrl}/sign?${urlParams.toString()}`
557
+ }
558
+
559
+ /**
560
+ * Send private transfer by redirecting to MyNearWallet
561
+ */
562
+ sendPrivateTransfer(params: MyNearWalletPrivateTransferParams): void {
563
+ this.connectionState = 'signing'
564
+
565
+ if (typeof window !== 'undefined') {
566
+ window.location.href = this.getPrivateTransferUrl(params)
567
+ } else {
568
+ throw new Error('sendPrivateTransfer requires browser environment')
569
+ }
570
+ }
571
+
572
+ /**
573
+ * Handle callback after signing
574
+ */
575
+ handleTransactionCallback(callbackParams: URLSearchParams): MyNearWalletCallbackResult {
576
+ this.connectionState = 'connected'
577
+
578
+ const transactionHashes = callbackParams.get('transactionHashes') ?? undefined
579
+ const errorCode = callbackParams.get('errorCode') ?? undefined
580
+ const errorMessage = callbackParams.get('errorMessage') ?? undefined
581
+
582
+ return {
583
+ transactionHashes,
584
+ errorCode,
585
+ errorMessage,
586
+ accountId: this.accountId ?? undefined,
587
+ }
588
+ }
589
+
590
+ // ─── Multi-Action Transactions ──────────────────────────────────────────────
591
+
592
+ /**
593
+ * Get URL for batch private transfers
594
+ */
595
+ getBatchPrivateTransferUrl(
596
+ transfers: MyNearWalletPrivateTransferParams[]
597
+ ): string {
598
+ if (!this.accountId) {
599
+ throw new Error('Not connected to MyNearWallet')
600
+ }
601
+
602
+ // Build all transactions
603
+ const transactions = transfers.map((params) => {
604
+ const recipientMeta = typeof params.recipientMetaAddress === 'string'
605
+ ? parseNEARStealthMetaAddress(params.recipientMetaAddress)
606
+ : params.recipientMetaAddress
607
+
608
+ const amount = typeof params.amount === 'string' ? BigInt(params.amount) : params.amount
609
+ const transfer = buildPrivateTransfer(recipientMeta, amount)
610
+
611
+ return {
612
+ signerId: this.accountId,
613
+ receiverId: transfer.stealthAccountId,
614
+ actions: transfer.actions.map((action) => ({
615
+ type: action.type,
616
+ ...serializeParams(action.params as unknown as Record<string, unknown>),
617
+ })),
618
+ meta: {
619
+ isPrivate: true,
620
+ stealthAccountId: transfer.stealthAccountId,
621
+ announcementMemo: transfer.announcementMemo,
622
+ label: params.label,
623
+ },
624
+ }
625
+ })
626
+
627
+ const urlParams = new URLSearchParams({
628
+ transactions: JSON.stringify(transactions),
629
+ callbackUrl: this.config.callbackUrl,
630
+ })
631
+
632
+ return `${this.walletUrl}/sign?${urlParams.toString()}`
633
+ }
634
+
635
+ /**
636
+ * Send batch private transfers
637
+ */
638
+ sendBatchPrivateTransfers(transfers: MyNearWalletPrivateTransferParams[]): void {
639
+ this.connectionState = 'signing'
640
+
641
+ if (typeof window !== 'undefined') {
642
+ window.location.href = this.getBatchPrivateTransferUrl(transfers)
643
+ } else {
644
+ throw new Error('sendBatchPrivateTransfers requires browser environment')
645
+ }
646
+ }
647
+
648
+ // ─── Viewing Key Export ─────────────────────────────────────────────────────
649
+
650
+ /**
651
+ * Export viewing key
652
+ */
653
+ exportViewingKey(label?: string): MyNearWalletViewingKeyExport {
654
+ if (!this.privacyKeys) {
655
+ throw new Error('Privacy keys not derived')
656
+ }
657
+
658
+ if (!this.accountId) {
659
+ throw new Error('Not connected')
660
+ }
661
+
662
+ return {
663
+ network: this.config.network,
664
+ viewingPublicKey: this.privacyKeys.viewingPublicKey,
665
+ viewingPrivateKey: this.privacyKeys.viewingPrivateKey,
666
+ spendingPublicKey: this.privacyKeys.spendingPublicKey,
667
+ accountId: this.accountId,
668
+ createdAt: Date.now(),
669
+ label,
670
+ walletType: 'mynearwallet',
671
+ }
672
+ }
673
+
674
+ // ─── Utility Methods ────────────────────────────────────────────────────────
675
+
676
+ /**
677
+ * Get tracked stealth addresses
678
+ */
679
+ getStealthAddresses(): Map<string, MyNearWalletStealthAddress> {
680
+ return new Map(this.stealthAddresses)
681
+ }
682
+
683
+ /**
684
+ * Get wallet URL
685
+ */
686
+ getWalletUrl(): string {
687
+ return this.walletUrl
688
+ }
689
+
690
+ /**
691
+ * Get config
692
+ */
693
+ getConfig(): MyNearWalletConfig {
694
+ return { ...this.config }
695
+ }
696
+ }
697
+
698
+ // ─── Factory Functions ────────────────────────────────────────────────────────
699
+
700
+ /**
701
+ * Create MyNearWallet privacy integration
702
+ */
703
+ export function createMyNearWalletPrivacy(
704
+ config: MyNearWalletConfig
705
+ ): MyNearWalletPrivacy {
706
+ return new MyNearWalletPrivacy(config)
707
+ }
708
+
709
+ /**
710
+ * Create mainnet MyNearWallet integration
711
+ */
712
+ export function createMainnetMyNearWallet(
713
+ callbackUrl: string
714
+ ): MyNearWalletPrivacy {
715
+ return new MyNearWalletPrivacy({
716
+ network: 'mainnet',
717
+ callbackUrl,
718
+ })
719
+ }
720
+
721
+ /**
722
+ * Create testnet MyNearWallet integration
723
+ */
724
+ export function createTestnetMyNearWallet(
725
+ callbackUrl: string
726
+ ): MyNearWalletPrivacy {
727
+ return new MyNearWalletPrivacy({
728
+ network: 'testnet',
729
+ callbackUrl,
730
+ })
731
+ }
732
+
733
+ // ─── Utility Functions ────────────────────────────────────────────────────────
734
+
735
+ /**
736
+ * Clamp scalar for ed25519
737
+ */
738
+ function clampScalar(bytes: Uint8Array): Uint8Array {
739
+ const clamped = new Uint8Array(bytes)
740
+ clamped[0] &= 248
741
+ clamped[31] &= 127
742
+ clamped[31] |= 64
743
+ return clamped
744
+ }
745
+
746
+ /**
747
+ * Format amount in NEAR
748
+ */
749
+ function formatNearAmount(yoctoNear: bigint): string {
750
+ const nearStr = yoctoNear.toString().padStart(25, '0')
751
+ const whole = nearStr.slice(0, -24) || '0'
752
+ const decimal = nearStr.slice(-24).replace(/0+$/, '')
753
+ return decimal ? `${whole}.${decimal}` : whole
754
+ }
755
+
756
+ /**
757
+ * Serialize action params for URL encoding
758
+ */
759
+ function serializeParams(params: Record<string, unknown>): Record<string, unknown> {
760
+ const serialized: Record<string, unknown> = {}
761
+
762
+ for (const [key, value] of Object.entries(params)) {
763
+ if (typeof value === 'bigint') {
764
+ serialized[key] = value.toString()
765
+ } else if (value instanceof Uint8Array) {
766
+ serialized[key] = bytesToHex(value)
767
+ } else {
768
+ serialized[key] = value
769
+ }
770
+ }
771
+
772
+ return serialized
773
+ }
774
+
775
+ /**
776
+ * Parse callback URL parameters
777
+ */
778
+ export function parseMyNearWalletCallback(
779
+ url: string
780
+ ): { type: 'login' | 'transaction'; params: URLSearchParams } {
781
+ const urlObj = new URL(url)
782
+ const params = urlObj.searchParams
783
+
784
+ // Check if login or transaction callback
785
+ if (params.has('account_id')) {
786
+ return { type: 'login', params }
787
+ }
788
+
789
+ return { type: 'transaction', params }
790
+ }