@ledgerhq/coin-sui 0.16.0 → 0.16.1-nightly.0

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