@ledgerhq/coin-sui 0.16.0 → 0.17.0-nightly.1

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 (329) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.unimportedrc.json +2 -1
  3. package/CHANGELOG.md +22 -0
  4. package/lib/api/index.d.ts.map +1 -1
  5. package/lib/api/index.js +1 -0
  6. package/lib/api/index.js.map +1 -1
  7. package/lib/logic/estimateFees.d.ts +4 -1
  8. package/lib/logic/estimateFees.d.ts.map +1 -1
  9. package/lib/logic/estimateFees.js +2 -1
  10. package/lib/logic/estimateFees.js.map +1 -1
  11. package/lib/logic/getValidators.d.ts +3 -0
  12. package/lib/logic/getValidators.d.ts.map +1 -0
  13. package/lib/logic/getValidators.js +24 -0
  14. package/lib/logic/getValidators.js.map +1 -0
  15. package/lib/logic/index.d.ts +1 -0
  16. package/lib/logic/index.d.ts.map +1 -1
  17. package/lib/logic/index.js +3 -1
  18. package/lib/logic/index.js.map +1 -1
  19. package/lib/network/index.d.ts +3 -2
  20. package/lib/network/index.d.ts.map +1 -1
  21. package/lib/network/index.js +3 -1
  22. package/lib/network/index.js.map +1 -1
  23. package/lib/network/sdk.d.ts +4 -1
  24. package/lib/network/sdk.d.ts.map +1 -1
  25. package/lib/network/sdk.js +54 -23
  26. package/lib/network/sdk.js.map +1 -1
  27. package/lib/{bridge/bridge.integration.test.d.ts → test/bridge.dataset.d.ts} +1 -1
  28. package/lib/test/bridge.dataset.d.ts.map +1 -0
  29. package/lib/{bridge/bridge.integration.test.js → test/bridge.dataset.js} +2 -2
  30. package/lib/test/bridge.dataset.js.map +1 -0
  31. package/lib-es/api/index.d.ts.map +1 -1
  32. package/lib-es/api/index.js +2 -1
  33. package/lib-es/api/index.js.map +1 -1
  34. package/lib-es/logic/estimateFees.d.ts +4 -1
  35. package/lib-es/logic/estimateFees.d.ts.map +1 -1
  36. package/lib-es/logic/estimateFees.js +2 -1
  37. package/lib-es/logic/estimateFees.js.map +1 -1
  38. package/lib-es/logic/getValidators.d.ts +3 -0
  39. package/lib-es/logic/getValidators.d.ts.map +1 -0
  40. package/lib-es/logic/getValidators.js +20 -0
  41. package/lib-es/logic/getValidators.js.map +1 -0
  42. package/lib-es/logic/index.d.ts +1 -0
  43. package/lib-es/logic/index.d.ts.map +1 -1
  44. package/lib-es/logic/index.js +1 -0
  45. package/lib-es/logic/index.js.map +1 -1
  46. package/lib-es/network/index.d.ts +3 -2
  47. package/lib-es/network/index.d.ts.map +1 -1
  48. package/lib-es/network/index.js +3 -2
  49. package/lib-es/network/index.js.map +1 -1
  50. package/lib-es/network/sdk.d.ts +4 -1
  51. package/lib-es/network/sdk.d.ts.map +1 -1
  52. package/lib-es/network/sdk.js +52 -22
  53. package/lib-es/network/sdk.js.map +1 -1
  54. package/lib-es/{bridge/bridge.integration.test.d.ts → test/bridge.dataset.d.ts} +1 -1
  55. package/lib-es/test/bridge.dataset.d.ts.map +1 -0
  56. package/lib-es/{bridge/bridge.integration.test.js → test/bridge.dataset.js} +2 -2
  57. package/lib-es/test/bridge.dataset.js.map +1 -0
  58. package/package.json +5 -9
  59. package/src/api/index.integration.test.ts +80 -7
  60. package/src/api/index.ts +2 -0
  61. package/src/logic/estimateFees.test.ts +22 -16
  62. package/src/logic/estimateFees.ts +6 -1
  63. package/src/logic/getValidators.test.ts +92 -0
  64. package/src/logic/getValidators.ts +23 -0
  65. package/src/logic/index.ts +1 -0
  66. package/src/network/index.ts +3 -0
  67. package/src/network/sdk.test.ts +134 -60
  68. package/src/network/sdk.ts +58 -23
  69. package/src/{bridge/bridge.integration.test.ts → test/bridge.dataset.ts} +1 -1
  70. package/lib/api/index.integration.test.d.ts +0 -2
  71. package/lib/api/index.integration.test.d.ts.map +0 -1
  72. package/lib/api/index.integration.test.js +0 -173
  73. package/lib/api/index.integration.test.js.map +0 -1
  74. package/lib/api/index.test.d.ts +0 -2
  75. package/lib/api/index.test.d.ts.map +0 -1
  76. package/lib/api/index.test.js +0 -173
  77. package/lib/api/index.test.js.map +0 -1
  78. package/lib/bridge/bridge.integration.test.d.ts.map +0 -1
  79. package/lib/bridge/bridge.integration.test.js.map +0 -1
  80. package/lib/bridge/broadcast.test.d.ts +0 -2
  81. package/lib/bridge/broadcast.test.d.ts.map +0 -1
  82. package/lib/bridge/broadcast.test.js +0 -48
  83. package/lib/bridge/broadcast.test.js.map +0 -1
  84. package/lib/bridge/buildOptimisticOperation.test.d.ts +0 -2
  85. package/lib/bridge/buildOptimisticOperation.test.d.ts.map +0 -1
  86. package/lib/bridge/buildOptimisticOperation.test.js +0 -52
  87. package/lib/bridge/buildOptimisticOperation.test.js.map +0 -1
  88. package/lib/bridge/buildTransaction.integration.test.d.ts +0 -2
  89. package/lib/bridge/buildTransaction.integration.test.d.ts.map +0 -1
  90. package/lib/bridge/buildTransaction.integration.test.js +0 -72
  91. package/lib/bridge/buildTransaction.integration.test.js.map +0 -1
  92. package/lib/bridge/buildTransaction.test.d.ts +0 -2
  93. package/lib/bridge/buildTransaction.test.d.ts.map +0 -1
  94. package/lib/bridge/buildTransaction.test.js +0 -231
  95. package/lib/bridge/buildTransaction.test.js.map +0 -1
  96. package/lib/bridge/estimateMaxSpendable.test.d.ts +0 -2
  97. package/lib/bridge/estimateMaxSpendable.test.d.ts.map +0 -1
  98. package/lib/bridge/estimateMaxSpendable.test.js +0 -52
  99. package/lib/bridge/estimateMaxSpendable.test.js.map +0 -1
  100. package/lib/bridge/formatters.test.d.ts +0 -2
  101. package/lib/bridge/formatters.test.d.ts.map +0 -1
  102. package/lib/bridge/formatters.test.js +0 -18
  103. package/lib/bridge/formatters.test.js.map +0 -1
  104. package/lib/bridge/getFeesForTransaction.test.d.ts +0 -2
  105. package/lib/bridge/getFeesForTransaction.test.d.ts.map +0 -1
  106. package/lib/bridge/getFeesForTransaction.test.js +0 -35
  107. package/lib/bridge/getFeesForTransaction.test.js.map +0 -1
  108. package/lib/bridge/getTransactionStatus.test.d.ts +0 -2
  109. package/lib/bridge/getTransactionStatus.test.d.ts.map +0 -1
  110. package/lib/bridge/getTransactionStatus.test.js +0 -69
  111. package/lib/bridge/getTransactionStatus.test.js.map +0 -1
  112. package/lib/bridge/index.test.d.ts +0 -2
  113. package/lib/bridge/index.test.d.ts.map +0 -1
  114. package/lib/bridge/index.test.js +0 -265
  115. package/lib/bridge/index.test.js.map +0 -1
  116. package/lib/bridge/preload.test.d.ts +0 -2
  117. package/lib/bridge/preload.test.d.ts.map +0 -1
  118. package/lib/bridge/preload.test.js +0 -52
  119. package/lib/bridge/preload.test.js.map +0 -1
  120. package/lib/bridge/prepareTransaction.test.d.ts +0 -2
  121. package/lib/bridge/prepareTransaction.test.d.ts.map +0 -1
  122. package/lib/bridge/prepareTransaction.test.js +0 -97
  123. package/lib/bridge/prepareTransaction.test.js.map +0 -1
  124. package/lib/bridge/serialization.test.d.ts +0 -2
  125. package/lib/bridge/serialization.test.d.ts.map +0 -1
  126. package/lib/bridge/serialization.test.js +0 -131
  127. package/lib/bridge/serialization.test.js.map +0 -1
  128. package/lib/bridge/signOperation.integration.test.d.ts +0 -2
  129. package/lib/bridge/signOperation.integration.test.d.ts.map +0 -1
  130. package/lib/bridge/signOperation.integration.test.js +0 -80
  131. package/lib/bridge/signOperation.integration.test.js.map +0 -1
  132. package/lib/bridge/signOperation.test.d.ts +0 -2
  133. package/lib/bridge/signOperation.test.d.ts.map +0 -1
  134. package/lib/bridge/signOperation.test.js +0 -445
  135. package/lib/bridge/signOperation.test.js.map +0 -1
  136. package/lib/bridge/synchronisation.test.d.ts +0 -2
  137. package/lib/bridge/synchronisation.test.d.ts.map +0 -1
  138. package/lib/bridge/synchronisation.test.js +0 -505
  139. package/lib/bridge/synchronisation.test.js.map +0 -1
  140. package/lib/bridge/transaction.test.d.ts +0 -2
  141. package/lib/bridge/transaction.test.d.ts.map +0 -1
  142. package/lib/bridge/transaction.test.js +0 -68
  143. package/lib/bridge/transaction.test.js.map +0 -1
  144. package/lib/logic/broadcast.test.d.ts +0 -2
  145. package/lib/logic/broadcast.test.d.ts.map +0 -1
  146. package/lib/logic/broadcast.test.js +0 -62
  147. package/lib/logic/broadcast.test.js.map +0 -1
  148. package/lib/logic/combine.test.d.ts +0 -2
  149. package/lib/logic/combine.test.d.ts.map +0 -1
  150. package/lib/logic/combine.test.js +0 -37
  151. package/lib/logic/combine.test.js.map +0 -1
  152. package/lib/logic/craftTransaction.integration.test.d.ts +0 -2
  153. package/lib/logic/craftTransaction.integration.test.d.ts.map +0 -1
  154. package/lib/logic/craftTransaction.integration.test.js +0 -98
  155. package/lib/logic/craftTransaction.integration.test.js.map +0 -1
  156. package/lib/logic/craftTransaction.test.d.ts +0 -2
  157. package/lib/logic/craftTransaction.test.d.ts.map +0 -1
  158. package/lib/logic/craftTransaction.test.js +0 -127
  159. package/lib/logic/craftTransaction.test.js.map +0 -1
  160. package/lib/logic/estimateFees.integration.test.d.ts +0 -2
  161. package/lib/logic/estimateFees.integration.test.d.ts.map +0 -1
  162. package/lib/logic/estimateFees.integration.test.js +0 -82
  163. package/lib/logic/estimateFees.integration.test.js.map +0 -1
  164. package/lib/logic/estimateFees.test.d.ts +0 -2
  165. package/lib/logic/estimateFees.test.d.ts.map +0 -1
  166. package/lib/logic/estimateFees.test.js +0 -70
  167. package/lib/logic/estimateFees.test.js.map +0 -1
  168. package/lib/logic/getBalance.integration.test.d.ts +0 -2
  169. package/lib/logic/getBalance.integration.test.d.ts.map +0 -1
  170. package/lib/logic/getBalance.integration.test.js +0 -56
  171. package/lib/logic/getBalance.integration.test.js.map +0 -1
  172. package/lib/logic/getBalance.test.d.ts +0 -2
  173. package/lib/logic/getBalance.test.d.ts.map +0 -1
  174. package/lib/logic/getBalance.test.js +0 -64
  175. package/lib/logic/getBalance.test.js.map +0 -1
  176. package/lib/logic/lastBlock.test.d.ts +0 -2
  177. package/lib/logic/lastBlock.test.d.ts.map +0 -1
  178. package/lib/logic/lastBlock.test.js +0 -27
  179. package/lib/logic/lastBlock.test.js.map +0 -1
  180. package/lib/logic/listOperations.test.d.ts +0 -2
  181. package/lib/logic/listOperations.test.d.ts.map +0 -1
  182. package/lib/logic/listOperations.test.js +0 -79
  183. package/lib/logic/listOperations.test.js.map +0 -1
  184. package/lib/network/sdk.integration.test.d.ts +0 -2
  185. package/lib/network/sdk.integration.test.d.ts.map +0 -1
  186. package/lib/network/sdk.integration.test.js +0 -215
  187. package/lib/network/sdk.integration.test.js.map +0 -1
  188. package/lib/network/sdk.test.d.ts +0 -2
  189. package/lib/network/sdk.test.d.ts.map +0 -1
  190. package/lib/network/sdk.test.js +0 -1784
  191. package/lib/network/sdk.test.js.map +0 -1
  192. package/lib/signer/getAddress.test.d.ts +0 -2
  193. package/lib/signer/getAddress.test.d.ts.map +0 -1
  194. package/lib/signer/getAddress.test.js +0 -106
  195. package/lib/signer/getAddress.test.js.map +0 -1
  196. package/lib/test/config.test.d.ts +0 -2
  197. package/lib/test/config.test.d.ts.map +0 -1
  198. package/lib/test/config.test.js +0 -44
  199. package/lib/test/config.test.js.map +0 -1
  200. package/lib-es/api/index.integration.test.d.ts +0 -2
  201. package/lib-es/api/index.integration.test.d.ts.map +0 -1
  202. package/lib-es/api/index.integration.test.js +0 -171
  203. package/lib-es/api/index.integration.test.js.map +0 -1
  204. package/lib-es/api/index.test.d.ts +0 -2
  205. package/lib-es/api/index.test.d.ts.map +0 -1
  206. package/lib-es/api/index.test.js +0 -148
  207. package/lib-es/api/index.test.js.map +0 -1
  208. package/lib-es/bridge/bridge.integration.test.d.ts.map +0 -1
  209. package/lib-es/bridge/bridge.integration.test.js.map +0 -1
  210. package/lib-es/bridge/broadcast.test.d.ts +0 -2
  211. package/lib-es/bridge/broadcast.test.d.ts.map +0 -1
  212. package/lib-es/bridge/broadcast.test.js +0 -46
  213. package/lib-es/bridge/broadcast.test.js.map +0 -1
  214. package/lib-es/bridge/buildOptimisticOperation.test.d.ts +0 -2
  215. package/lib-es/bridge/buildOptimisticOperation.test.d.ts.map +0 -1
  216. package/lib-es/bridge/buildOptimisticOperation.test.js +0 -47
  217. package/lib-es/bridge/buildOptimisticOperation.test.js.map +0 -1
  218. package/lib-es/bridge/buildTransaction.integration.test.d.ts +0 -2
  219. package/lib-es/bridge/buildTransaction.integration.test.d.ts.map +0 -1
  220. package/lib-es/bridge/buildTransaction.integration.test.js +0 -67
  221. package/lib-es/bridge/buildTransaction.integration.test.js.map +0 -1
  222. package/lib-es/bridge/buildTransaction.test.d.ts +0 -2
  223. package/lib-es/bridge/buildTransaction.test.d.ts.map +0 -1
  224. package/lib-es/bridge/buildTransaction.test.js +0 -229
  225. package/lib-es/bridge/buildTransaction.test.js.map +0 -1
  226. package/lib-es/bridge/estimateMaxSpendable.test.d.ts +0 -2
  227. package/lib-es/bridge/estimateMaxSpendable.test.d.ts.map +0 -1
  228. package/lib-es/bridge/estimateMaxSpendable.test.js +0 -50
  229. package/lib-es/bridge/estimateMaxSpendable.test.js.map +0 -1
  230. package/lib-es/bridge/formatters.test.d.ts +0 -2
  231. package/lib-es/bridge/formatters.test.d.ts.map +0 -1
  232. package/lib-es/bridge/formatters.test.js +0 -16
  233. package/lib-es/bridge/formatters.test.js.map +0 -1
  234. package/lib-es/bridge/getFeesForTransaction.test.d.ts +0 -2
  235. package/lib-es/bridge/getFeesForTransaction.test.d.ts.map +0 -1
  236. package/lib-es/bridge/getFeesForTransaction.test.js +0 -30
  237. package/lib-es/bridge/getFeesForTransaction.test.js.map +0 -1
  238. package/lib-es/bridge/getTransactionStatus.test.d.ts +0 -2
  239. package/lib-es/bridge/getTransactionStatus.test.d.ts.map +0 -1
  240. package/lib-es/bridge/getTransactionStatus.test.js +0 -64
  241. package/lib-es/bridge/getTransactionStatus.test.js.map +0 -1
  242. package/lib-es/bridge/index.test.d.ts +0 -2
  243. package/lib-es/bridge/index.test.d.ts.map +0 -1
  244. package/lib-es/bridge/index.test.js +0 -260
  245. package/lib-es/bridge/index.test.js.map +0 -1
  246. package/lib-es/bridge/preload.test.d.ts +0 -2
  247. package/lib-es/bridge/preload.test.d.ts.map +0 -1
  248. package/lib-es/bridge/preload.test.js +0 -50
  249. package/lib-es/bridge/preload.test.js.map +0 -1
  250. package/lib-es/bridge/prepareTransaction.test.d.ts +0 -2
  251. package/lib-es/bridge/prepareTransaction.test.d.ts.map +0 -1
  252. package/lib-es/bridge/prepareTransaction.test.js +0 -92
  253. package/lib-es/bridge/prepareTransaction.test.js.map +0 -1
  254. package/lib-es/bridge/serialization.test.d.ts +0 -2
  255. package/lib-es/bridge/serialization.test.d.ts.map +0 -1
  256. package/lib-es/bridge/serialization.test.js +0 -126
  257. package/lib-es/bridge/serialization.test.js.map +0 -1
  258. package/lib-es/bridge/signOperation.integration.test.d.ts +0 -2
  259. package/lib-es/bridge/signOperation.integration.test.d.ts.map +0 -1
  260. package/lib-es/bridge/signOperation.integration.test.js +0 -75
  261. package/lib-es/bridge/signOperation.integration.test.js.map +0 -1
  262. package/lib-es/bridge/signOperation.test.d.ts +0 -2
  263. package/lib-es/bridge/signOperation.test.d.ts.map +0 -1
  264. package/lib-es/bridge/signOperation.test.js +0 -440
  265. package/lib-es/bridge/signOperation.test.js.map +0 -1
  266. package/lib-es/bridge/synchronisation.test.d.ts +0 -2
  267. package/lib-es/bridge/synchronisation.test.d.ts.map +0 -1
  268. package/lib-es/bridge/synchronisation.test.js +0 -477
  269. package/lib-es/bridge/synchronisation.test.js.map +0 -1
  270. package/lib-es/bridge/transaction.test.d.ts +0 -2
  271. package/lib-es/bridge/transaction.test.d.ts.map +0 -1
  272. package/lib-es/bridge/transaction.test.js +0 -66
  273. package/lib-es/bridge/transaction.test.js.map +0 -1
  274. package/lib-es/logic/broadcast.test.d.ts +0 -2
  275. package/lib-es/logic/broadcast.test.d.ts.map +0 -1
  276. package/lib-es/logic/broadcast.test.js +0 -57
  277. package/lib-es/logic/broadcast.test.js.map +0 -1
  278. package/lib-es/logic/combine.test.d.ts +0 -2
  279. package/lib-es/logic/combine.test.d.ts.map +0 -1
  280. package/lib-es/logic/combine.test.js +0 -35
  281. package/lib-es/logic/combine.test.js.map +0 -1
  282. package/lib-es/logic/craftTransaction.integration.test.d.ts +0 -2
  283. package/lib-es/logic/craftTransaction.integration.test.d.ts.map +0 -1
  284. package/lib-es/logic/craftTransaction.integration.test.js +0 -93
  285. package/lib-es/logic/craftTransaction.integration.test.js.map +0 -1
  286. package/lib-es/logic/craftTransaction.test.d.ts +0 -2
  287. package/lib-es/logic/craftTransaction.test.d.ts.map +0 -1
  288. package/lib-es/logic/craftTransaction.test.js +0 -122
  289. package/lib-es/logic/craftTransaction.test.js.map +0 -1
  290. package/lib-es/logic/estimateFees.integration.test.d.ts +0 -2
  291. package/lib-es/logic/estimateFees.integration.test.d.ts.map +0 -1
  292. package/lib-es/logic/estimateFees.integration.test.js +0 -77
  293. package/lib-es/logic/estimateFees.integration.test.js.map +0 -1
  294. package/lib-es/logic/estimateFees.test.d.ts +0 -2
  295. package/lib-es/logic/estimateFees.test.d.ts.map +0 -1
  296. package/lib-es/logic/estimateFees.test.js +0 -65
  297. package/lib-es/logic/estimateFees.test.js.map +0 -1
  298. package/lib-es/logic/getBalance.integration.test.d.ts +0 -2
  299. package/lib-es/logic/getBalance.integration.test.d.ts.map +0 -1
  300. package/lib-es/logic/getBalance.integration.test.js +0 -51
  301. package/lib-es/logic/getBalance.integration.test.js.map +0 -1
  302. package/lib-es/logic/getBalance.test.d.ts +0 -2
  303. package/lib-es/logic/getBalance.test.d.ts.map +0 -1
  304. package/lib-es/logic/getBalance.test.js +0 -62
  305. package/lib-es/logic/getBalance.test.js.map +0 -1
  306. package/lib-es/logic/lastBlock.test.d.ts +0 -2
  307. package/lib-es/logic/lastBlock.test.d.ts.map +0 -1
  308. package/lib-es/logic/lastBlock.test.js +0 -25
  309. package/lib-es/logic/lastBlock.test.js.map +0 -1
  310. package/lib-es/logic/listOperations.test.d.ts +0 -2
  311. package/lib-es/logic/listOperations.test.d.ts.map +0 -1
  312. package/lib-es/logic/listOperations.test.js +0 -77
  313. package/lib-es/logic/listOperations.test.js.map +0 -1
  314. package/lib-es/network/sdk.integration.test.d.ts +0 -2
  315. package/lib-es/network/sdk.integration.test.d.ts.map +0 -1
  316. package/lib-es/network/sdk.integration.test.js +0 -210
  317. package/lib-es/network/sdk.integration.test.js.map +0 -1
  318. package/lib-es/network/sdk.test.d.ts +0 -2
  319. package/lib-es/network/sdk.test.d.ts.map +0 -1
  320. package/lib-es/network/sdk.test.js +0 -1756
  321. package/lib-es/network/sdk.test.js.map +0 -1
  322. package/lib-es/signer/getAddress.test.d.ts +0 -2
  323. package/lib-es/signer/getAddress.test.d.ts.map +0 -1
  324. package/lib-es/signer/getAddress.test.js +0 -101
  325. package/lib-es/signer/getAddress.test.js.map +0 -1
  326. package/lib-es/test/config.test.d.ts +0 -2
  327. package/lib-es/test/config.test.d.ts.map +0 -1
  328. package/lib-es/test/config.test.js +0 -39
  329. package/lib-es/test/config.test.js.map +0 -1
