@ledgerhq/coin-sui 0.16.0-nightly.7 → 0.16.0-nightly.8

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