@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,840 @@
1
+ /**
2
+ * NEAR Implicit Account Privacy Support
3
+ *
4
+ * Provides privacy operations for NEAR implicit accounts using stealth addresses.
5
+ * Implicit accounts are ideal for stealth addresses as they:
6
+ * - Don't require on-chain registration
7
+ * - Are created automatically on first transfer
8
+ * - Account ID = lowercase hex of ed25519 public key
9
+ *
10
+ * @example Send private transfer
11
+ * ```typescript
12
+ * import { buildPrivateTransfer } from '@sip-protocol/sdk'
13
+ *
14
+ * const { transaction, stealthAddress } = await buildPrivateTransfer({
15
+ * recipientMetaAddress: 'sip:near:0x...:0x...',
16
+ * amount: 1_000_000_000_000_000_000_000_000n, // 1 NEAR
17
+ * })
18
+ *
19
+ * // Sign and send transaction using your NEAR wallet
20
+ * await wallet.signAndSendTransaction(transaction)
21
+ * ```
22
+ *
23
+ * @example Claim from stealth account
24
+ * ```typescript
25
+ * import { buildClaimTransaction, deriveStealthAccountKeyPair } from '@sip-protocol/sdk'
26
+ *
27
+ * // Derive keypair for the stealth account
28
+ * const keypair = deriveStealthAccountKeyPair({
29
+ * stealthAddress: detectedPayment.stealthAddress,
30
+ * spendingPrivateKey: mySpendingKey,
31
+ * viewingPrivateKey: myViewingKey,
32
+ * })
33
+ *
34
+ * // Build claim transaction
35
+ * const tx = buildClaimTransaction({
36
+ * stealthAccountId: detectedPayment.stealthAccountId,
37
+ * destinationAccountId: 'alice.near',
38
+ * amount: detectedPayment.amount,
39
+ * })
40
+ * ```
41
+ *
42
+ * @packageDocumentation
43
+ */
44
+
45
+ import { ed25519 } from '@noble/curves/ed25519'
46
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
47
+ import type { HexString, StealthAddress, StealthMetaAddress } from '@sip-protocol/types'
48
+ import { ValidationError } from '../../errors'
49
+ import { isValidPrivateKey } from '../../validation'
50
+ import {
51
+ generateNEARStealthAddress,
52
+ deriveNEARStealthPrivateKey,
53
+ ed25519PublicKeyToImplicitAccount,
54
+ parseNEARStealthMetaAddress,
55
+ } from './stealth'
56
+ import { createAnnouncementMemo } from './types'
57
+ import {
58
+ isImplicitAccount,
59
+ isValidAccountId,
60
+ ONE_YOCTO,
61
+ DEFAULT_GAS,
62
+ STORAGE_DEPOSIT_DEFAULT,
63
+ } from './constants'
64
+
65
+ // ─── Types ────────────────────────────────────────────────────────────────────
66
+
67
+ /**
68
+ * Result of building a private transfer
69
+ */
70
+ export interface NEARPrivateTransferBuild {
71
+ /** The stealth address generated for the recipient */
72
+ stealthAddress: StealthAddress
73
+ /** NEAR implicit account ID (64 hex chars) */
74
+ stealthAccountId: string
75
+ /** Announcement memo to include in transaction */
76
+ announcementMemo: string
77
+ /** Transaction actions to execute */
78
+ actions: NEARAction[]
79
+ /** Receiver ID for the transaction (the stealth implicit account) */
80
+ receiverId: string
81
+ }
82
+
83
+ /**
84
+ * NEAR transaction action
85
+ */
86
+ export interface NEARAction {
87
+ type: 'Transfer' | 'FunctionCall' | 'AddKey' | 'DeleteKey' | 'DeleteAccount'
88
+ params: NEARTransferAction | NEARFunctionCallAction | NEARAddKeyAction | NEARDeleteKeyAction | NEARDeleteAccountAction
89
+ }
90
+
91
+ /**
92
+ * Native NEAR transfer action
93
+ */
94
+ export interface NEARTransferAction {
95
+ deposit: bigint
96
+ }
97
+
98
+ /**
99
+ * Function call action (for NEP-141 tokens or contracts)
100
+ */
101
+ export interface NEARFunctionCallAction {
102
+ methodName: string
103
+ args: string | Uint8Array
104
+ gas: bigint
105
+ deposit: bigint
106
+ }
107
+
108
+ /**
109
+ * Add access key action
110
+ */
111
+ export interface NEARAddKeyAction {
112
+ publicKey: string
113
+ accessKey: {
114
+ permission: 'FullAccess' | {
115
+ FunctionCall: {
116
+ allowance?: bigint
117
+ receiverId: string
118
+ methodNames: string[]
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Delete access key action
126
+ */
127
+ export interface NEARDeleteKeyAction {
128
+ publicKey: string
129
+ }
130
+
131
+ /**
132
+ * Delete account action (sends remaining balance to beneficiary)
133
+ */
134
+ export interface NEARDeleteAccountAction {
135
+ beneficiaryId: string
136
+ }
137
+
138
+ /**
139
+ * Derived stealth account keypair
140
+ */
141
+ export interface NEARStealthKeyPair {
142
+ /** Ed25519 public key (0x-prefixed hex) */
143
+ publicKey: HexString
144
+ /** Ed25519 private key scalar (0x-prefixed hex) */
145
+ privateKey: HexString
146
+ /** NEAR implicit account ID */
147
+ accountId: string
148
+ /** NEAR-formatted public key string (ed25519:base58) */
149
+ nearPublicKey: string
150
+ /** Raw public key bytes */
151
+ publicKeyBytes: Uint8Array
152
+ }
153
+
154
+ /**
155
+ * Parameters for deriving a stealth account keypair
156
+ */
157
+ export interface DeriveStealthKeyPairParams {
158
+ /** The stealth address to derive keys for */
159
+ stealthAddress: StealthAddress
160
+ /** Recipient's spending private key */
161
+ spendingPrivateKey: HexString
162
+ /** Recipient's viewing private key */
163
+ viewingPrivateKey: HexString
164
+ }
165
+
166
+ /**
167
+ * Parameters for building a claim transaction
168
+ */
169
+ export interface NEARClaimTransactionParams {
170
+ /** Stealth implicit account ID to claim from */
171
+ stealthAccountId: string
172
+ /** Destination account ID to receive funds */
173
+ destinationAccountId: string
174
+ /** Amount to claim in yoctoNEAR (defaults to full balance minus storage) */
175
+ amount?: bigint
176
+ /** Token contract for NEP-141 claims (omit for native NEAR) */
177
+ tokenContract?: string
178
+ /** Leave minimum balance for storage (default: true) */
179
+ keepStorageDeposit?: boolean
180
+ }
181
+
182
+ /**
183
+ * Result of building a claim transaction
184
+ */
185
+ export interface NEARClaimTransactionBuild {
186
+ /** Transaction actions */
187
+ actions: NEARAction[]
188
+ /** Receiver ID (destination for native NEAR, token contract for NEP-141) */
189
+ receiverId: string
190
+ /** Whether this is a token transfer */
191
+ isTokenTransfer: boolean
192
+ }
193
+
194
+ /**
195
+ * Parameters for adding an access key to a stealth account
196
+ */
197
+ export interface NEARAddAccessKeyParams {
198
+ /** New public key to add (ed25519:base58 format) */
199
+ newPublicKey: string
200
+ /** Permission type */
201
+ permission: 'FullAccess' | {
202
+ allowance?: bigint
203
+ receiverId: string
204
+ methodNames: string[]
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Parameters for key rotation
210
+ */
211
+ export interface NEARKeyRotationParams {
212
+ /** Current stealth account ID */
213
+ stealthAccountId: string
214
+ /** New public key (ed25519:base58 format) */
215
+ newPublicKey: string
216
+ /** Old public key to delete (ed25519:base58 format) */
217
+ oldPublicKey: string
218
+ /** Permission for new key */
219
+ permission?: 'FullAccess' | {
220
+ allowance?: bigint
221
+ receiverId: string
222
+ methodNames: string[]
223
+ }
224
+ }
225
+
226
+ // ─── Private Transfer Building ────────────────────────────────────────────────
227
+
228
+ /**
229
+ * Build a private NEAR transfer to a stealth address
230
+ *
231
+ * Generates a one-time stealth address and builds the transaction
232
+ * actions needed to send NEAR privately.
233
+ *
234
+ * @param recipientMetaAddress - Recipient's stealth meta-address
235
+ * @param amount - Amount in yoctoNEAR
236
+ * @returns Transfer build with actions and stealth address
237
+ *
238
+ * @example Native NEAR transfer
239
+ * ```typescript
240
+ * const { actions, receiverId, stealthAddress, announcementMemo } =
241
+ * buildPrivateTransfer(
242
+ * 'sip:near:0x...:0x...',
243
+ * 1_000_000_000_000_000_000_000_000n // 1 NEAR
244
+ * )
245
+ *
246
+ * // Create transaction with these actions
247
+ * // Include announcementMemo in transaction logs/memo
248
+ * ```
249
+ */
250
+ export function buildPrivateTransfer(
251
+ recipientMetaAddress: StealthMetaAddress | string,
252
+ amount: bigint
253
+ ): NEARPrivateTransferBuild {
254
+ // Parse meta-address if string
255
+ const metaAddr = typeof recipientMetaAddress === 'string'
256
+ ? parseNEARStealthMetaAddress(recipientMetaAddress)
257
+ : recipientMetaAddress
258
+
259
+ // Validate chain
260
+ if (metaAddr.chain !== 'near') {
261
+ throw new ValidationError(
262
+ `Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
263
+ 'recipientMetaAddress'
264
+ )
265
+ }
266
+
267
+ // Validate amount
268
+ if (amount <= 0n) {
269
+ throw new ValidationError('amount must be greater than 0', 'amount')
270
+ }
271
+
272
+ // Generate stealth address
273
+ const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
274
+
275
+ // Create announcement memo
276
+ const announcementMemo = createAnnouncementMemo(
277
+ stealthAddress.ephemeralPublicKey,
278
+ stealthAddress.viewTag
279
+ )
280
+
281
+ // Build transfer action
282
+ const actions: NEARAction[] = [
283
+ {
284
+ type: 'Transfer',
285
+ params: {
286
+ deposit: amount,
287
+ } as NEARTransferAction,
288
+ },
289
+ ]
290
+
291
+ return {
292
+ stealthAddress,
293
+ stealthAccountId: implicitAccountId,
294
+ announcementMemo,
295
+ actions,
296
+ receiverId: implicitAccountId,
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Build a private NEP-141 token transfer to a stealth address
302
+ *
303
+ * @param recipientMetaAddress - Recipient's stealth meta-address
304
+ * @param tokenContract - NEP-141 token contract address
305
+ * @param amount - Amount in token's smallest units
306
+ * @param memo - Optional memo for the transfer
307
+ * @returns Transfer build with actions and stealth address
308
+ *
309
+ * @example NEP-141 token transfer
310
+ * ```typescript
311
+ * const { actions, receiverId, stealthAddress, announcementMemo } =
312
+ * buildPrivateTokenTransfer(
313
+ * 'sip:near:0x...:0x...',
314
+ * 'usdt.tether-token.near',
315
+ * 1_000_000n, // 1 USDT (6 decimals)
316
+ * )
317
+ *
318
+ * // receiverId is the token contract
319
+ * // ft_transfer to stealthAccountId
320
+ * ```
321
+ */
322
+ export function buildPrivateTokenTransfer(
323
+ recipientMetaAddress: StealthMetaAddress | string,
324
+ tokenContract: string,
325
+ amount: bigint,
326
+ memo?: string
327
+ ): NEARPrivateTransferBuild {
328
+ // Parse meta-address if string
329
+ const metaAddr = typeof recipientMetaAddress === 'string'
330
+ ? parseNEARStealthMetaAddress(recipientMetaAddress)
331
+ : recipientMetaAddress
332
+
333
+ // Validate chain
334
+ if (metaAddr.chain !== 'near') {
335
+ throw new ValidationError(
336
+ `Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
337
+ 'recipientMetaAddress'
338
+ )
339
+ }
340
+
341
+ // Validate token contract
342
+ if (!isValidAccountId(tokenContract)) {
343
+ throw new ValidationError('Invalid token contract account ID', 'tokenContract')
344
+ }
345
+
346
+ // Validate amount
347
+ if (amount <= 0n) {
348
+ throw new ValidationError('amount must be greater than 0', 'amount')
349
+ }
350
+
351
+ // Generate stealth address
352
+ const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
353
+
354
+ // Create announcement memo (include in the ft_transfer memo)
355
+ const announcementMemo = createAnnouncementMemo(
356
+ stealthAddress.ephemeralPublicKey,
357
+ stealthAddress.viewTag
358
+ )
359
+
360
+ // Build ft_transfer_call args
361
+ const transferMemo = memo ? `${announcementMemo}|${memo}` : announcementMemo
362
+ const args = JSON.stringify({
363
+ receiver_id: implicitAccountId,
364
+ amount: amount.toString(),
365
+ memo: transferMemo,
366
+ })
367
+
368
+ // Build function call action
369
+ const actions: NEARAction[] = [
370
+ {
371
+ type: 'FunctionCall',
372
+ params: {
373
+ methodName: 'ft_transfer',
374
+ args,
375
+ gas: DEFAULT_GAS,
376
+ deposit: ONE_YOCTO, // NEP-141 requires 1 yoctoNEAR deposit
377
+ } as NEARFunctionCallAction,
378
+ },
379
+ ]
380
+
381
+ return {
382
+ stealthAddress,
383
+ stealthAccountId: implicitAccountId,
384
+ announcementMemo,
385
+ actions,
386
+ receiverId: tokenContract,
387
+ }
388
+ }
389
+
390
+ /**
391
+ * Build storage deposit for a stealth account on a token contract
392
+ *
393
+ * Many NEP-141 tokens require storage deposit before receiving tokens.
394
+ *
395
+ * @param stealthAccountId - Stealth implicit account ID
396
+ * @param tokenContract - Token contract address
397
+ * @param amount - Storage deposit amount (defaults to standard amount)
398
+ * @returns Actions for storage deposit
399
+ */
400
+ export function buildStorageDeposit(
401
+ stealthAccountId: string,
402
+ tokenContract: string,
403
+ amount: bigint = STORAGE_DEPOSIT_DEFAULT
404
+ ): NEARAction[] {
405
+ if (!isImplicitAccount(stealthAccountId)) {
406
+ throw new ValidationError(
407
+ 'stealthAccountId must be a valid implicit account',
408
+ 'stealthAccountId'
409
+ )
410
+ }
411
+
412
+ if (!isValidAccountId(tokenContract)) {
413
+ throw new ValidationError('Invalid token contract account ID', 'tokenContract')
414
+ }
415
+
416
+ const args = JSON.stringify({
417
+ account_id: stealthAccountId,
418
+ })
419
+
420
+ return [
421
+ {
422
+ type: 'FunctionCall',
423
+ params: {
424
+ methodName: 'storage_deposit',
425
+ args,
426
+ gas: DEFAULT_GAS,
427
+ deposit: amount,
428
+ } as NEARFunctionCallAction,
429
+ },
430
+ ]
431
+ }
432
+
433
+ // ─── Key Derivation ───────────────────────────────────────────────────────────
434
+
435
+ /**
436
+ * Derive the keypair for a stealth implicit account
437
+ *
438
+ * Uses the DKSAP (Dual-Key Stealth Address Protocol) to derive
439
+ * the private key that controls the stealth account.
440
+ *
441
+ * @param params - Derivation parameters
442
+ * @returns Derived keypair with NEAR-formatted public key
443
+ *
444
+ * @example
445
+ * ```typescript
446
+ * const keypair = deriveStealthAccountKeyPair({
447
+ * stealthAddress: detectedPayment.stealthAddress,
448
+ * spendingPrivateKey: mySpendingKey,
449
+ * viewingPrivateKey: myViewingKey,
450
+ * })
451
+ *
452
+ * // keypair.nearPublicKey can be used to sign transactions
453
+ * // keypair.accountId is the implicit account ID
454
+ * ```
455
+ */
456
+ export function deriveStealthAccountKeyPair(
457
+ params: DeriveStealthKeyPairParams
458
+ ): NEARStealthKeyPair {
459
+ const { stealthAddress, spendingPrivateKey, viewingPrivateKey } = params
460
+
461
+ // Validate inputs
462
+ if (!stealthAddress) {
463
+ throw new ValidationError('stealthAddress is required', 'stealthAddress')
464
+ }
465
+ if (!isValidPrivateKey(spendingPrivateKey)) {
466
+ throw new ValidationError('Invalid spendingPrivateKey', 'spendingPrivateKey')
467
+ }
468
+ if (!isValidPrivateKey(viewingPrivateKey)) {
469
+ throw new ValidationError('Invalid viewingPrivateKey', 'viewingPrivateKey')
470
+ }
471
+
472
+ // Derive private key using DKSAP
473
+ const recovery = deriveNEARStealthPrivateKey(
474
+ stealthAddress,
475
+ spendingPrivateKey,
476
+ viewingPrivateKey
477
+ )
478
+
479
+ // The derived private key is a scalar (not a seed)
480
+ // Compute public key from scalar
481
+ const privateKeyBytes = hexToBytes(recovery.privateKey.slice(2))
482
+ const scalar = bytesToBigIntLE(privateKeyBytes)
483
+ const publicPoint = ed25519.ExtendedPoint.BASE.multiply(scalar)
484
+ const publicKeyBytes = publicPoint.toRawBytes()
485
+
486
+ // Convert to NEAR-formatted public key (ed25519:base58)
487
+ const nearPublicKey = `ed25519:${bytesToBase58(publicKeyBytes)}`
488
+
489
+ // Get implicit account ID
490
+ const accountId = ed25519PublicKeyToImplicitAccount(
491
+ `0x${bytesToHex(publicKeyBytes)}` as HexString
492
+ )
493
+
494
+ return {
495
+ publicKey: `0x${bytesToHex(publicKeyBytes)}` as HexString,
496
+ privateKey: recovery.privateKey,
497
+ accountId,
498
+ nearPublicKey,
499
+ publicKeyBytes,
500
+ }
501
+ }
502
+
503
+ // ─── Claim Transactions ───────────────────────────────────────────────────────
504
+
505
+ /**
506
+ * Build a transaction to claim funds from a stealth account
507
+ *
508
+ * @param params - Claim parameters
509
+ * @returns Transaction build with actions
510
+ *
511
+ * @example Claim native NEAR
512
+ * ```typescript
513
+ * const { actions, receiverId } = buildClaimTransaction({
514
+ * stealthAccountId: '1234...abcd',
515
+ * destinationAccountId: 'alice.near',
516
+ * amount: 1_000_000_000_000_000_000_000_000n,
517
+ * })
518
+ *
519
+ * // Sign with derived stealth keypair and send
520
+ * ```
521
+ */
522
+ export function buildClaimTransaction(
523
+ params: NEARClaimTransactionParams
524
+ ): NEARClaimTransactionBuild {
525
+ const {
526
+ stealthAccountId,
527
+ destinationAccountId,
528
+ amount,
529
+ tokenContract,
530
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
531
+ keepStorageDeposit: _keepStorageDeposit = true, // Reserved for future balance calculation
532
+ } = params
533
+
534
+ // Validate stealth account
535
+ if (!isImplicitAccount(stealthAccountId)) {
536
+ throw new ValidationError(
537
+ 'stealthAccountId must be a valid implicit account',
538
+ 'stealthAccountId'
539
+ )
540
+ }
541
+
542
+ // Validate destination
543
+ if (!isValidAccountId(destinationAccountId)) {
544
+ throw new ValidationError(
545
+ 'Invalid destinationAccountId',
546
+ 'destinationAccountId'
547
+ )
548
+ }
549
+
550
+ // Token transfer
551
+ if (tokenContract) {
552
+ if (!isValidAccountId(tokenContract)) {
553
+ throw new ValidationError('Invalid tokenContract', 'tokenContract')
554
+ }
555
+
556
+ const args = JSON.stringify({
557
+ receiver_id: destinationAccountId,
558
+ amount: amount?.toString() ?? '0', // Will need to query balance if not specified
559
+ memo: null,
560
+ })
561
+
562
+ return {
563
+ actions: [
564
+ {
565
+ type: 'FunctionCall',
566
+ params: {
567
+ methodName: 'ft_transfer',
568
+ args,
569
+ gas: DEFAULT_GAS,
570
+ deposit: ONE_YOCTO,
571
+ } as NEARFunctionCallAction,
572
+ },
573
+ ],
574
+ receiverId: tokenContract,
575
+ isTokenTransfer: true,
576
+ }
577
+ }
578
+
579
+ // Native NEAR transfer
580
+ const transferAmount = amount ?? 0n
581
+
582
+ return {
583
+ actions: [
584
+ {
585
+ type: 'Transfer',
586
+ params: {
587
+ deposit: transferAmount,
588
+ } as NEARTransferAction,
589
+ },
590
+ ],
591
+ receiverId: destinationAccountId,
592
+ isTokenTransfer: false,
593
+ }
594
+ }
595
+
596
+ /**
597
+ * Build a transaction to delete a stealth account and claim all funds
598
+ *
599
+ * This is more gas-efficient than regular transfer as it reclaims
600
+ * storage deposit. Use when you want to fully drain the account.
601
+ *
602
+ * @param stealthAccountId - Stealth implicit account to delete
603
+ * @param beneficiaryId - Account to receive all remaining funds
604
+ * @returns Delete account action
605
+ */
606
+ export function buildDeleteStealthAccount(
607
+ stealthAccountId: string,
608
+ beneficiaryId: string
609
+ ): NEARAction[] {
610
+ if (!isImplicitAccount(stealthAccountId)) {
611
+ throw new ValidationError(
612
+ 'stealthAccountId must be a valid implicit account',
613
+ 'stealthAccountId'
614
+ )
615
+ }
616
+
617
+ if (!isValidAccountId(beneficiaryId)) {
618
+ throw new ValidationError('Invalid beneficiaryId', 'beneficiaryId')
619
+ }
620
+
621
+ return [
622
+ {
623
+ type: 'DeleteAccount',
624
+ params: {
625
+ beneficiaryId,
626
+ } as NEARDeleteAccountAction,
627
+ },
628
+ ]
629
+ }
630
+
631
+ // ─── Access Key Management ────────────────────────────────────────────────────
632
+
633
+ /**
634
+ * Build actions to add an access key to a stealth account
635
+ *
636
+ * This allows spending from the stealth account with a different key
637
+ * (e.g., a hardware wallet key) without revealing the stealth private key.
638
+ *
639
+ * @param params - Add access key parameters
640
+ * @returns Add key action
641
+ *
642
+ * @example Add full access key
643
+ * ```typescript
644
+ * const actions = buildAddAccessKey({
645
+ * newPublicKey: 'ed25519:...',
646
+ * permission: 'FullAccess',
647
+ * })
648
+ *
649
+ * // Sign with stealth keypair and send
650
+ * ```
651
+ */
652
+ export function buildAddAccessKey(params: NEARAddAccessKeyParams): NEARAction[] {
653
+ const { newPublicKey, permission } = params
654
+
655
+ // Validate public key format
656
+ if (!newPublicKey.startsWith('ed25519:')) {
657
+ throw new ValidationError(
658
+ 'newPublicKey must be in ed25519:base58 format',
659
+ 'newPublicKey'
660
+ )
661
+ }
662
+
663
+ const accessKey = permission === 'FullAccess'
664
+ ? { permission: 'FullAccess' as const }
665
+ : {
666
+ permission: {
667
+ FunctionCall: {
668
+ allowance: permission.allowance,
669
+ receiverId: permission.receiverId,
670
+ methodNames: permission.methodNames,
671
+ },
672
+ },
673
+ }
674
+
675
+ return [
676
+ {
677
+ type: 'AddKey',
678
+ params: {
679
+ publicKey: newPublicKey,
680
+ accessKey,
681
+ } as NEARAddKeyAction,
682
+ },
683
+ ]
684
+ }
685
+
686
+ /**
687
+ * Build actions for key rotation on a stealth account
688
+ *
689
+ * Atomically adds a new key and removes the old key in a single transaction.
690
+ * Useful for migrating to a hardware wallet key.
691
+ *
692
+ * @param params - Key rotation parameters
693
+ * @returns Actions for key rotation
694
+ */
695
+ export function buildKeyRotation(params: NEARKeyRotationParams): NEARAction[] {
696
+ const { newPublicKey, oldPublicKey, permission = 'FullAccess' } = params
697
+
698
+ // Validate public key formats
699
+ if (!newPublicKey.startsWith('ed25519:')) {
700
+ throw new ValidationError(
701
+ 'newPublicKey must be in ed25519:base58 format',
702
+ 'newPublicKey'
703
+ )
704
+ }
705
+ if (!oldPublicKey.startsWith('ed25519:')) {
706
+ throw new ValidationError(
707
+ 'oldPublicKey must be in ed25519:base58 format',
708
+ 'oldPublicKey'
709
+ )
710
+ }
711
+
712
+ const accessKey = permission === 'FullAccess'
713
+ ? { permission: 'FullAccess' as const }
714
+ : {
715
+ permission: {
716
+ FunctionCall: {
717
+ allowance: permission.allowance,
718
+ receiverId: permission.receiverId,
719
+ methodNames: permission.methodNames,
720
+ },
721
+ },
722
+ }
723
+
724
+ // Add new key first, then delete old key
725
+ return [
726
+ {
727
+ type: 'AddKey',
728
+ params: {
729
+ publicKey: newPublicKey,
730
+ accessKey,
731
+ } as NEARAddKeyAction,
732
+ },
733
+ {
734
+ type: 'DeleteKey',
735
+ params: {
736
+ publicKey: oldPublicKey,
737
+ } as NEARDeleteKeyAction,
738
+ },
739
+ ]
740
+ }
741
+
742
+ // ─── Account State Helpers ────────────────────────────────────────────────────
743
+
744
+ /**
745
+ * Check if an implicit account ID is valid and follows stealth address format
746
+ *
747
+ * @param accountId - Account ID to check
748
+ * @returns True if it's a valid stealth-compatible implicit account
749
+ */
750
+ export function isStealthCompatibleAccount(accountId: string): boolean {
751
+ return isImplicitAccount(accountId)
752
+ }
753
+
754
+ /**
755
+ * Get the public key for an implicit account
756
+ *
757
+ * @param accountId - Implicit account ID (64 hex chars)
758
+ * @returns Ed25519 public key in NEAR format (ed25519:base58)
759
+ */
760
+ export function getImplicitAccountPublicKey(accountId: string): string {
761
+ if (!isImplicitAccount(accountId)) {
762
+ throw new ValidationError(
763
+ 'accountId must be a valid implicit account',
764
+ 'accountId'
765
+ )
766
+ }
767
+
768
+ // Convert hex to bytes
769
+ const publicKeyBytes = hexToBytes(accountId)
770
+
771
+ // Convert to base58 and format
772
+ return `ed25519:${bytesToBase58(publicKeyBytes)}`
773
+ }
774
+
775
+ /**
776
+ * Verify that an implicit account matches a stealth address
777
+ *
778
+ * @param accountId - Implicit account ID to check
779
+ * @param stealthAddress - Expected stealth address
780
+ * @returns True if the account matches the stealth address
781
+ */
782
+ export function verifyImplicitAccountMatch(
783
+ accountId: string,
784
+ stealthAddress: StealthAddress
785
+ ): boolean {
786
+ if (!isImplicitAccount(accountId)) {
787
+ return false
788
+ }
789
+
790
+ // Get expected account ID from stealth address
791
+ const expectedAccountId = ed25519PublicKeyToImplicitAccount(stealthAddress.address)
792
+
793
+ return accountId.toLowerCase() === expectedAccountId.toLowerCase()
794
+ }
795
+
796
+ // ─── Utility Functions ────────────────────────────────────────────────────────
797
+
798
+ /**
799
+ * Convert bytes to little-endian BigInt
800
+ */
801
+ function bytesToBigIntLE(bytes: Uint8Array): bigint {
802
+ let result = 0n
803
+ for (let i = bytes.length - 1; i >= 0; i--) {
804
+ result = (result << 8n) | BigInt(bytes[i])
805
+ }
806
+ return result
807
+ }
808
+
809
+ /**
810
+ * Convert bytes to base58
811
+ */
812
+ function bytesToBase58(bytes: Uint8Array): string {
813
+ const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
814
+
815
+ // Count leading zeros
816
+ let zeros = 0
817
+ for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
818
+ zeros++
819
+ }
820
+
821
+ // Convert to base58
822
+ const result: number[] = []
823
+ let num = 0n
824
+ for (const byte of bytes) {
825
+ num = num * 256n + BigInt(byte)
826
+ }
827
+
828
+ while (num > 0n) {
829
+ const remainder = Number(num % 58n)
830
+ num = num / 58n
831
+ result.unshift(remainder)
832
+ }
833
+
834
+ // Add leading '1's for each leading zero byte
835
+ for (let i = 0; i < zeros; i++) {
836
+ result.unshift(0)
837
+ }
838
+
839
+ return result.map(i => ALPHABET[i]).join('')
840
+ }