@@ -1,1756 +0,0 @@
1
- import * as sdk from "./sdk";
2
- import coinConfig from "../config";
3
- import { BigNumber } from "bignumber.js";
4
- import { SuiClient } from "@mysten/sui/client";
5
- import assert from "assert";
6
- // Mock SUI client for tests
7
- jest.mock("@mysten/sui/client", () => {
8
- return {
9
- ...jest.requireActual("@mysten/sui/client"),
10
- SuiClient: jest.fn().mockImplementation(() => ({
11
- getAllBalances: jest.fn().mockResolvedValue([
12
- { coinType: "0x2::sui::SUI", totalBalance: "1000000000" },
13
- { coinType: "0x123::test::TOKEN", totalBalance: "500000" },
14
- ]),
15
- queryTransactionBlocks: jest.fn().mockResolvedValue({
16
- data: [],
17
- hasNextPage: false,
18
- }),
19
- dryRunTransactionBlock: jest.fn().mockResolvedValue({
20
- effects: {
21
- gasUsed: {
22
- computationCost: "1000000",
23
- storageCost: "500000",
24
- storageRebate: "450000",
25
- },
26
- },
27
- input: {
28
- gasData: {
29
- budget: "4000000",
30
- },
31
- },
32
- }),
33
- getCoins: jest.fn().mockResolvedValue({
34
- data: [{ coinObjectId: "0xtest_coin_object_id" }],
35
- }),
36
- executeTransactionBlock: jest.fn().mockResolvedValue({
37
- digest: "transaction_digest_123",
38
- effects: {
39
- status: { status: "success" },
40
- },
41
- }),
42
- getReferenceGasPrice: jest.fn().mockResolvedValue("1000"),
43
- getTransactionBlock: jest.fn().mockResolvedValue({
44
- transaction: {
45
- data: {
46
- transaction: {
47
- kind: "ProgrammableTransaction",
48
- inputs: [],
49
- transactions: [],
50
- },
51
- },
52
- },
53
- effects: {
54
- status: { status: "success" },
55
- },
56
- }),
57
- })),
58
- getFullnodeUrl: jest.fn().mockReturnValue("https://mockapi.sui.io"),
59
- };
60
- });
61
- // Mock the Transaction class
62
- jest.mock("@mysten/sui/transactions", () => {
63
- const mockTxb = {
64
- // This will be the built transaction block
65
- transactionBlock: new Uint8Array(),
66
- };
67
- return {
68
- ...jest.requireActual("@mysten/sui/transactions"),
69
- Transaction: jest.fn().mockImplementation(() => {
70
- return {
71
- gas: "0xmock_gas_object_id",
72
- setSender: jest.fn(),
73
- splitCoins: jest.fn().mockReturnValue(["0xmock_coin"]),
74
- transferObjects: jest.fn(),
75
- moveCall: jest.fn(),
76
- object: jest.fn(),
77
- pure: {
78
- address: jest.fn(),
79
- u64: jest.fn(),
80
- },
81
- build: jest.fn().mockResolvedValue(mockTxb),
82
- setGasBudgetIfNotSet: jest.fn(),
83
- };
84
- }),
85
- };
86
- });
87
- const mockTransaction = {
88
- digest: "DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt",
89
- transaction: {
90
- data: {
91
- messageVersion: "v1",
92
- transaction: {
93
- kind: "ProgrammableTransaction",
94
- inputs: [
95
- {
96
- type: "pure",
97
- valueType: "address",
98
- value: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
99
- },
100
- ],
101
- transactions: [
102
- {
103
- TransferObjects: [["GasCoin"], { Input: 0 }],
104
- },
105
- ],
106
- },
107
- sender: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
108
- gasData: {
109
- payment: [
110
- {
111
- objectId: "0x9d49c70b621b618c7918468a7ac286e71cffe6e30c4e4175a4385516b121cb0e",
112
- version: "57",
113
- digest: "2rPEonJQQUXmAmAegn3fVqBjpKrC5NadAZBetb5wJQm6",
114
- },
115
- ],
116
- owner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
117
- price: "1000",
118
- budget: "2988000",
119
- },
120
- },
121
- txSignatures: [
122
- "AJKFd5y+1y/ggTAKTZlrrQlvSWXoYCSU7ksxyBG6BI9FDjN/R8db5PNbw19Bs+Lp4VE0cu9BBzAc/gYDFwgYrQVgR+QnZSFg3qWm+IjLX2dEep/wlLje2lziXO+HmZApcQ==",
123
- ],
124
- },
125
- effects: {
126
- messageVersion: "v1",
127
- status: { status: "success" },
128
- executedEpoch: "18",
129
- gasUsed: {
130
- computationCost: "1000000",
131
- storageCost: "988000",
132
- storageRebate: "978120",
133
- nonRefundableStorageFee: "9880",
134
- },
135
- modifiedAtVersions: [
136
- {
137
- objectId: "0x9d49c70b621b618c7918468a7ac286e71cffe6e30c4e4175a4385516b121cb0e",
138
- sequenceNumber: "57",
139
- },
140
- ],
141
- transactionDigest: "DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt",
142
- mutated: [
143
- {
144
- owner: {
145
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
146
- },
147
- reference: {
148
- objectId: "0x9d49c70b621b618c7918468a7ac286e71cffe6e30c4e4175a4385516b121cb0e",
149
- version: "58",
150
- digest: "82pvkMbymnBFQjhuDDaaW88BeATbNgWWcWH67DcLaPBi",
151
- },
152
- },
153
- ],
154
- gasObject: {
155
- owner: { AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0" },
156
- reference: {
157
- objectId: "0x9d49c70b621b618c7918468a7ac286e71cffe6e30c4e4175a4385516b121cb0e",
158
- version: "58",
159
- digest: "82pvkMbymnBFQjhuDDaaW88BeATbNgWWcWH67DcLaPBi",
160
- },
161
- },
162
- dependencies: ["D8tHbu9JwGuoaH67PFXCoswqDUy2M4S6KVLWhCodt1a7"],
163
- },
164
- balanceChanges: [
165
- {
166
- owner: { AddressOwner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24" },
167
- coinType: "0x2::sui::SUI",
168
- amount: "-10000000000",
169
- },
170
- {
171
- owner: { AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0" },
172
- coinType: "0x2::sui::SUI",
173
- amount: "9998990120",
174
- },
175
- {
176
- owner: { AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0" },
177
- coinType: "0x123::test::TOKEN",
178
- amount: "500000",
179
- },
180
- ],
181
- timestampMs: "1742294454878",
182
- checkpoint: "313024",
183
- };
184
- // Create a mock staking transaction
185
- // amount must be a negative number
186
- function mockStakingTx(address, amount) {
187
- assert(new BigNumber(amount).lte(0), "amount must be a negative number");
188
- return {
189
- digest: "delegate_tx_digest_123",
190
- transaction: {
191
- data: {
192
- sender: address,
193
- transaction: {
194
- kind: "ProgrammableTransaction",
195
- inputs: [],
196
- transactions: [
197
- {
198
- MoveCall: {
199
- function: "request_add_stake",
200
- },
201
- },
202
- ],
203
- },
204
- },
205
- },
206
- effects: {
207
- status: { status: "success" },
208
- gasUsed: {
209
- computationCost: "1000000",
210
- storageCost: "500000",
211
- storageRebate: "450000",
212
- },
213
- },
214
- balanceChanges: [
215
- {
216
- owner: { AddressOwner: address },
217
- coinType: "0x2::sui::SUI",
218
- amount: amount.startsWith("-") ? amount : `-${amount}`,
219
- },
220
- ],
221
- timestampMs: "1742294454878",
222
- checkpoint: "313024",
223
- };
224
- }
225
- // amount must be a positive number
226
- function mockUnstakingTx(address, amount) {
227
- assert(new BigNumber(amount).gte(0), "amount must be a positive number");
228
- return {
229
- digest: "undelegate_tx_digest_456",
230
- transaction: {
231
- data: {
232
- sender: address,
233
- transaction: {
234
- kind: "ProgrammableTransaction",
235
- inputs: [],
236
- transactions: [
237
- {
238
- MoveCall: {
239
- function: "request_withdraw_stake",
240
- },
241
- },
242
- ],
243
- },
244
- },
245
- },
246
- effects: {
247
- status: { status: "success" },
248
- gasUsed: {
249
- computationCost: "1000000",
250
- storageCost: "500000",
251
- storageRebate: "450000",
252
- },
253
- },
254
- balanceChanges: [
255
- {
256
- owner: { AddressOwner: address },
257
- coinType: "0x2::sui::SUI",
258
- amount: amount,
259
- },
260
- ],
261
- timestampMs: "1742294454878",
262
- checkpoint: "313024",
263
- };
264
- }
265
- const mockApi = new SuiClient({ url: "mock" });
266
- // Add getTransactionBlock method to mockApi
267
- mockApi.getTransactionBlock = jest.fn();
268
- // Helper function to generate mock coins from an array of balances
269
- const createMockCoins = (balances) => {
270
- return balances.map((balance, index) => ({
271
- coinObjectId: `0xcoin${index + 1}`,
272
- balance,
273
- digest: `0xdigest${index + 1}`,
274
- version: "1",
275
- }));
276
- };
277
- beforeAll(() => {
278
- coinConfig.setCoinConfig(() => ({
279
- status: {
280
- type: "active",
281
- },
282
- node: {
283
- url: "https://mockapi.sui.io",
284
- },
285
- }));
286
- });
287
- beforeEach(() => {
288
- mockApi.queryTransactionBlocks.mockReset();
289
- });
290
- describe("SDK Functions", () => {
291
- test("getAccountBalances should return array of account balances", async () => {
292
- // Patch getAllBalancesCached to return a valid array for this test
293
- jest.spyOn(sdk, "getAllBalancesCached").mockResolvedValue([
294
- {
295
- coinType: "0x2::sui::SUI",
296
- totalBalance: "1000000000",
297
- coinObjectCount: 1,
298
- lockedBalance: {},
299
- },
300
- {
301
- coinType: "0x123::test::TOKEN",
302
- totalBalance: "500000",
303
- coinObjectCount: 1,
304
- lockedBalance: {},
305
- },
306
- ]);
307
- const address = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
308
- const balances = await sdk.getAccountBalances(address);
309
- expect(Array.isArray(balances)).toBe(true);
310
- expect(balances.length).toBeGreaterThan(0);
311
- // Check structure of the first balance
312
- const firstBalance = balances[0];
313
- expect(firstBalance).toHaveProperty("coinType");
314
- expect(firstBalance).toHaveProperty("blockHeight");
315
- expect(firstBalance).toHaveProperty("balance");
316
- expect(firstBalance.balance).toBeInstanceOf(BigNumber);
317
- // Should include SUI and token balances
318
- const coinTypes = balances.map(b => b.coinType);
319
- expect(coinTypes).toContain(sdk.DEFAULT_COIN_TYPE);
320
- });
321
- test("getOperationType should return IN for incoming tx", () => {
322
- const address = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
323
- expect(sdk.getOperationType(address, mockTransaction)).toBe("IN");
324
- });
325
- test("getOperationType should return OUT for outgoing tx", () => {
326
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
327
- expect(sdk.getOperationType(address, mockTransaction)).toBe("OUT");
328
- });
329
- test("getOperationSenders should return sender address", () => {
330
- expect(sdk.getOperationSenders(mockTransaction.transaction?.data)).toEqual(["0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24"]);
331
- });
332
- test("getOperationRecipients should return recipient addresses", () => {
333
- expect(sdk.getOperationRecipients(mockTransaction.transaction?.data)).toEqual(["0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0"]);
334
- });
335
- test("getOperationFee should calculate fee correctly", () => {
336
- expect(sdk.getOperationFee(mockTransaction)).toEqual(new BigNumber(1009880));
337
- });
338
- test("getOperationDate should return correct date", () => {
339
- const date = sdk.getOperationDate(mockTransaction);
340
- expect(date).toBeDefined();
341
- expect(date).toBeInstanceOf(Date);
342
- });
343
- test("getOperationCoinType should extract token coin type", () => {
344
- // For a token transaction
345
- const tokenTx = {
346
- ...mockTransaction,
347
- balanceChanges: [
348
- {
349
- owner: {
350
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
351
- },
352
- coinType: "0x123::test::TOKEN",
353
- amount: "500000",
354
- },
355
- {
356
- owner: {
357
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
358
- },
359
- coinType: sdk.DEFAULT_COIN_TYPE,
360
- amount: "-1009880",
361
- },
362
- ],
363
- };
364
- expect(sdk.getOperationCoinType(tokenTx)).toBe("0x123::test::TOKEN");
365
- // For a SUI-only transaction
366
- const suiTx = {
367
- ...mockTransaction,
368
- balanceChanges: [
369
- {
370
- owner: {
371
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
372
- },
373
- coinType: sdk.DEFAULT_COIN_TYPE,
374
- amount: "9998990120",
375
- },
376
- ],
377
- };
378
- expect(sdk.getOperationCoinType(suiTx)).toBe(sdk.DEFAULT_COIN_TYPE);
379
- });
380
- test("transactionToOperation should map transaction to operation", () => {
381
- const accountId = "mockAccountId";
382
- const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
383
- // Create a SUI-only transaction for this test to avoid token detection
384
- const suiTx = {
385
- ...mockTransaction,
386
- balanceChanges: [
387
- {
388
- owner: {
389
- AddressOwner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
390
- },
391
- coinType: sdk.DEFAULT_COIN_TYPE,
392
- amount: "-10000000000",
393
- },
394
- {
395
- owner: {
396
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
397
- },
398
- coinType: sdk.DEFAULT_COIN_TYPE,
399
- amount: "9998990120",
400
- },
401
- ],
402
- };
403
- // Instead of mocking, just directly verify the amount
404
- const operation = sdk.transactionToOperation(accountId, address, suiTx);
405
- expect(operation).toHaveProperty("id");
406
- expect(operation).toHaveProperty("accountId", accountId);
407
- expect(operation).toHaveProperty("extra");
408
- expect(operation.extra.coinType).toBe(sdk.DEFAULT_COIN_TYPE);
409
- // Directly calculate expected amount for SUI coin type
410
- const expectedAmount = sdk.getOperationAmount(address, suiTx, sdk.DEFAULT_COIN_TYPE);
411
- expect(expectedAmount.toString()).toBe("9998990120");
412
- });
413
- test("transactionToOperation should map token transaction to operation", () => {
414
- const accountId = "mockAccountId";
415
- const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
416
- // Create a token transaction
417
- const tokenTx = {
418
- ...mockTransaction,
419
- balanceChanges: [
420
- {
421
- owner: {
422
- AddressOwner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
423
- },
424
- coinType: "0x123::test::TOKEN",
425
- amount: "-500000",
426
- },
427
- {
428
- owner: {
429
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
430
- },
431
- coinType: "0x123::test::TOKEN",
432
- amount: "500000",
433
- },
434
- {
435
- owner: {
436
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
437
- },
438
- coinType: sdk.DEFAULT_COIN_TYPE,
439
- amount: "-1000000",
440
- },
441
- ],
442
- };
443
- const operation = sdk.transactionToOperation(accountId, address, tokenTx);
444
- expect(operation).toHaveProperty("id");
445
- expect(operation).toHaveProperty("accountId", accountId);
446
- expect(operation).toHaveProperty("extra");
447
- expect(operation.extra.coinType).toBe("0x123::test::TOKEN");
448
- expect(operation.value).toEqual(new BigNumber("500000"));
449
- });
450
- test("transactionToOp should map token transaction to operation", () => {
451
- const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
452
- // Create a token transaction
453
- const tokenTx = {
454
- ...mockTransaction,
455
- balanceChanges: [
456
- {
457
- owner: {
458
- AddressOwner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
459
- },
460
- coinType: "0x123::test::TOKEN",
461
- amount: "-500000",
462
- },
463
- {
464
- owner: {
465
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
466
- },
467
- coinType: "0x123::test::TOKEN",
468
- amount: "500000",
469
- },
470
- {
471
- owner: {
472
- AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
473
- },
474
- coinType: sdk.DEFAULT_COIN_TYPE,
475
- amount: "-1000000",
476
- },
477
- ],
478
- };
479
- const operation = sdk.alpacaTransactionToOp(address, tokenTx);
480
- expect(operation.id).toEqual("DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt");
481
- expect(operation.type).toEqual("IN");
482
- expect(operation.senders).toEqual([
483
- "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
484
- ]);
485
- expect(operation.recipients).toEqual([
486
- "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
487
- ]);
488
- expect(operation.value).toEqual(500000n);
489
- expect(operation.asset).toEqual({ type: "token", assetReference: "0x123::test::TOKEN" });
490
- expect(operation.memo).toBeUndefined();
491
- expect(operation.details).toBeUndefined();
492
- expect(operation.tx.block.hash).toBeUndefined();
493
- expect(operation.tx).toMatchObject({
494
- hash: "DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt",
495
- block: {},
496
- fees: 1009880n,
497
- date: new Date("2025-03-18T10:40:54.878Z"),
498
- });
499
- });
500
- test("getOperations should fetch operations", async () => {
501
- const accountId = "mockAccountId";
502
- const addr = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
503
- const operations = await sdk.getOperations(accountId, addr);
504
- expect(Array.isArray(operations)).toBe(true);
505
- });
506
- test("paymentInfo should return gas budget and fees", async () => {
507
- const sender = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
508
- const fakeTransaction = {
509
- mode: "send",
510
- coinType: sdk.DEFAULT_COIN_TYPE,
511
- family: "sui",
512
- amount: new BigNumber(100),
513
- recipient: "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164",
514
- errors: {},
515
- };
516
- const info = await sdk.paymentInfo(sender, fakeTransaction);
517
- expect(info).toHaveProperty("gasBudget");
518
- expect(info).toHaveProperty("totalGasUsed");
519
- expect(info).toHaveProperty("fees");
520
- });
521
- test("createTransaction should build a transaction", async () => {
522
- const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
523
- const transaction = {
524
- mode: "send",
525
- coinType: sdk.DEFAULT_COIN_TYPE,
526
- amount: new BigNumber(100),
527
- recipient: "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164",
528
- };
529
- const tx = await sdk.createTransaction(address, transaction);
530
- expect(tx).toBeDefined();
531
- });
532
- test("executeTransactionBlock should execute a transaction", async () => {
533
- const result = await sdk.executeTransactionBlock({
534
- transactionBlock: new Uint8Array(),
535
- signature: "mockSignature",
536
- options: { showEffects: true },
537
- });
538
- expect(result).toHaveProperty("digest", "transaction_digest_123");
539
- expect(result?.effects).toBeDefined();
540
- if (result?.effects) {
541
- expect(result.effects).toHaveProperty("status");
542
- expect(result.effects.status).toHaveProperty("status", "success");
543
- }
544
- });
545
- });
546
- describe("Staking Operations", () => {
547
- describe("Operation Type Detection", () => {
548
- test("getOperationType should return DELEGATE for staking transaction", () => {
549
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
550
- expect(sdk.getOperationType(address, mockStakingTx(address, "-1000000000"))).toBe("DELEGATE");
551
- });
552
- test("getOperationType should return UNDELEGATE for unstaking transaction", () => {
553
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
554
- expect(sdk.getOperationType(address, mockUnstakingTx(address, "1000000000"))).toBe("UNDELEGATE");
555
- });
556
- });
557
- describe("Operation Amount Calculation", () => {
558
- const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
559
- function bridgeOperationAmount(mock, coinType = sdk.DEFAULT_COIN_TYPE) {
560
- return sdk.getOperationAmount(address, mock, coinType);
561
- }
562
- test("getOperationAmount should calculate staking amount", () => expect(bridgeOperationAmount(mockStakingTx(address, "-1000000000"))).toEqual(new BigNumber("1000000000")));
563
- test("getOperationAmount should calculate unstaking amount of 1000", () => expect(bridgeOperationAmount(mockUnstakingTx(address, "1000"))).toEqual(new BigNumber("-1000")));
564
- test("getOperationAmount should calculate unstaking amount of 0", () => expect(bridgeOperationAmount(mockUnstakingTx(address, "0"))).toEqual(new BigNumber("0")));
565
- test("getOperationAmount should calculate amount correctly for SUI", () => expect(bridgeOperationAmount(mockTransaction)).toEqual(new BigNumber("9998990120")));
566
- test("getOperationAmount should calculate amount correctly for tokens", () => expect(bridgeOperationAmount(mockTransaction, "0x123::test::TOKEN")).toEqual(new BigNumber("500000")));
567
- function alpacaOperationAmount(mock, coinType = sdk.DEFAULT_COIN_TYPE) {
568
- return sdk.alpacaGetOperationAmount(address, mock, coinType);
569
- }
570
- test("alpaca getOperationAmount should calculate staking amount", () => expect(alpacaOperationAmount(mockStakingTx(address, "-1000000000"))).toEqual(new BigNumber("1000000000")));
571
- test("alpaca getOperationAmount should calculate unstaking amount of 1000", () => expect(alpacaOperationAmount(mockUnstakingTx(address, "1000"))).toEqual(new BigNumber("1000")));
572
- test("alpaca getOperationAmount should calculate unstaking amount of 0", () => expect(alpacaOperationAmount(mockUnstakingTx(address, "0"))).toEqual(new BigNumber("0")));
573
- test("alpaca getOperationAmount should calculate amount correctly for SUI", () => expect(alpacaOperationAmount(mockTransaction)).toEqual(new BigNumber("9998990120")));
574
- test("alpaca getOperationAmount should calculate amount correctly for tokens", () => expect(alpacaOperationAmount(mockTransaction, "0x123::test::TOKEN")).toEqual(new BigNumber("500000")));
575
- });
576
- describe("Operation Recipients", () => {
577
- test("getOperationRecipients should return empty array for staking transaction", () => {
578
- const recipients = sdk.getOperationRecipients(mockStakingTx("0xdeadbeef", "-1000000000").transaction?.data);
579
- expect(recipients).toEqual([]);
580
- });
581
- test("getOperationRecipients should return empty array for unstaking transaction", () => {
582
- const recipients = sdk.getOperationRecipients(mockUnstakingTx("0xdeadbeef", "1000000000").transaction?.data);
583
- expect(recipients).toEqual([]);
584
- });
585
- });
586
- describe("Transaction Creation", () => {
587
- test("createTransaction should build delegate transaction", async () => {
588
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
589
- const transaction = {
590
- mode: "delegate",
591
- coinType: sdk.DEFAULT_COIN_TYPE,
592
- amount: new BigNumber(1000000000), // 1 SUI
593
- recipient: "0xvalidator_address_123",
594
- };
595
- const tx = await sdk.createTransaction(address, transaction);
596
- expect(tx).toBeDefined();
597
- });
598
- test("createTransaction should build undelegate transaction with specific amount", async () => {
599
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
600
- const transaction = {
601
- mode: "undelegate",
602
- coinType: sdk.DEFAULT_COIN_TYPE,
603
- amount: new BigNumber(500000000), // 0.5 SUI
604
- stakedSuiId: "0xstaked_sui_object_123",
605
- useAllAmount: false,
606
- recipient: "0xvalidator_address_123", // Required by type but not used for undelegate
607
- };
608
- const tx = await sdk.createTransaction(address, transaction);
609
- expect(tx).toBeDefined();
610
- });
611
- test("createTransaction should build undelegate transaction with all amount", async () => {
612
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
613
- const transaction = {
614
- mode: "undelegate",
615
- coinType: sdk.DEFAULT_COIN_TYPE,
616
- amount: new BigNumber(0),
617
- stakedSuiId: "0xstaked_sui_object_123",
618
- useAllAmount: true,
619
- recipient: "0xvalidator_address_123", // Required by type but not used for undelegate
620
- };
621
- const tx = await sdk.createTransaction(address, transaction);
622
- expect(tx).toBeDefined();
623
- });
624
- });
625
- describe("Payment Info for Staking", () => {
626
- test("paymentInfo should return gas budget and fees for delegate transaction", async () => {
627
- const sender = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
628
- const fakeTransaction = {
629
- mode: "delegate",
630
- coinType: sdk.DEFAULT_COIN_TYPE,
631
- family: "sui",
632
- amount: new BigNumber(1000000000), // 1 SUI
633
- recipient: "0xvalidator_address_123",
634
- errors: {},
635
- };
636
- const info = await sdk.paymentInfo(sender, fakeTransaction);
637
- expect(info).toHaveProperty("gasBudget");
638
- expect(info).toHaveProperty("totalGasUsed");
639
- expect(info).toHaveProperty("fees");
640
- });
641
- test("paymentInfo should return gas budget and fees for undelegate transaction", async () => {
642
- const sender = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
643
- const fakeTransaction = {
644
- mode: "undelegate",
645
- coinType: sdk.DEFAULT_COIN_TYPE,
646
- family: "sui",
647
- amount: new BigNumber(500000000), // 0.5 SUI
648
- stakedSuiId: "0xstaked_sui_object_123",
649
- useAllAmount: false,
650
- recipient: "0xvalidator_address_123", // Required by type but not used for undelegate
651
- errors: {},
652
- };
653
- const info = await sdk.paymentInfo(sender, fakeTransaction);
654
- expect(info).toHaveProperty("gasBudget");
655
- expect(info).toHaveProperty("totalGasUsed");
656
- expect(info).toHaveProperty("fees");
657
- });
658
- });
659
- describe("Transaction to Operation Mapping", () => {
660
- test("transactionToOperation should map staking transaction correctly", () => {
661
- const accountId = "mockAccountId";
662
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
663
- const operation = sdk.transactionToOperation(accountId, address, mockStakingTx(address, "-1000000000"));
664
- expect(operation).toHaveProperty("id");
665
- expect(operation).toHaveProperty("accountId", accountId);
666
- expect(operation).toHaveProperty("type", "DELEGATE");
667
- expect(operation).toHaveProperty("hash", "delegate_tx_digest_123");
668
- expect(operation).toHaveProperty("extra");
669
- expect(operation.extra.coinType).toBe(sdk.DEFAULT_COIN_TYPE);
670
- expect(operation.value).toEqual(new BigNumber("1000000000")); // The function returns minus of the balance change
671
- expect(operation.recipients).toEqual([]);
672
- expect(operation.senders).toEqual([address]);
673
- });
674
- test("transactionToOperation should map unstaking transaction correctly", () => {
675
- const accountId = "mockAccountId";
676
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
677
- const operation = sdk.transactionToOperation(accountId, address, mockUnstakingTx(address, "1000000000"));
678
- expect(operation).toHaveProperty("id");
679
- expect(operation).toHaveProperty("accountId", accountId);
680
- expect(operation).toHaveProperty("type", "UNDELEGATE");
681
- expect(operation).toHaveProperty("hash", "undelegate_tx_digest_456");
682
- expect(operation).toHaveProperty("extra");
683
- expect(operation.extra.coinType).toBe(sdk.DEFAULT_COIN_TYPE);
684
- expect(operation.value).toEqual(new BigNumber("-1000000000"));
685
- expect(operation.recipients).toEqual([]);
686
- expect(operation.senders).toEqual([address]);
687
- });
688
- test("transactionToOp should map staking transaction correctly", () => {
689
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
690
- const operation = sdk.alpacaTransactionToOp(address, mockStakingTx(address, "-1000000000"));
691
- expect(operation.id).toEqual("delegate_tx_digest_123");
692
- expect(operation.type).toEqual("DELEGATE");
693
- expect(operation.senders).toEqual([address]);
694
- expect(operation.recipients).toEqual([]);
695
- expect(operation.value).toEqual(1000000000n); // The function returns minus of the balance change
696
- expect(operation.asset).toEqual({ type: "native" });
697
- expect(operation.tx.block.hash).toBeUndefined();
698
- });
699
- test("transactionToOp should map unstaking transaction correctly", () => {
700
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
701
- const operation = sdk.alpacaTransactionToOp(address, mockUnstakingTx(address, "1000000000"));
702
- expect(operation.id).toEqual("undelegate_tx_digest_456");
703
- expect(operation.type).toEqual("UNDELEGATE");
704
- expect(operation.senders).toEqual([address]);
705
- expect(operation.recipients).toEqual([]);
706
- expect(operation.value).toEqual(1000000000n);
707
- expect(operation.asset).toEqual({ type: "native" });
708
- expect(operation.tx.block.hash).toBeUndefined();
709
- });
710
- });
711
- describe("Operation Extra Information", () => {
712
- test("getOperationExtra should be a function", () => {
713
- expect(typeof sdk.getOperationExtra).toBe("function");
714
- });
715
- test("getOperationExtra should return a Promise", () => {
716
- const result = sdk.getOperationExtra("test_digest");
717
- expect(result).toBeInstanceOf(Promise);
718
- });
719
- });
720
- });
721
- describe("queryTransactions", () => {
722
- it("should call api.queryTransactionBlocks with correct params for IN", async () => {
723
- mockApi.queryTransactionBlocks.mockResolvedValueOnce({
724
- data: [{ digest: "tx1" }],
725
- hasNextPage: false,
726
- });
727
- const result = await sdk.queryTransactions({
728
- api: mockApi,
729
- addr: "0xabc",
730
- type: "IN",
731
- order: "ascending",
732
- });
733
- expect(mockApi.queryTransactionBlocks).toHaveBeenCalledWith(expect.objectContaining({
734
- filter: { ToAddress: "0xabc" },
735
- }));
736
- expect(result.data).toHaveLength(1);
737
- });
738
- it("should call api.queryTransactionBlocks with correct params for OUT", async () => {
739
- mockApi.queryTransactionBlocks.mockResolvedValueOnce({
740
- data: [{ digest: "tx2" }],
741
- hasNextPage: false,
742
- });
743
- const result = await sdk.queryTransactions({
744
- api: mockApi,
745
- addr: "0xdef",
746
- type: "OUT",
747
- order: "ascending",
748
- });
749
- expect(mockApi.queryTransactionBlocks).toHaveBeenCalledWith(expect.objectContaining({
750
- filter: { FromAddress: "0xdef" },
751
- }));
752
- expect(result.data).toHaveLength(1);
753
- });
754
- });
755
- describe("loadOperations", () => {
756
- it("should paginate and accumulate results", async () => {
757
- const pageSize = sdk.TRANSACTIONS_LIMIT_PER_QUERY;
758
- const firstPage = Array.from({ length: pageSize }, (_, i) => ({ digest: `tx${i + 1}` }));
759
- mockApi.queryTransactionBlocks
760
- .mockResolvedValueOnce({
761
- data: firstPage,
762
- hasNextPage: true,
763
- nextCursor: "cursor1",
764
- })
765
- .mockResolvedValueOnce({
766
- data: [{ digest: `tx${pageSize + 1}` }],
767
- hasNextPage: false,
768
- });
769
- const result = await sdk.loadOperations({
770
- api: mockApi,
771
- addr: "0xabc",
772
- type: "IN",
773
- order: "ascending",
774
- operations: [],
775
- });
776
- expect(result.operations).toHaveLength(pageSize + 1);
777
- expect(result.operations.map(tx => tx.digest)).toEqual([
778
- ...firstPage.map(tx => tx.digest),
779
- `tx${pageSize + 1}`,
780
- ]);
781
- expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(2);
782
- });
783
- it("should stop if less than TRANSACTIONS_LIMIT_PER_QUERY returned", async () => {
784
- // Create an array with length less than TRANSACTIONS_LIMIT_PER_QUERY
785
- const txs = Array.from({ length: sdk.TRANSACTIONS_LIMIT_PER_QUERY - 1 }, (_, i) => ({
786
- digest: `tx${i + 1}`,
787
- }));
788
- mockApi.queryTransactionBlocks.mockResolvedValueOnce({
789
- data: txs,
790
- hasNextPage: false, // Only one call should be made
791
- });
792
- const result = await sdk.loadOperations({
793
- api: mockApi,
794
- addr: "0xabc",
795
- type: "OUT",
796
- order: "ascending",
797
- operations: [],
798
- });
799
- expect(result.operations).toHaveLength(sdk.TRANSACTIONS_LIMIT_PER_QUERY - 1);
800
- expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(1);
801
- });
802
- it("should not exceed TRANSACTIONS_LIMIT", async () => {
803
- const page = Array.from({ length: sdk.TRANSACTIONS_LIMIT_PER_QUERY }, (_, i) => ({
804
- digest: `tx${i + 1}`,
805
- }));
806
- const expectedCalls = Math.ceil(sdk.TRANSACTIONS_LIMIT / sdk.TRANSACTIONS_LIMIT_PER_QUERY);
807
- let callCount = 0;
808
- mockApi.queryTransactionBlocks.mockImplementation(() => {
809
- callCount++;
810
- return Promise.resolve({
811
- data: page,
812
- hasNextPage: callCount < expectedCalls,
813
- nextCursor: callCount < expectedCalls ? "cursor" : null,
814
- });
815
- });
816
- const result = await sdk.loadOperations({
817
- api: mockApi,
818
- addr: "0xabc",
819
- type: "IN",
820
- order: "ascending",
821
- operations: [],
822
- });
823
- expect(result.operations).toHaveLength(sdk.TRANSACTIONS_LIMIT);
824
- expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(expectedCalls);
825
- });
826
- it("should retry without cursor when InvalidParams error occurs", async () => {
827
- // Reset the mock for this test
828
- mockApi.queryTransactionBlocks.mockReset();
829
- // Call fails with InvalidParams
830
- mockApi.queryTransactionBlocks.mockRejectedValueOnce({ type: "InvalidParams" });
831
- const result = await sdk.loadOperations({
832
- api: mockApi,
833
- addr: "0xabc",
834
- type: "IN",
835
- cursor: "some-cursor",
836
- order: "ascending",
837
- operations: [],
838
- });
839
- // Should have been called once (no retry in actual implementation)
840
- expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(1);
841
- // Should have been called with the cursor
842
- expect(mockApi.queryTransactionBlocks).toHaveBeenCalledWith(expect.objectContaining({
843
- filter: { ToAddress: "0xabc" },
844
- cursor: "some-cursor",
845
- }));
846
- // Result should be empty array (no retry, just return operations)
847
- expect(result.operations).toHaveLength(0);
848
- });
849
- it("should should not retry after unexpected errors and return empty data", async () => {
850
- mockApi.queryTransactionBlocks.mockRejectedValueOnce(new Error("unexpected"));
851
- const result = await sdk.loadOperations({
852
- api: mockApi,
853
- addr: "0xerr",
854
- type: "IN",
855
- order: "ascending",
856
- operations: [],
857
- });
858
- expect(result.operations).toEqual([]);
859
- expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(1);
860
- });
861
- });
862
- describe("getOperations filtering logic", () => {
863
- const mockAccountId = "mockAccountId";
864
- const mockAddr = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
865
- // Mock loadOperations to return controlled test data
866
- const mockLoadOperations = jest.spyOn(sdk, "loadOperations");
867
- // Helper function to create mock transaction data
868
- const createMockTransaction = (digest, timestampMs, sender = mockAddr, recipients = [], balanceChangeAmount) => {
869
- // If sender is mockAddr (OUT), amount is negative; if sender is otherAddr (IN), amount is positive
870
- const isOut = sender === mockAddr;
871
- const amount = balanceChangeAmount ?? (isOut ? "-1000000" : "1000000");
872
- return {
873
- digest,
874
- timestampMs,
875
- effects: {
876
- status: { status: "success" },
877
- gasUsed: {
878
- computationCost: "1000000",
879
- storageCost: "500000",
880
- storageRebate: "450000",
881
- nonRefundableStorageFee: "0",
882
- },
883
- executedEpoch: "1",
884
- gasObject: {
885
- owner: { AddressOwner: sender },
886
- reference: {
887
- objectId: "0xgas",
888
- version: "1",
889
- digest: "gas-digest",
890
- },
891
- },
892
- messageVersion: "v1",
893
- transactionDigest: digest,
894
- },
895
- balanceChanges: [
896
- {
897
- owner: { AddressOwner: mockAddr },
898
- coinType: sdk.DEFAULT_COIN_TYPE,
899
- amount,
900
- },
901
- ],
902
- transaction: {
903
- data: {
904
- sender,
905
- transaction: {
906
- kind: "ProgrammableTransaction",
907
- inputs: recipients.map(r => ({ type: "pure", valueType: "address", value: r })),
908
- transactions: [],
909
- },
910
- gasData: {
911
- budget: "1000",
912
- owner: sender,
913
- payment: [],
914
- price: "1",
915
- },
916
- messageVersion: "v1",
917
- },
918
- txSignatures: [],
919
- },
920
- };
921
- };
922
- const otherAddr = "0xotheraddress";
923
- // OUT = sender is mockAddr, IN = sender is otherAddr
924
- beforeEach(() => {
925
- mockLoadOperations.mockReset();
926
- // Mock loadOperations to return different data based on operation type
927
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
928
- if (type === "OUT") {
929
- return {
930
- operations: [
931
- createMockTransaction("sent1", "1000", mockAddr, []),
932
- createMockTransaction("sent2", "2000", mockAddr, []),
933
- ],
934
- cursor: null,
935
- };
936
- }
937
- else if (type === "IN") {
938
- return {
939
- operations: [
940
- createMockTransaction("received1", "1500", otherAddr, [mockAddr]),
941
- createMockTransaction("received2", "2500", otherAddr, [mockAddr]),
942
- ],
943
- cursor: null,
944
- };
945
- }
946
- return { operations: [], cursor: null };
947
- });
948
- });
949
- afterEach(() => {
950
- // Remove mockRestore as it might interfere with the mock setup
951
- });
952
- test("should not apply timestamp filter when cursor is provided", async () => {
953
- const cursor = "test-cursor";
954
- const operations = await sdk.getOperations(mockAccountId, mockAddr, cursor);
955
- // Should not filter by timestamp when cursor is provided
956
- expect(operations).toHaveLength(4);
957
- expect(operations.map(op => op.hash)).toEqual(["received2", "sent2", "received1", "sent1"]);
958
- });
959
- test("should not apply timestamp filter when operations don't reach limits", async () => {
960
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
961
- // Should not filter by timestamp when limits aren't reached
962
- expect(operations).toHaveLength(4);
963
- expect(operations.map(op => op.hash)).toEqual(["received2", "sent2", "received1", "sent1"]);
964
- });
965
- test("should apply timestamp filter when sent operations reach limit", async () => {
966
- // Mock to return enough sent operations to reach limit
967
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
968
- if (type === "OUT") {
969
- return {
970
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`sent${i + 1}`, String(1000 + i * 100), mockAddr, [])),
971
- cursor: null,
972
- };
973
- }
974
- else if (type === "IN") {
975
- return {
976
- operations: [
977
- createMockTransaction("received1", "500", otherAddr, [mockAddr]),
978
- createMockTransaction("received2", "1500", otherAddr, [mockAddr]),
979
- ],
980
- cursor: null,
981
- };
982
- }
983
- return { operations: [], cursor: null };
984
- });
985
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
986
- // Filter timestamp should be the maximum of the last timestamps from both arrays
987
- // sent: last timestamp = 1000 + 299*100 = 30900
988
- // received: last timestamp = 1500
989
- // filter = max(30900, 1500) = 30900
990
- // Only operations with timestamp >= 30900 should remain
991
- expect(operations).toHaveLength(1); // Only sent300 (30900)
992
- expect(operations.map(op => op.hash)).toEqual(["sent300"]);
993
- });
994
- test("should apply timestamp filter when received operations reach limit", async () => {
995
- // Mock to return enough received operations to reach limit
996
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
997
- if (type === "OUT") {
998
- return {
999
- operations: [
1000
- createMockTransaction("sent1", "500", mockAddr, []),
1001
- createMockTransaction("sent2", "1500", mockAddr, []),
1002
- ],
1003
- cursor: null,
1004
- };
1005
- }
1006
- else if (type === "IN") {
1007
- return {
1008
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`received${i + 1}`, String(1000 + i * 100), otherAddr, [
1009
- mockAddr,
1010
- ])),
1011
- cursor: null,
1012
- };
1013
- }
1014
- return { operations: [], cursor: null };
1015
- });
1016
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
1017
- // Filter timestamp should be the maximum of the last timestamps from both arrays
1018
- // sent: last timestamp = 1500
1019
- // received: last timestamp = 1000 + 299*100 = 30900
1020
- // filter = max(1500, 30900) = 30900
1021
- // Only operations with timestamp >= 30900 should remain
1022
- expect(operations).toHaveLength(1); // Only received300 (30900)
1023
- expect(operations.map(op => op.hash)).toEqual(["received300"]);
1024
- });
1025
- test("should apply timestamp filter when both operations reach limit", async () => {
1026
- // Mock to return enough operations to reach limit for both types
1027
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
1028
- if (type === "OUT") {
1029
- return {
1030
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`sent${i + 1}`, String(1000 + i * 100), mockAddr, [])),
1031
- cursor: null,
1032
- };
1033
- }
1034
- else if (type === "IN") {
1035
- return {
1036
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`received${i + 1}`, String(2000 + i * 100), otherAddr, [
1037
- mockAddr,
1038
- ])),
1039
- cursor: null,
1040
- };
1041
- }
1042
- return { operations: [], cursor: null };
1043
- });
1044
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
1045
- // Filter timestamp should be the maximum of the last timestamps from both arrays
1046
- // sent: last timestamp = 1000 + 299*100 = 30900
1047
- // received: last timestamp = 2000 + 299*100 = 31900
1048
- // filter = max(30900, 31900) = 31900
1049
- // Only operations with timestamp >= 31900 should remain
1050
- expect(operations).toHaveLength(1); // Only received300 (31900)
1051
- expect(operations.map(op => op.hash)).toEqual(["received300"]);
1052
- });
1053
- test("should handle null/undefined timestampMs values", async () => {
1054
- // Mock to return operations with null timestamps and reach limit
1055
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
1056
- if (type === "OUT") {
1057
- return {
1058
- operations: [
1059
- createMockTransaction("sent1", "1000", mockAddr, []),
1060
- createMockTransaction("sent2", null, mockAddr, []),
1061
- createMockTransaction("sent3", "3000", mockAddr, []),
1062
- ...Array.from({ length: sdk.TRANSACTIONS_LIMIT - 3 }, (_, i) => createMockTransaction(`sent${i + 4}`, String(4000 + i * 100), mockAddr, [])),
1063
- ],
1064
- cursor: null,
1065
- };
1066
- }
1067
- else if (type === "IN") {
1068
- return {
1069
- operations: [
1070
- createMockTransaction("received1", null, otherAddr, [mockAddr]),
1071
- createMockTransaction("received2", "2000", otherAddr, [mockAddr]),
1072
- createMockTransaction("received3", "4000", otherAddr, [mockAddr]),
1073
- ],
1074
- cursor: null,
1075
- };
1076
- }
1077
- return { operations: [], cursor: null };
1078
- });
1079
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
1080
- // Filter timestamp should be the timestamp of the last sent operation (4000 + 296*100 = 33600)
1081
- // Only operations with timestamp >= 33600 should remain
1082
- expect(operations).toHaveLength(1); // Only sent300 (33600)
1083
- expect(operations.map(op => op.hash)).toEqual(["sent300"]);
1084
- });
1085
- test("should maintain chronological order after filtering", async () => {
1086
- // Mock to return operations that reach limit
1087
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
1088
- if (type === "OUT") {
1089
- return {
1090
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`sent${i + 1}`, String(1000 + i * 10), mockAddr, [])),
1091
- cursor: null,
1092
- };
1093
- }
1094
- else if (type === "IN") {
1095
- return {
1096
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`received${i + 1}`, String(500 + i * 10), otherAddr, [mockAddr])),
1097
- cursor: null,
1098
- };
1099
- }
1100
- return { operations: [], cursor: null };
1101
- });
1102
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
1103
- // Should be sorted by timestamp in descending order
1104
- const timestamps = operations.map(op => Number(op.date.getTime()));
1105
- expect(timestamps).toEqual(timestamps.slice().sort((a, b) => b - a));
1106
- });
1107
- test("should handle empty operations arrays", async () => {
1108
- // Mock to return empty arrays
1109
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
1110
- return { operations: [], cursor: null };
1111
- });
1112
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
1113
- expect(operations).toHaveLength(0);
1114
- });
1115
- test("should handle mixed empty and non-empty operations", async () => {
1116
- // Mock to return only OUT operations
1117
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
1118
- if (type === "OUT") {
1119
- return {
1120
- operations: [
1121
- createMockTransaction("sent1", "1000", mockAddr, []),
1122
- createMockTransaction("sent2", "2000", mockAddr, []),
1123
- ],
1124
- cursor: null,
1125
- };
1126
- }
1127
- else if (type === "IN") {
1128
- return { operations: [], cursor: null };
1129
- }
1130
- return { operations: [], cursor: null };
1131
- });
1132
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
1133
- expect(operations).toHaveLength(2);
1134
- expect(operations.map(op => op.hash)).toEqual(["sent2", "sent1"]);
1135
- });
1136
- test("should handle operations with same timestamps", async () => {
1137
- // Mock to return operations with same timestamps and reach limit
1138
- mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
1139
- if (type === "OUT") {
1140
- return {
1141
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`sent${i + 1}`, "1000", mockAddr, [])),
1142
- cursor: null,
1143
- };
1144
- }
1145
- else if (type === "IN") {
1146
- return {
1147
- operations: [
1148
- createMockTransaction("received1", "1000", otherAddr, [mockAddr]),
1149
- createMockTransaction("received2", "1000", otherAddr, [mockAddr]),
1150
- ],
1151
- cursor: null,
1152
- };
1153
- }
1154
- return { operations: [], cursor: null };
1155
- });
1156
- const operations = await sdk.getOperations(mockAccountId, mockAddr);
1157
- // Filter timestamp should be 1000 (the common timestamp)
1158
- // All operations have timestamp 1000, so all should pass the filter
1159
- expect(operations).toHaveLength(sdk.TRANSACTIONS_LIMIT + 2); // All 300 sent + 2 received
1160
- expect(operations[0].hash).toBe("sent1"); // First one should be the first sent
1161
- expect(operations[operations.length - 1].hash).toBe("received2"); // Last one should be the last received
1162
- });
1163
- });
1164
- describe("filterOperations", () => {
1165
- const createMockTransaction = (digest, timestampMs) => ({
1166
- digest,
1167
- timestampMs,
1168
- effects: {
1169
- status: { status: "success" },
1170
- gasUsed: {
1171
- computationCost: "1000000",
1172
- storageCost: "500000",
1173
- storageRebate: "450000",
1174
- nonRefundableStorageFee: "0",
1175
- },
1176
- executedEpoch: "1",
1177
- gasObject: {
1178
- owner: { AddressOwner: "0x123" },
1179
- reference: {
1180
- objectId: "0xgas",
1181
- version: "1",
1182
- digest: "gas-digest",
1183
- },
1184
- },
1185
- messageVersion: "v1",
1186
- transactionDigest: digest,
1187
- },
1188
- transaction: {
1189
- data: {
1190
- sender: "0x123",
1191
- transaction: {
1192
- kind: "ProgrammableTransaction",
1193
- inputs: [],
1194
- transactions: [],
1195
- },
1196
- gasData: {
1197
- budget: "1000",
1198
- owner: "0x123",
1199
- payment: [],
1200
- price: "1",
1201
- },
1202
- messageVersion: "v1",
1203
- },
1204
- txSignatures: [],
1205
- },
1206
- balanceChanges: [],
1207
- });
1208
- describe("when cursor is provided", () => {
1209
- test("should not apply timestamp filtering", () => {
1210
- const operationList1 = {
1211
- operations: [createMockTransaction("tx1", "1000"), createMockTransaction("tx2", "2000")],
1212
- cursor: null,
1213
- };
1214
- const operationList2 = {
1215
- operations: [createMockTransaction("tx3", "1500"), createMockTransaction("tx4", "2500")],
1216
- cursor: null,
1217
- };
1218
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1219
- // Should return all operations sorted by timestamp in descending order
1220
- expect(result.operations).toHaveLength(4);
1221
- expect(result.operations.map(tx => tx.digest)).toEqual(["tx4", "tx2", "tx3", "tx1"]);
1222
- });
1223
- test("should handle null cursor", () => {
1224
- const operationList1 = {
1225
- operations: [createMockTransaction("tx1", "1000"), createMockTransaction("tx2", "2000")],
1226
- cursor: null,
1227
- };
1228
- const operationList2 = {
1229
- operations: [createMockTransaction("tx3", "1500"), createMockTransaction("tx4", "2500")],
1230
- cursor: null,
1231
- };
1232
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1233
- // Should return all operations sorted by timestamp in descending order
1234
- expect(result.operations).toHaveLength(4);
1235
- expect(result.operations.map(tx => tx.digest)).toEqual(["tx4", "tx2", "tx3", "tx1"]);
1236
- });
1237
- test("should handle undefined cursor", () => {
1238
- const operationList1 = {
1239
- operations: [createMockTransaction("tx1", "1000"), createMockTransaction("tx2", "2000")],
1240
- cursor: null,
1241
- };
1242
- const operationList2 = {
1243
- operations: [createMockTransaction("tx3", "1500"), createMockTransaction("tx4", "2500")],
1244
- cursor: null,
1245
- };
1246
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1247
- // Should return all operations sorted by timestamp in descending order
1248
- expect(result.operations).toHaveLength(4);
1249
- expect(result.operations.map(tx => tx.digest)).toEqual(["tx4", "tx2", "tx3", "tx1"]);
1250
- });
1251
- });
1252
- describe("when cursor is not provided and operations reach limits", () => {
1253
- test("should apply timestamp filtering when both lists reach limit", () => {
1254
- const operationList1 = {
1255
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, String(1000 + i * 100))),
1256
- cursor: null,
1257
- };
1258
- const operationList2 = {
1259
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx2_${i + 1}`, String(2000 + i * 100))),
1260
- cursor: null,
1261
- };
1262
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1263
- // Filter timestamp should be max of last timestamps:
1264
- // operationList1: 1000 + 299*100 = 30900
1265
- // operationList2: 2000 + 299*100 = 31900
1266
- // filter = max(30900, 31900) = 31900
1267
- // Only operations with timestamp >= 31900 should remain
1268
- const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 31900);
1269
- expect(filteredOperations).toHaveLength(1);
1270
- expect(filteredOperations[0].digest).toBe("tx2_300");
1271
- });
1272
- test("should apply timestamp filtering when only first list reaches limit", () => {
1273
- const operationList1 = {
1274
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, String(1000 + i * 100))),
1275
- cursor: null,
1276
- };
1277
- const operationList2 = {
1278
- operations: [createMockTransaction("tx2_1", "500"), createMockTransaction("tx2_2", "1500")],
1279
- cursor: null,
1280
- };
1281
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1282
- // Filter timestamp should be max of last timestamps:
1283
- // operationList1: 1000 + 299*100 = 30900
1284
- // operationList2: 1500
1285
- // filter = max(30900, 1500) = 30900
1286
- // Only operations with timestamp >= 30900 should remain
1287
- const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 30900);
1288
- expect(filteredOperations).toHaveLength(1);
1289
- expect(filteredOperations[0].digest).toBe("tx1_300");
1290
- });
1291
- test("should apply timestamp filtering when only second list reaches limit", () => {
1292
- const operationList1 = {
1293
- operations: [createMockTransaction("tx1_1", "500"), createMockTransaction("tx1_2", "1500")],
1294
- cursor: null,
1295
- };
1296
- const operationList2 = {
1297
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx2_${i + 1}`, String(2000 + i * 100))),
1298
- cursor: null,
1299
- };
1300
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1301
- // Filter timestamp should be max of last timestamps:
1302
- // operationList1: 1500
1303
- // operationList2: 2000 + 299*100 = 31900
1304
- // filter = max(1500, 31900) = 31900
1305
- // Only operations with timestamp >= 31900 should remain
1306
- const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 31900);
1307
- expect(filteredOperations).toHaveLength(1);
1308
- expect(filteredOperations[0].digest).toBe("tx2_300");
1309
- });
1310
- });
1311
- describe("when cursor is not provided and operations don't reach limits", () => {
1312
- test("should not apply timestamp filtering when neither list reaches limit", () => {
1313
- const operationList1 = {
1314
- operations: [
1315
- createMockTransaction("tx1_1", "1000"),
1316
- createMockTransaction("tx1_2", "2000"),
1317
- ],
1318
- cursor: null,
1319
- };
1320
- const operationList2 = {
1321
- operations: [
1322
- createMockTransaction("tx2_1", "1500"),
1323
- createMockTransaction("tx2_2", "2500"),
1324
- ],
1325
- cursor: null,
1326
- };
1327
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1328
- // Should return all operations sorted by timestamp in descending order
1329
- expect(result.operations).toHaveLength(4);
1330
- expect(result.operations.map(tx => tx.digest)).toEqual(["tx2_2", "tx1_2", "tx2_1", "tx1_1"]);
1331
- });
1332
- test("should apply timestamp filtering when only one list reaches limit", () => {
1333
- const operationList1 = {
1334
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, String(1000 + i * 100))),
1335
- cursor: null,
1336
- };
1337
- const operationList2 = {
1338
- operations: [createMockTransaction("tx2_1", "1500")],
1339
- cursor: null,
1340
- };
1341
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1342
- // Should apply timestamp filtering since one list reaches limit
1343
- // Filter timestamp should be the timestamp of the last operation in list1 (1000 + 299*100 = 30900)
1344
- // Only operations with timestamp >= 30900 should remain
1345
- const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 30900);
1346
- expect(filteredOperations).toHaveLength(1);
1347
- expect(filteredOperations[0].digest).toBe("tx1_300");
1348
- });
1349
- });
1350
- describe("edge cases", () => {
1351
- test("should handle null/undefined timestampMs values", () => {
1352
- const operationList1 = {
1353
- operations: [
1354
- createMockTransaction("tx1_1", "1000"),
1355
- createMockTransaction("tx1_2", null),
1356
- createMockTransaction("tx1_3", "3000"),
1357
- ...Array.from({ length: sdk.TRANSACTIONS_LIMIT - 3 }, (_, i) => createMockTransaction(`tx1_${i + 4}`, String(4000 + i * 100))),
1358
- ],
1359
- cursor: null,
1360
- };
1361
- const operationList2 = {
1362
- operations: [
1363
- createMockTransaction("tx2_1", null),
1364
- createMockTransaction("tx2_2", "2000"),
1365
- createMockTransaction("tx2_3", "4000"),
1366
- ],
1367
- cursor: null,
1368
- };
1369
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1370
- // Filter timestamp should be the timestamp of the last operation in list1 (4000 + 296*100 = 33600)
1371
- // Only operations with timestamp >= 33600 should remain
1372
- const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 33600);
1373
- expect(filteredOperations).toHaveLength(1);
1374
- expect(filteredOperations[0].digest).toBe("tx1_300");
1375
- });
1376
- test("should handle empty arrays", () => {
1377
- const result = sdk.filterOperations({ operations: [], cursor: null }, { operations: [], cursor: null }, "ascending");
1378
- expect(result.operations).toHaveLength(0);
1379
- });
1380
- test("should handle one empty array", () => {
1381
- const operationList1 = {
1382
- operations: [
1383
- createMockTransaction("tx1_1", "1000"),
1384
- createMockTransaction("tx1_2", "2000"),
1385
- ],
1386
- cursor: null,
1387
- };
1388
- const operationList2 = {
1389
- operations: [],
1390
- cursor: null,
1391
- };
1392
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1393
- expect(result.operations).toHaveLength(2);
1394
- expect(result.operations.map(tx => tx.digest)).toEqual(["tx1_2", "tx1_1"]);
1395
- });
1396
- test("should remove duplicate transactions by digest", () => {
1397
- const operationList1 = {
1398
- operations: [createMockTransaction("tx1", "1000"), createMockTransaction("tx2", "2000")],
1399
- cursor: null,
1400
- };
1401
- const operationList2 = {
1402
- operations: [
1403
- createMockTransaction("tx2", "2000"), // Duplicate digest
1404
- createMockTransaction("tx3", "3000"),
1405
- ],
1406
- cursor: null,
1407
- };
1408
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1409
- // Should remove duplicate tx2
1410
- expect(result.operations).toHaveLength(3);
1411
- expect(result.operations.map(tx => tx.digest)).toEqual(["tx3", "tx2", "tx1"]);
1412
- });
1413
- test("should maintain chronological order after filtering", () => {
1414
- const operationList1 = {
1415
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, String(1000 + i * 10))),
1416
- cursor: null,
1417
- };
1418
- const operationList2 = {
1419
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx2_${i + 1}`, String(500 + i * 10))),
1420
- cursor: null,
1421
- };
1422
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1423
- // Should be sorted by timestamp in descending order
1424
- const timestamps = result.operations.map(tx => Number(tx.timestampMs));
1425
- expect(timestamps).toEqual(timestamps.slice().sort((a, b) => b - a));
1426
- });
1427
- test("should handle operations with same timestamps", () => {
1428
- const operationList1 = {
1429
- operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, "1000")),
1430
- cursor: null,
1431
- };
1432
- const operationList2 = {
1433
- operations: [
1434
- createMockTransaction("tx2_1", "1000"),
1435
- createMockTransaction("tx2_2", "1000"),
1436
- ],
1437
- cursor: null,
1438
- };
1439
- const result = sdk.filterOperations(operationList1, operationList2, "ascending");
1440
- // Filter timestamp should be 1000 (the common timestamp)
1441
- // All operations have timestamp 1000, so all should pass the filter
1442
- expect(result.operations).toHaveLength(sdk.TRANSACTIONS_LIMIT + 2);
1443
- });
1444
- });
1445
- describe("conversion methods", () => {
1446
- test("toBlockOperation should map native transfers correctly", () => {
1447
- expect(sdk.toBlockOperation(mockTransaction, {
1448
- owner: {
1449
- AddressOwner: "0x65449f57946938c84c5127",
1450
- },
1451
- coinType: sdk.DEFAULT_COIN_TYPE,
1452
- amount: "-10000000000",
1453
- })).toEqual([
1454
- {
1455
- type: "transfer",
1456
- address: "0x65449f57946938c84c5127",
1457
- amount: -10000000000n,
1458
- asset: { type: "native" },
1459
- },
1460
- ]);
1461
- });
1462
- test("toBlockOperation should ignore transfers from shared owner", () => {
1463
- expect(sdk.toBlockOperation(mockTransaction, {
1464
- owner: {
1465
- Shared: {
1466
- initial_shared_version: "0",
1467
- },
1468
- },
1469
- coinType: sdk.DEFAULT_COIN_TYPE,
1470
- amount: "-10000000000",
1471
- })).toEqual([]);
1472
- });
1473
- test("toBlockOperation should ignore transfers from object owner", () => {
1474
- expect(sdk.toBlockOperation(mockTransaction, {
1475
- owner: {
1476
- ObjectOwner: "test",
1477
- },
1478
- coinType: sdk.DEFAULT_COIN_TYPE,
1479
- amount: "-10000000000",
1480
- })).toEqual([]);
1481
- });
1482
- test("toBlockOperation should ignore transfers from immutable owner", () => {
1483
- expect(sdk.toBlockOperation(mockTransaction, {
1484
- owner: "Immutable",
1485
- coinType: sdk.DEFAULT_COIN_TYPE,
1486
- amount: "-10000000000",
1487
- })).toEqual([]);
1488
- });
1489
- test("toBlockOperation should ignore transfers from consensus owner", () => {
1490
- expect(sdk.toBlockOperation(mockTransaction, {
1491
- owner: {
1492
- ConsensusAddressOwner: {
1493
- owner: "test",
1494
- start_version: "1",
1495
- },
1496
- },
1497
- coinType: sdk.DEFAULT_COIN_TYPE,
1498
- amount: "-10000000000",
1499
- })).toEqual([]);
1500
- });
1501
- test("toBlockOperation should map token transfers correctly", () => {
1502
- expect(sdk.toBlockOperation(mockTransaction, {
1503
- owner: {
1504
- AddressOwner: "0x65449f57946938c84c5127",
1505
- },
1506
- coinType: "0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC",
1507
- amount: "8824",
1508
- })).toEqual([
1509
- {
1510
- type: "transfer",
1511
- address: "0x65449f57946938c84c5127",
1512
- amount: 8824n,
1513
- asset: {
1514
- type: "token",
1515
- assetReference: "0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC",
1516
- },
1517
- },
1518
- ]);
1519
- });
1520
- test("toBlockOperation should map staking operations correctly", () => {
1521
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
1522
- expect(sdk.toBlockOperation(mockStakingTx(address, "-1000000000"), {
1523
- owner: { AddressOwner: address },
1524
- coinType: sdk.DEFAULT_COIN_TYPE,
1525
- amount: "-10000000000",
1526
- })).toEqual([
1527
- {
1528
- type: "other",
1529
- operationType: "DELEGATE",
1530
- address: address,
1531
- asset: { type: "native" },
1532
- amount: 10000000000n,
1533
- },
1534
- ]);
1535
- });
1536
- test("toBlockOperation should map unstaking operations correctly", () => {
1537
- const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
1538
- expect(sdk.toBlockOperation(mockUnstakingTx(address, "1000000000"), {
1539
- owner: { AddressOwner: address },
1540
- coinType: sdk.DEFAULT_COIN_TYPE,
1541
- amount: "10000000000",
1542
- })).toEqual([
1543
- {
1544
- type: "other",
1545
- operationType: "UNDELEGATE",
1546
- address: address,
1547
- asset: { type: "native" },
1548
- amount: 10000000000n,
1549
- },
1550
- ]);
1551
- });
1552
- test("toBlockInfo should map checkpoints correctly", () => {
1553
- expect(sdk.toBlockInfo({
1554
- checkpointCommitments: [],
1555
- digest: "0xaaaaaaaaa",
1556
- previousDigest: "0xbbbbbbbbbb",
1557
- epoch: "",
1558
- epochRollingGasCostSummary: {
1559
- computationCost: "",
1560
- nonRefundableStorageFee: "",
1561
- storageCost: "",
1562
- storageRebate: "",
1563
- },
1564
- networkTotalTransactions: "",
1565
- sequenceNumber: "42",
1566
- timestampMs: "1751696298663",
1567
- transactions: [],
1568
- validatorSignature: "",
1569
- })).toEqual({
1570
- height: 42,
1571
- hash: "0xaaaaaaaaa",
1572
- time: new Date(1751696298663),
1573
- parent: {
1574
- height: 41,
1575
- hash: "0xbbbbbbbbbb",
1576
- },
1577
- });
1578
- });
1579
- test("toBlockTransaction should map transactions correctly", () => {
1580
- expect(sdk.toBlockTransaction(
1581
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1582
- mockTransaction)).toEqual({
1583
- hash: "DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt",
1584
- failed: false,
1585
- fees: 1009880n,
1586
- feesPayer: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
1587
- operations: [
1588
- {
1589
- address: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
1590
- amount: -10000000000n,
1591
- asset: { type: "native" },
1592
- type: "transfer",
1593
- },
1594
- {
1595
- address: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
1596
- amount: 9998990120n,
1597
- asset: { type: "native" },
1598
- type: "transfer",
1599
- },
1600
- {
1601
- address: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
1602
- amount: 500000n,
1603
- asset: { type: "token", assetReference: "0x123::test::TOKEN" },
1604
- type: "transfer",
1605
- },
1606
- ],
1607
- });
1608
- });
1609
- test("toSuiAsset should map native coin correctly", () => {
1610
- expect(sdk.toSuiAsset(sdk.DEFAULT_COIN_TYPE)).toEqual({ type: "native" });
1611
- });
1612
- test("suiCoinTypeToAsset should map tokens correctly", () => {
1613
- expect(sdk.toSuiAsset("0x123::test::TOKEN")).toEqual({
1614
- type: "token",
1615
- assetReference: "0x123::test::TOKEN",
1616
- });
1617
- });
1618
- });
1619
- });
1620
- describe("getCoinsForAmount", () => {
1621
- const mockAddress = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
1622
- const mockCoinType = "0x2::sui::SUI";
1623
- beforeEach(() => {
1624
- mockApi.getCoins.mockReset();
1625
- });
1626
- describe("basic functionality", () => {
1627
- test("handles single coin scenarios", async () => {
1628
- const sufficientCoins = createMockCoins(["1000"]);
1629
- mockApi.getCoins.mockResolvedValueOnce({ data: sufficientCoins, hasNextPage: false });
1630
- let result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1631
- expect(result).toHaveLength(1);
1632
- expect(result[0].balance).toBe("1000");
1633
- const insufficientCoins = createMockCoins(["500"]);
1634
- mockApi.getCoins.mockResolvedValueOnce({ data: insufficientCoins, hasNextPage: false });
1635
- result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1636
- expect(result).toHaveLength(1);
1637
- expect(result[0].balance).toBe("500");
1638
- });
1639
- test("selects minimum coins needed", async () => {
1640
- const exactMatchCoins = createMockCoins(["600", "400", "300"]);
1641
- mockApi.getCoins.mockResolvedValueOnce({ data: exactMatchCoins, hasNextPage: false });
1642
- let result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1643
- expect(result).toHaveLength(2);
1644
- expect(result[0].balance).toBe("600");
1645
- expect(result[1].balance).toBe("400");
1646
- const exceedCoins = createMockCoins(["800", "400", "200"]);
1647
- mockApi.getCoins.mockResolvedValueOnce({ data: exceedCoins, hasNextPage: false });
1648
- result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1649
- expect(result).toHaveLength(2);
1650
- expect(result[0].balance).toBe("800");
1651
- expect(result[1].balance).toBe("400");
1652
- });
1653
- test("handles edge cases", async () => {
1654
- mockApi.getCoins.mockResolvedValueOnce({ data: [], hasNextPage: false });
1655
- let result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1656
- expect(result).toHaveLength(0);
1657
- const coins = createMockCoins(["1000"]);
1658
- mockApi.getCoins.mockResolvedValueOnce({ data: coins, hasNextPage: false });
1659
- result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 0);
1660
- expect(result).toHaveLength(0);
1661
- });
1662
- });
1663
- describe("sorting and filtering", () => {
1664
- test("filters zero balance coins", async () => {
1665
- const mockCoins = createMockCoins(["1000", "500"]);
1666
- mockCoins.splice(1, 0, createMockCoins(["0"])[0]);
1667
- mockCoins.push({ coinObjectId: "0xcoin4", balance: "0", digest: "0xdigest4", version: "1" });
1668
- mockApi.getCoins.mockResolvedValueOnce({ data: mockCoins, hasNextPage: false });
1669
- const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1670
- expect(result).toHaveLength(1);
1671
- expect(result[0].balance).toBe("1000");
1672
- expect(result.every(coin => parseInt(coin.balance) > 0)).toBe(true);
1673
- });
1674
- test("sorts and optimizes coin selection", async () => {
1675
- const unsortedCoins = createMockCoins(["100", "800", "300", "500"]);
1676
- mockApi.getCoins.mockResolvedValueOnce({ data: unsortedCoins, hasNextPage: false });
1677
- let result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1678
- expect(result).toHaveLength(2);
1679
- expect(result[0].balance).toBe("800");
1680
- expect(result[1].balance).toBe("500");
1681
- const mixedCoins = createMockCoins(["200", "800", "400"]);
1682
- mixedCoins.unshift(createMockCoins(["0"])[0]);
1683
- mixedCoins.splice(2, 0, createMockCoins(["0"])[0]);
1684
- mockApi.getCoins.mockResolvedValueOnce({ data: mixedCoins, hasNextPage: false });
1685
- result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1686
- expect(result).toHaveLength(2);
1687
- expect(result[0].balance).toBe("800");
1688
- expect(result[1].balance).toBe("400");
1689
- expect(result.every(coin => parseInt(coin.balance) > 0)).toBe(true);
1690
- });
1691
- test("handles all zero balance coins", async () => {
1692
- const mockCoins = createMockCoins(["0", "0", "0"]);
1693
- mockApi.getCoins.mockResolvedValueOnce({ data: mockCoins, hasNextPage: false });
1694
- const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1695
- expect(result).toHaveLength(0);
1696
- expect(result).toEqual([]);
1697
- });
1698
- });
1699
- describe("pagination", () => {
1700
- test("handles single page scenarios", async () => {
1701
- const mockCoins = createMockCoins(["800", "400", "300"]);
1702
- mockApi.getCoins.mockResolvedValueOnce({
1703
- data: mockCoins,
1704
- hasNextPage: true,
1705
- nextCursor: "cursor1",
1706
- });
1707
- const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1708
- expect(result).toHaveLength(2);
1709
- expect(result[0].balance).toBe("800");
1710
- expect(result[1].balance).toBe("400");
1711
- expect(mockApi.getCoins).toHaveBeenCalledTimes(1);
1712
- });
1713
- test("handles multi-page scenarios", async () => {
1714
- const firstPageCoins = createMockCoins(["300", "200"]);
1715
- const secondPageCoins = createMockCoins(["600", "400", "100"]);
1716
- mockApi.getCoins
1717
- .mockResolvedValueOnce({
1718
- data: firstPageCoins,
1719
- hasNextPage: true,
1720
- nextCursor: "cursor1",
1721
- })
1722
- .mockResolvedValueOnce({
1723
- data: secondPageCoins,
1724
- hasNextPage: false,
1725
- });
1726
- const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1727
- expect(result).toHaveLength(3);
1728
- expect(result[0].balance).toBe("300");
1729
- expect(result[1].balance).toBe("200");
1730
- expect(result[2].balance).toBe("600");
1731
- expect(mockApi.getCoins).toHaveBeenCalledTimes(2);
1732
- });
1733
- test("handles insufficient funds across pages", async () => {
1734
- const firstPageCoins = createMockCoins(["300", "200"]);
1735
- const secondPageCoins = createMockCoins(["200", "100"]);
1736
- mockApi.getCoins
1737
- .mockResolvedValueOnce({
1738
- data: firstPageCoins,
1739
- hasNextPage: true,
1740
- nextCursor: "cursor1",
1741
- })
1742
- .mockResolvedValueOnce({
1743
- data: secondPageCoins,
1744
- hasNextPage: false,
1745
- });
1746
- const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
1747
- expect(result).toHaveLength(4);
1748
- expect(result[0].balance).toBe("300");
1749
- expect(result[1].balance).toBe("200");
1750
- expect(result[2].balance).toBe("200");
1751
- expect(result[3].balance).toBe("100");
1752
- expect(mockApi.getCoins).toHaveBeenCalledTimes(2);
1753
- });
1754
- });
1755
- });
1756
- //# sourceMappingURL=sdk.test.js.map