@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,775 @@
1
+ /**
2
+ * NEAR NEP-141 Token Privacy Support
3
+ *
4
+ * Extends basic token transfer functionality with:
5
+ * - Amount commitments for hidden transfer values
6
+ * - ft_transfer_call support for DeFi interactions
7
+ * - Batch token transfers with privacy
8
+ * - Token metadata fetching for UI display
9
+ *
10
+ * @example Privacy-wrapped token transfer with commitment
11
+ * ```typescript
12
+ * import { buildPrivateTokenTransferWithCommitment } from '@sip-protocol/sdk'
13
+ *
14
+ * const result = buildPrivateTokenTransferWithCommitment({
15
+ * recipientMetaAddress: 'sip:near:0x...:0x...',
16
+ * tokenContract: 'usdc.near',
17
+ * amount: 100_000_000n, // 100 USDC
18
+ * decimals: 6,
19
+ * hideAmount: true,
20
+ * })
21
+ *
22
+ * // result.commitment contains the hidden amount
23
+ * // result.transfer contains the transaction actions
24
+ * ```
25
+ *
26
+ * @example ft_transfer_call for DeFi
27
+ * ```typescript
28
+ * import { buildPrivateTokenTransferCall } from '@sip-protocol/sdk'
29
+ *
30
+ * const result = buildPrivateTokenTransferCall({
31
+ * recipientMetaAddress: 'sip:near:0x...:0x...',
32
+ * tokenContract: 'usdc.near',
33
+ * amount: 100_000_000n,
34
+ * msg: JSON.stringify({ action: 'deposit' }),
35
+ * })
36
+ * ```
37
+ *
38
+ * @packageDocumentation
39
+ */
40
+
41
+ import type { HexString, StealthAddress, StealthMetaAddress } from '@sip-protocol/types'
42
+ import { ValidationError } from '../../errors'
43
+ import { isValidAccountId, DEFAULT_GAS, ONE_YOCTO, STORAGE_DEPOSIT_DEFAULT } from './constants'
44
+ import { generateNEARStealthAddress, parseNEARStealthMetaAddress } from './stealth'
45
+ import { createAnnouncementMemo } from './types'
46
+ import { commitNEP141Token, type NEP141TokenCommitment } from './commitment'
47
+ import type { NEARAction, NEARFunctionCallAction, NEARPrivateTransferBuild } from './implicit-account'
48
+
49
+ // ─── Types ────────────────────────────────────────────────────────────────────
50
+
51
+ /**
52
+ * Parameters for a privacy-wrapped token transfer with commitment
53
+ */
54
+ export interface PrivateTokenTransferWithCommitmentParams {
55
+ /** Recipient's stealth meta-address */
56
+ recipientMetaAddress: StealthMetaAddress | string
57
+ /** NEP-141 token contract address */
58
+ tokenContract: string
59
+ /** Amount in token's smallest units */
60
+ amount: bigint
61
+ /** Token decimals (required for commitment) */
62
+ decimals: number
63
+ /** Whether to create a Pedersen commitment for the amount (default: true) */
64
+ hideAmount?: boolean
65
+ /** Optional memo for the transfer */
66
+ memo?: string
67
+ /** Optional pre-generated blinding factor */
68
+ blinding?: Uint8Array
69
+ }
70
+
71
+ /**
72
+ * Result of building a privacy-wrapped token transfer with commitment
73
+ */
74
+ export interface PrivateTokenTransferWithCommitmentResult {
75
+ /** The transfer build (actions, stealth address, etc.) */
76
+ transfer: NEARPrivateTransferBuild
77
+ /** Amount commitment (if hideAmount is true) */
78
+ commitment?: NEP141TokenCommitment
79
+ /** The stealth address */
80
+ stealthAddress: StealthAddress
81
+ /** NEAR implicit account ID */
82
+ stealthAccountId: string
83
+ }
84
+
85
+ /**
86
+ * Parameters for ft_transfer_call with privacy
87
+ */
88
+ export interface PrivateTokenTransferCallParams {
89
+ /** Recipient's stealth meta-address */
90
+ recipientMetaAddress: StealthMetaAddress | string
91
+ /** NEP-141 token contract address */
92
+ tokenContract: string
93
+ /** Amount in token's smallest units */
94
+ amount: bigint
95
+ /** Message to pass to the receiver contract */
96
+ msg: string
97
+ /** Optional memo for the transfer */
98
+ memo?: string
99
+ /** Gas for the receiver callback (default: 30 TGas) */
100
+ receiverGas?: bigint
101
+ }
102
+
103
+ /**
104
+ * Result of building a ft_transfer_call with privacy
105
+ */
106
+ export interface PrivateTokenTransferCallResult {
107
+ /** Transaction actions */
108
+ actions: NEARAction[]
109
+ /** Receiver ID (the token contract) */
110
+ receiverId: string
111
+ /** The stealth address */
112
+ stealthAddress: StealthAddress
113
+ /** NEAR implicit account ID */
114
+ stealthAccountId: string
115
+ /** Announcement memo */
116
+ announcementMemo: string
117
+ }
118
+
119
+ /**
120
+ * Parameters for batch token transfer
121
+ */
122
+ export interface BatchTokenTransferParams {
123
+ /** Token contract for all transfers */
124
+ tokenContract: string
125
+ /** List of transfers to execute */
126
+ transfers: Array<{
127
+ /** Recipient's stealth meta-address */
128
+ recipientMetaAddress: StealthMetaAddress | string
129
+ /** Amount in token's smallest units */
130
+ amount: bigint
131
+ }>
132
+ /** Token decimals (for commitments) */
133
+ decimals?: number
134
+ /** Create commitments for amounts */
135
+ hideAmounts?: boolean
136
+ }
137
+
138
+ /**
139
+ * Result of building batch token transfers
140
+ */
141
+ export interface BatchTokenTransferResult {
142
+ /** Individual transfer results */
143
+ transfers: Array<{
144
+ stealthAddress: StealthAddress
145
+ stealthAccountId: string
146
+ announcementMemo: string
147
+ amount: bigint
148
+ commitment?: NEP141TokenCommitment
149
+ }>
150
+ /** Combined actions for all transfers */
151
+ actions: NEARAction[]
152
+ /** Receiver ID (the token contract) */
153
+ receiverId: string
154
+ /** Total amount being transferred */
155
+ totalAmount: bigint
156
+ }
157
+
158
+ /**
159
+ * NEP-141 token metadata
160
+ */
161
+ export interface NEP141TokenMetadata {
162
+ /** Token specification (e.g., "ft-1.0.0") */
163
+ spec: string
164
+ /** Token name */
165
+ name: string
166
+ /** Token symbol */
167
+ symbol: string
168
+ /** Token icon (data URI or URL) */
169
+ icon?: string
170
+ /** Reference URL for additional info */
171
+ reference?: string
172
+ /** SHA256 hash of reference content */
173
+ referenceHash?: string
174
+ /** Number of decimals */
175
+ decimals: number
176
+ }
177
+
178
+ /**
179
+ * Token balance with metadata
180
+ */
181
+ export interface TokenBalanceInfo {
182
+ /** Balance in smallest units */
183
+ balance: bigint
184
+ /** Token metadata */
185
+ metadata?: NEP141TokenMetadata
186
+ /** Storage deposit status */
187
+ hasStorageDeposit: boolean
188
+ }
189
+
190
+ /**
191
+ * Storage deposit info
192
+ */
193
+ export interface StorageDepositInfo {
194
+ /** Total storage balance */
195
+ total: bigint
196
+ /** Available storage balance */
197
+ available: bigint
198
+ }
199
+
200
+ // ─── Constants ────────────────────────────────────────────────────────────────
201
+
202
+ /**
203
+ * Default gas for ft_transfer_call receiver callback
204
+ */
205
+ export const FT_TRANSFER_CALL_GAS = 30_000_000_000_000n // 30 TGas
206
+
207
+ /**
208
+ * Gas for ft_transfer_call itself
209
+ */
210
+ export const FT_TRANSFER_CALL_TOTAL_GAS = 100_000_000_000_000n // 100 TGas
211
+
212
+ // ─── Privacy-Wrapped Token Transfers ──────────────────────────────────────────
213
+
214
+ /**
215
+ * Build a privacy-wrapped NEP-141 token transfer with optional amount commitment
216
+ *
217
+ * Creates a Pedersen commitment to the amount, allowing the recipient to
218
+ * verify the amount while keeping it hidden from observers.
219
+ *
220
+ * @param params - Transfer parameters
221
+ * @returns Transfer build with optional commitment
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * const result = buildPrivateTokenTransferWithCommitment({
226
+ * recipientMetaAddress: 'sip:near:0x...:0x...',
227
+ * tokenContract: 'usdc.near',
228
+ * amount: 100_000_000n, // 100 USDC
229
+ * decimals: 6,
230
+ * hideAmount: true,
231
+ * })
232
+ *
233
+ * // Share commitment with recipient off-chain
234
+ * // They can verify with the blinding factor
235
+ * ```
236
+ */
237
+ export function buildPrivateTokenTransferWithCommitment(
238
+ params: PrivateTokenTransferWithCommitmentParams
239
+ ): PrivateTokenTransferWithCommitmentResult {
240
+ const {
241
+ recipientMetaAddress,
242
+ tokenContract,
243
+ amount,
244
+ decimals,
245
+ hideAmount = true,
246
+ memo,
247
+ blinding,
248
+ } = params
249
+
250
+ // Parse meta-address if string
251
+ const metaAddr = typeof recipientMetaAddress === 'string'
252
+ ? parseNEARStealthMetaAddress(recipientMetaAddress)
253
+ : recipientMetaAddress
254
+
255
+ // Validate chain
256
+ if (metaAddr.chain !== 'near') {
257
+ throw new ValidationError(
258
+ `Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
259
+ 'recipientMetaAddress'
260
+ )
261
+ }
262
+
263
+ // Validate token contract
264
+ if (!isValidAccountId(tokenContract)) {
265
+ throw new ValidationError('Invalid token contract account ID', 'tokenContract')
266
+ }
267
+
268
+ // Validate amount
269
+ if (amount <= 0n) {
270
+ throw new ValidationError('amount must be greater than 0', 'amount')
271
+ }
272
+
273
+ // Generate stealth address
274
+ const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
275
+
276
+ // Create announcement memo
277
+ const announcementMemo = createAnnouncementMemo(
278
+ stealthAddress.ephemeralPublicKey,
279
+ stealthAddress.viewTag
280
+ )
281
+
282
+ // Create amount commitment if requested
283
+ let commitment: NEP141TokenCommitment | undefined
284
+ if (hideAmount) {
285
+ commitment = commitNEP141Token(amount, tokenContract, decimals, blinding)
286
+ }
287
+
288
+ // Build ft_transfer args with commitment hash in memo
289
+ const transferMemo = commitment
290
+ ? `${announcementMemo}|c:${commitment.commitment.slice(2, 18)}` // Include commitment prefix
291
+ : announcementMemo
292
+
293
+ const fullMemo = memo ? `${transferMemo}|${memo}` : transferMemo
294
+ const args = JSON.stringify({
295
+ receiver_id: implicitAccountId,
296
+ amount: amount.toString(),
297
+ memo: fullMemo,
298
+ })
299
+
300
+ // Build function call action
301
+ const actions: NEARAction[] = [
302
+ {
303
+ type: 'FunctionCall',
304
+ params: {
305
+ methodName: 'ft_transfer',
306
+ args,
307
+ gas: DEFAULT_GAS,
308
+ deposit: ONE_YOCTO,
309
+ } as NEARFunctionCallAction,
310
+ },
311
+ ]
312
+
313
+ const transfer: NEARPrivateTransferBuild = {
314
+ stealthAddress,
315
+ stealthAccountId: implicitAccountId,
316
+ announcementMemo,
317
+ actions,
318
+ receiverId: tokenContract,
319
+ }
320
+
321
+ return {
322
+ transfer,
323
+ commitment,
324
+ stealthAddress,
325
+ stealthAccountId: implicitAccountId,
326
+ }
327
+ }
328
+
329
+ /**
330
+ * Build a privacy-wrapped ft_transfer_call for DeFi interactions
331
+ *
332
+ * ft_transfer_call sends tokens and triggers a callback on the receiver,
333
+ * enabling composable DeFi operations with privacy.
334
+ *
335
+ * @param params - Transfer call parameters
336
+ * @returns Transfer call build
337
+ *
338
+ * @example Deposit to a DEX with privacy
339
+ * ```typescript
340
+ * const result = buildPrivateTokenTransferCall({
341
+ * recipientMetaAddress: 'sip:near:0x...:0x...',
342
+ * tokenContract: 'usdc.near',
343
+ * amount: 100_000_000n,
344
+ * msg: JSON.stringify({
345
+ * action: 'swap',
346
+ * output_token: 'wrap.near',
347
+ * min_output: '1000000000000000000000000',
348
+ * }),
349
+ * })
350
+ * ```
351
+ */
352
+ export function buildPrivateTokenTransferCall(
353
+ params: PrivateTokenTransferCallParams
354
+ ): PrivateTokenTransferCallResult {
355
+ const {
356
+ recipientMetaAddress,
357
+ tokenContract,
358
+ amount,
359
+ msg,
360
+ memo,
361
+ receiverGas = FT_TRANSFER_CALL_GAS,
362
+ } = params
363
+
364
+ // Parse meta-address if string
365
+ const metaAddr = typeof recipientMetaAddress === 'string'
366
+ ? parseNEARStealthMetaAddress(recipientMetaAddress)
367
+ : recipientMetaAddress
368
+
369
+ // Validate chain
370
+ if (metaAddr.chain !== 'near') {
371
+ throw new ValidationError(
372
+ `Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
373
+ 'recipientMetaAddress'
374
+ )
375
+ }
376
+
377
+ // Validate token contract
378
+ if (!isValidAccountId(tokenContract)) {
379
+ throw new ValidationError('Invalid token contract account ID', 'tokenContract')
380
+ }
381
+
382
+ // Validate amount
383
+ if (amount <= 0n) {
384
+ throw new ValidationError('amount must be greater than 0', 'amount')
385
+ }
386
+
387
+ // Validate msg is valid JSON
388
+ try {
389
+ JSON.parse(msg)
390
+ } catch {
391
+ throw new ValidationError('msg must be valid JSON', 'msg')
392
+ }
393
+
394
+ // Generate stealth address
395
+ const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
396
+
397
+ // Create announcement memo
398
+ const announcementMemo = createAnnouncementMemo(
399
+ stealthAddress.ephemeralPublicKey,
400
+ stealthAddress.viewTag
401
+ )
402
+
403
+ // Build ft_transfer_call args
404
+ const transferMemo = memo ? `${announcementMemo}|${memo}` : announcementMemo
405
+ const args = JSON.stringify({
406
+ receiver_id: implicitAccountId,
407
+ amount: amount.toString(),
408
+ memo: transferMemo,
409
+ msg,
410
+ })
411
+
412
+ // Build function call action with extra gas for callback
413
+ const totalGas = FT_TRANSFER_CALL_TOTAL_GAS > receiverGas
414
+ ? FT_TRANSFER_CALL_TOTAL_GAS
415
+ : receiverGas + 50_000_000_000_000n
416
+
417
+ const actions: NEARAction[] = [
418
+ {
419
+ type: 'FunctionCall',
420
+ params: {
421
+ methodName: 'ft_transfer_call',
422
+ args,
423
+ gas: totalGas,
424
+ deposit: ONE_YOCTO,
425
+ } as NEARFunctionCallAction,
426
+ },
427
+ ]
428
+
429
+ return {
430
+ actions,
431
+ receiverId: tokenContract,
432
+ stealthAddress,
433
+ stealthAccountId: implicitAccountId,
434
+ announcementMemo,
435
+ }
436
+ }
437
+
438
+ // ─── Batch Token Transfers ────────────────────────────────────────────────────
439
+
440
+ /**
441
+ * Build batch privacy-wrapped token transfers
442
+ *
443
+ * Sends tokens to multiple stealth addresses in a single transaction,
444
+ * improving efficiency and reducing transaction costs.
445
+ *
446
+ * Note: NEAR doesn't support batch ft_transfer in a single action,
447
+ * so this creates multiple function call actions.
448
+ *
449
+ * @param params - Batch transfer parameters
450
+ * @returns Batch transfer build
451
+ *
452
+ * @example
453
+ * ```typescript
454
+ * const result = buildBatchPrivateTokenTransfer({
455
+ * tokenContract: 'usdc.near',
456
+ * transfers: [
457
+ * { recipientMetaAddress: 'sip:near:0x...', amount: 100_000_000n },
458
+ * { recipientMetaAddress: 'sip:near:0x...', amount: 50_000_000n },
459
+ * ],
460
+ * decimals: 6,
461
+ * hideAmounts: true,
462
+ * })
463
+ *
464
+ * // Execute all transfers in one transaction
465
+ * ```
466
+ */
467
+ export function buildBatchPrivateTokenTransfer(
468
+ params: BatchTokenTransferParams
469
+ ): BatchTokenTransferResult {
470
+ const {
471
+ tokenContract,
472
+ transfers,
473
+ decimals,
474
+ hideAmounts = false,
475
+ } = params
476
+
477
+ // Validate token contract
478
+ if (!isValidAccountId(tokenContract)) {
479
+ throw new ValidationError('Invalid token contract account ID', 'tokenContract')
480
+ }
481
+
482
+ // Validate transfers
483
+ if (!transfers || transfers.length === 0) {
484
+ throw new ValidationError('At least one transfer is required', 'transfers')
485
+ }
486
+
487
+ if (transfers.length > 10) {
488
+ throw new ValidationError(
489
+ 'Maximum 10 transfers per batch (gas limit)',
490
+ 'transfers'
491
+ )
492
+ }
493
+
494
+ // Validate decimals if hiding amounts
495
+ if (hideAmounts && decimals === undefined) {
496
+ throw new ValidationError(
497
+ 'decimals is required when hideAmounts is true',
498
+ 'decimals'
499
+ )
500
+ }
501
+
502
+ const results: BatchTokenTransferResult['transfers'] = []
503
+ const actions: NEARAction[] = []
504
+ let totalAmount = 0n
505
+
506
+ for (const transfer of transfers) {
507
+ const { recipientMetaAddress, amount } = transfer
508
+
509
+ // Parse meta-address if string
510
+ const metaAddr = typeof recipientMetaAddress === 'string'
511
+ ? parseNEARStealthMetaAddress(recipientMetaAddress)
512
+ : recipientMetaAddress
513
+
514
+ // Validate chain
515
+ if (metaAddr.chain !== 'near') {
516
+ throw new ValidationError(
517
+ `Expected NEAR meta-address, got chain '${metaAddr.chain}'`,
518
+ 'recipientMetaAddress'
519
+ )
520
+ }
521
+
522
+ // Validate amount
523
+ if (amount <= 0n) {
524
+ throw new ValidationError('amount must be greater than 0', 'amount')
525
+ }
526
+
527
+ // Generate stealth address
528
+ const { stealthAddress, implicitAccountId } = generateNEARStealthAddress(metaAddr)
529
+
530
+ // Create announcement memo
531
+ const announcementMemo = createAnnouncementMemo(
532
+ stealthAddress.ephemeralPublicKey,
533
+ stealthAddress.viewTag
534
+ )
535
+
536
+ // Create commitment if hiding amounts
537
+ let commitment: NEP141TokenCommitment | undefined
538
+ if (hideAmounts && decimals !== undefined) {
539
+ commitment = commitNEP141Token(amount, tokenContract, decimals)
540
+ }
541
+
542
+ // Build transfer memo
543
+ const transferMemo = commitment
544
+ ? `${announcementMemo}|c:${commitment.commitment.slice(2, 18)}`
545
+ : announcementMemo
546
+
547
+ // Build ft_transfer args
548
+ const args = JSON.stringify({
549
+ receiver_id: implicitAccountId,
550
+ amount: amount.toString(),
551
+ memo: transferMemo,
552
+ })
553
+
554
+ // Add action
555
+ actions.push({
556
+ type: 'FunctionCall',
557
+ params: {
558
+ methodName: 'ft_transfer',
559
+ args,
560
+ gas: DEFAULT_GAS,
561
+ deposit: ONE_YOCTO,
562
+ } as NEARFunctionCallAction,
563
+ })
564
+
565
+ results.push({
566
+ stealthAddress,
567
+ stealthAccountId: implicitAccountId,
568
+ announcementMemo,
569
+ amount,
570
+ commitment,
571
+ })
572
+
573
+ totalAmount += amount
574
+ }
575
+
576
+ return {
577
+ transfers: results,
578
+ actions,
579
+ receiverId: tokenContract,
580
+ totalAmount,
581
+ }
582
+ }
583
+
584
+ // ─── Storage Deposit Helpers ──────────────────────────────────────────────────
585
+
586
+ /**
587
+ * Build batch storage deposit for multiple stealth accounts
588
+ *
589
+ * Pre-registers storage for multiple stealth accounts before sending tokens.
590
+ *
591
+ * @param stealthAccountIds - List of stealth implicit account IDs
592
+ * @param tokenContract - Token contract address
593
+ * @param amountPerAccount - Storage deposit per account (default: 0.00125 NEAR)
594
+ * @returns Storage deposit actions
595
+ */
596
+ export function buildBatchStorageDeposit(
597
+ stealthAccountIds: string[],
598
+ tokenContract: string,
599
+ amountPerAccount: bigint = STORAGE_DEPOSIT_DEFAULT
600
+ ): NEARAction[] {
601
+ if (!isValidAccountId(tokenContract)) {
602
+ throw new ValidationError('Invalid token contract account ID', 'tokenContract')
603
+ }
604
+
605
+ if (!stealthAccountIds || stealthAccountIds.length === 0) {
606
+ throw new ValidationError('At least one account ID is required', 'stealthAccountIds')
607
+ }
608
+
609
+ if (stealthAccountIds.length > 20) {
610
+ throw new ValidationError(
611
+ 'Maximum 20 storage deposits per batch (gas limit)',
612
+ 'stealthAccountIds'
613
+ )
614
+ }
615
+
616
+ return stealthAccountIds.map(accountId => {
617
+ const args = JSON.stringify({
618
+ account_id: accountId,
619
+ })
620
+
621
+ return {
622
+ type: 'FunctionCall' as const,
623
+ params: {
624
+ methodName: 'storage_deposit',
625
+ args,
626
+ gas: DEFAULT_GAS,
627
+ deposit: amountPerAccount,
628
+ } as NEARFunctionCallAction,
629
+ }
630
+ })
631
+ }
632
+
633
+ /**
634
+ * Build storage withdraw action
635
+ *
636
+ * Withdraw excess storage deposit from a token contract.
637
+ *
638
+ * @param amount - Amount to withdraw (null for all available)
639
+ * @returns Storage withdraw action
640
+ */
641
+ export function buildStorageWithdraw(amount?: bigint): NEARAction {
642
+ const args = amount !== undefined
643
+ ? JSON.stringify({ amount: amount.toString() })
644
+ : '{}'
645
+
646
+ return {
647
+ type: 'FunctionCall',
648
+ params: {
649
+ methodName: 'storage_withdraw',
650
+ args,
651
+ gas: DEFAULT_GAS,
652
+ deposit: ONE_YOCTO,
653
+ } as NEARFunctionCallAction,
654
+ }
655
+ }
656
+
657
+ /**
658
+ * Build storage unregister action
659
+ *
660
+ * Unregister from a token contract and reclaim storage deposit.
661
+ * Only works if token balance is zero.
662
+ *
663
+ * @param force - Force unregister even if balance > 0 (burns tokens)
664
+ * @returns Storage unregister action
665
+ */
666
+ export function buildStorageUnregister(force: boolean = false): NEARAction {
667
+ const args = JSON.stringify({ force })
668
+
669
+ return {
670
+ type: 'FunctionCall',
671
+ params: {
672
+ methodName: 'storage_unregister',
673
+ args,
674
+ gas: DEFAULT_GAS,
675
+ deposit: ONE_YOCTO,
676
+ } as NEARFunctionCallAction,
677
+ }
678
+ }
679
+
680
+ // ─── Token Metadata ───────────────────────────────────────────────────────────
681
+
682
+ /**
683
+ * Parse ft_metadata response
684
+ *
685
+ * @param response - Raw metadata response from RPC
686
+ * @returns Parsed token metadata
687
+ */
688
+ export function parseTokenMetadata(response: unknown): NEP141TokenMetadata {
689
+ if (!response || typeof response !== 'object') {
690
+ throw new ValidationError('Invalid metadata response', 'response')
691
+ }
692
+
693
+ const data = response as Record<string, unknown>
694
+
695
+ return {
696
+ spec: String(data.spec || 'ft-1.0.0'),
697
+ name: String(data.name || 'Unknown Token'),
698
+ symbol: String(data.symbol || '???'),
699
+ icon: data.icon ? String(data.icon) : undefined,
700
+ reference: data.reference ? String(data.reference) : undefined,
701
+ referenceHash: data.reference_hash ? String(data.reference_hash) : undefined,
702
+ decimals: Number(data.decimals || 0),
703
+ }
704
+ }
705
+
706
+ /**
707
+ * Format token amount for display
708
+ *
709
+ * @param amount - Amount in smallest units
710
+ * @param decimals - Token decimals
711
+ * @param symbol - Token symbol
712
+ * @returns Formatted amount string (e.g., "100.50 USDC")
713
+ */
714
+ export function formatTokenAmount(
715
+ amount: bigint,
716
+ decimals: number,
717
+ symbol?: string
718
+ ): string {
719
+ const str = amount.toString().padStart(decimals + 1, '0')
720
+ const whole = str.slice(0, -decimals) || '0'
721
+ const fraction = str.slice(-decimals).replace(/0+$/, '')
722
+
723
+ const formatted = fraction ? `${whole}.${fraction}` : whole
724
+
725
+ return symbol ? `${formatted} ${symbol}` : formatted
726
+ }
727
+
728
+ /**
729
+ * Parse token amount from display string
730
+ *
731
+ * @param displayAmount - Human-readable amount (e.g., "100.50")
732
+ * @param decimals - Token decimals
733
+ * @returns Amount in smallest units
734
+ */
735
+ export function parseTokenAmount(displayAmount: string, decimals: number): bigint {
736
+ // Remove any symbol suffix
737
+ const cleaned = displayAmount.replace(/[^0-9.]/g, '').trim()
738
+
739
+ const [whole, fraction = ''] = cleaned.split('.')
740
+ const paddedFraction = fraction.padEnd(decimals, '0').slice(0, decimals)
741
+
742
+ return BigInt(whole + paddedFraction)
743
+ }
744
+
745
+ // ─── Commitment Verification ──────────────────────────────────────────────────
746
+
747
+ /**
748
+ * Extract commitment hash from transfer memo
749
+ *
750
+ * @param memo - Transfer memo string
751
+ * @returns Commitment hash prefix if present
752
+ */
753
+ export function extractCommitmentFromMemo(memo: string): string | null {
754
+ const match = memo.match(/\|c:([a-f0-9]{16})/)
755
+ return match ? match[1] : null
756
+ }
757
+
758
+ /**
759
+ * Verify that a commitment matches the expected prefix in memo
760
+ *
761
+ * @param commitment - The full commitment
762
+ * @param memo - Transfer memo
763
+ * @returns True if commitment matches memo prefix
764
+ */
765
+ export function verifyCommitmentInMemo(
766
+ commitment: HexString,
767
+ memo: string
768
+ ): boolean {
769
+ const extracted = extractCommitmentFromMemo(memo)
770
+ if (!extracted) return false
771
+
772
+ // Compare prefix (first 16 hex chars after 0x)
773
+ const commitmentPrefix = commitment.slice(2, 18)
774
+ return commitmentPrefix === extracted
775
+ }