@tomo-inc/chains-service 0.0.22 → 0.0.24

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 (50) hide show
  1. package/dist/index.cjs +50 -26
  2. package/dist/index.d.cts +5 -1
  3. package/dist/index.d.ts +5 -1
  4. package/dist/index.js +51 -27
  5. package/package.json +2 -1
  6. package/project.json +1 -1
  7. package/src/__tests__/config.test.ts +46 -0
  8. package/src/__tests__/dogecoin-utils.test.ts +147 -0
  9. package/src/__tests__/evm-utils.test.ts +133 -0
  10. package/src/__tests__/index.test.ts +40 -0
  11. package/src/__tests__/services.test.ts +285 -0
  12. package/src/__tests__/solana-utils.test.ts +131 -0
  13. package/src/__tests__/utils.test.ts +52 -0
  14. package/src/__tests__/wallet.test.ts +350 -0
  15. package/src/api/__tests__/base.test.ts +146 -0
  16. package/src/api/__tests__/index.test.ts +51 -0
  17. package/src/api/__tests__/network.test.ts +153 -0
  18. package/src/api/__tests__/token.test.ts +231 -2
  19. package/src/api/__tests__/transaction.test.ts +121 -6
  20. package/src/api/__tests__/user.test.ts +237 -3
  21. package/src/api/__tests__/wallet.test.ts +174 -4
  22. package/src/api/network.ts +9 -1
  23. package/src/api/utils/__tests__/index.test.ts +91 -0
  24. package/src/api/utils/__tests__/signature.test.ts +124 -0
  25. package/src/api/utils/index.ts +6 -2
  26. package/src/base/__tests__/network.test.ts +119 -0
  27. package/src/base/__tests__/service.test.ts +68 -0
  28. package/src/base/__tests__/token.test.ts +123 -0
  29. package/src/base/__tests__/transaction.test.ts +210 -0
  30. package/src/config.ts +1 -1
  31. package/src/dogecoin/__tests__/base.test.ts +76 -0
  32. package/src/dogecoin/__tests__/rpc.test.ts +465 -0
  33. package/src/dogecoin/__tests__/service-extended.test.ts +420 -0
  34. package/src/dogecoin/__tests__/utils-doge.test.ts +244 -0
  35. package/src/dogecoin/__tests__/utils-extended.test.ts +323 -0
  36. package/src/dogecoin/base.ts +1 -0
  37. package/src/dogecoin/config.ts +2 -1
  38. package/src/dogecoin/rpc.ts +33 -7
  39. package/src/dogecoin/service.ts +9 -5
  40. package/src/evm/__tests__/rpc.test.ts +132 -0
  41. package/src/evm/__tests__/service.test.ts +535 -0
  42. package/src/evm/__tests__/utils.test.ts +170 -0
  43. package/src/evm/utils.ts +2 -2
  44. package/src/solana/__tests__/service.test.ts +425 -0
  45. package/src/solana/__tests__/utils.test.ts +937 -0
  46. package/src/solana/config.ts +1 -1
  47. package/src/solana/service.ts +2 -0
  48. package/src/solana/utils.ts +2 -16
  49. package/src/utils/index.ts +1 -1
  50. package/vitest.config.ts +13 -0
@@ -0,0 +1,76 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { fromHex, toHex, toBase64, fromBase64, toBase58 } from "../base";
3
+
4
+ describe("dogecoin/base", () => {
5
+ describe("fromHex", () => {
6
+ it("should convert hex to Uint8Array", () => {
7
+ const result = fromHex("48656c6c6f");
8
+ expect(result).toBeInstanceOf(Uint8Array);
9
+ expect(result.length).toBe(5);
10
+ });
11
+
12
+ it("should handle hex with 0x prefix", () => {
13
+ const result = fromHex("0x48656c6c6f");
14
+ expect(result.length).toBe(5);
15
+ });
16
+
17
+ it("should pad odd-length hex", () => {
18
+ const result = fromHex("48656c6c6");
19
+ expect(result.length).toBe(5);
20
+ });
21
+ });
22
+
23
+ describe("toHex", () => {
24
+ it("should convert Uint8Array to hex", () => {
25
+ const array = new Uint8Array([72, 101, 108, 108, 111]);
26
+ const hex = toHex(array);
27
+ expect(hex).toBe("48656c6c6f");
28
+ });
29
+
30
+ it("should convert Buffer to hex", () => {
31
+ const buffer = Buffer.from("Hello");
32
+ const hex = toHex(buffer);
33
+ expect(hex).toBe("48656c6c6f");
34
+ });
35
+
36
+ it("should handle string input", () => {
37
+ const hex = toHex("0x48656c6c6f");
38
+ expect(hex).toBe("48656c6c6f");
39
+ });
40
+ });
41
+
42
+ describe("toBase64", () => {
43
+ it("should convert Uint8Array to base64", () => {
44
+ const array = new Uint8Array([72, 101, 108, 108, 111]);
45
+ const base64 = toBase64(array);
46
+ expect(base64).toBe("SGVsbG8=");
47
+ });
48
+
49
+ it("should convert hex string to base64", () => {
50
+ const base64 = toBase64("48656c6c6f");
51
+ expect(base64).toBe("SGVsbG8=");
52
+ });
53
+
54
+ it("should convert Buffer to base64", () => {
55
+ const buffer = Buffer.from("Hello");
56
+ const base64 = toBase64(buffer);
57
+ expect(base64).toBe("SGVsbG8=");
58
+ });
59
+ });
60
+
61
+ describe("fromBase64", () => {
62
+ it("should convert base64 to Uint8Array", () => {
63
+ const result = fromBase64("SGVsbG8=");
64
+ expect(result).toBeInstanceOf(Uint8Array);
65
+ expect(result.length).toBe(5);
66
+ });
67
+ });
68
+
69
+ describe("toBase58", () => {
70
+ it("should throw with message to install bs58", () => {
71
+ expect(() => toBase58(new Uint8Array([1, 2, 3]))).toThrow(
72
+ "toBase58 requires bs58 package. Install it: pnpm add bs58",
73
+ );
74
+ });
75
+ });
76
+ });
@@ -0,0 +1,465 @@
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import axios from "axios";
3
+
4
+ // Mock axios before importing rpc module
5
+ vi.mock("axios", () => ({
6
+ default: {
7
+ create: vi.fn(() => ({
8
+ get: vi.fn(),
9
+ post: vi.fn(),
10
+ })),
11
+ },
12
+ }));
13
+
14
+ // Import rpc after mocking axios
15
+ import * as rpc from "../rpc";
16
+
17
+ describe("dogecoin rpc", () => {
18
+ beforeEach(() => {
19
+ vi.clearAllMocks();
20
+
21
+ // Replace methods on the exported mydoge instance
22
+ if (rpc.mydoge) {
23
+ rpc.mydoge.get = vi.fn();
24
+ rpc.mydoge.post = vi.fn();
25
+ }
26
+
27
+ // For api instance (not exported), we need to spy on axios.create calls
28
+ // But since it's already created, we'll handle it differently in each test
29
+ });
30
+
31
+ describe("getBalance", () => {
32
+ it("should return balance for valid address", async () => {
33
+ (rpc.mydoge.get as any).mockResolvedValue({
34
+ data: {
35
+ address: "DTest123",
36
+ balance: 100000000,
37
+ },
38
+ });
39
+
40
+ const result = await rpc.getBalance("DTest123");
41
+ expect(result.address).toBe("DTest123");
42
+ expect(result.balance).toBe(100000000);
43
+ });
44
+
45
+ it("should return empty balance for empty address", async () => {
46
+ const result = await rpc.getBalance("");
47
+ expect(result.address).toBe("");
48
+ expect(result.balance).toBe(0);
49
+ });
50
+
51
+ it("should return empty balance for undefined address", async () => {
52
+ const result = await rpc.getBalance(undefined as any);
53
+ expect(result.address).toBe("");
54
+ expect(result.balance).toBe(0);
55
+ });
56
+ });
57
+
58
+ describe("getTxDetail", () => {
59
+ it("should return transaction detail for valid txId", async () => {
60
+ const mockTxDetail = {
61
+ txid: "test-tx-id",
62
+ hex: "01000000",
63
+ blockHeight: 100,
64
+ confirmations: 10,
65
+ };
66
+ (rpc.mydoge.get as any).mockResolvedValue({ data: mockTxDetail });
67
+
68
+ const result = await rpc.getTxDetail("test-tx-id");
69
+ expect(result.txid).toBe("test-tx-id");
70
+ });
71
+
72
+ it("should return empty object for empty txId", async () => {
73
+ const result = await rpc.getTxDetail("");
74
+ expect(result).toEqual({});
75
+ });
76
+ });
77
+
78
+ describe("getSpendableUtxos", () => {
79
+ it("should return spendable UTXOs", async () => {
80
+ const mockUtxos = [
81
+ { txid: "tx1", vout: 0, satoshis: 100000000 },
82
+ { txid: "tx2", vout: 1, satoshis: 50000000 },
83
+ ];
84
+ (rpc.mydoge.get as any).mockResolvedValue({
85
+ data: {
86
+ utxos: mockUtxos,
87
+ next_cursor: null,
88
+ },
89
+ });
90
+
91
+ const result = await rpc.getSpendableUtxos("DTest123");
92
+ expect(result.length).toBeGreaterThan(0);
93
+ });
94
+
95
+ it("should paginate when next_cursor is present", async () => {
96
+ const page1 = [{ txid: "tx1", vout: 0, satoshis: 50000000 }];
97
+ const page2 = [{ txid: "tx2", vout: 1, satoshis: 100000000 }];
98
+ (rpc.mydoge.get as any)
99
+ .mockResolvedValueOnce({
100
+ data: { utxos: page1, next_cursor: 100 },
101
+ })
102
+ .mockResolvedValueOnce({
103
+ data: { utxos: page2, next_cursor: null },
104
+ });
105
+
106
+ const result = await rpc.getSpendableUtxos("DTest123");
107
+ expect(result.length).toBe(2);
108
+ });
109
+ });
110
+
111
+ describe("getInscriptionsUtxos", () => {
112
+ it("should return inscription UTXOs", async () => {
113
+ const mockUtxos = [{ txid: "tx1", vout: 0, satoshis: 100000000, inscriptions: [] }];
114
+ (rpc.mydoge.get as any).mockResolvedValue({
115
+ data: {
116
+ utxos: mockUtxos,
117
+ next_cursor: null,
118
+ },
119
+ });
120
+
121
+ const result = await rpc.getInscriptionsUtxos("DTest123");
122
+ expect(Array.isArray(result)).toBe(true);
123
+ });
124
+
125
+ it("should include inscriptions field when filter is inscriptions", async () => {
126
+ const mockUtxos = [
127
+ { txid: "tx1", vout: 0, satoshis: 100000000, script_pubkey: "script", inscriptions: [{ id: "ins1" }] },
128
+ ];
129
+ (rpc.mydoge.get as any).mockResolvedValue({
130
+ data: { utxos: mockUtxos, next_cursor: null },
131
+ });
132
+
133
+ const result = await rpc.getInscriptionsUtxos("DTest123");
134
+ expect(result[0]).toHaveProperty("inscriptions");
135
+ expect(result[0].inscriptions).toEqual([{ id: "ins1" }]);
136
+ });
137
+ });
138
+
139
+ describe("getInscriptionsUtxo", () => {
140
+ it("should return single inscription utxo for given tx", async () => {
141
+ const tx = { txid: "tx1", vout: 0 };
142
+ const mockUtxos = [
143
+ { txid: "tx1", vout: 0, satoshis: 100000000, script_pubkey: "script", inscriptions: [{ id: "ins1" }] },
144
+ ];
145
+ (rpc.mydoge.get as any).mockResolvedValue({
146
+ data: { utxos: mockUtxos, next_cursor: null },
147
+ });
148
+
149
+ const result = await rpc.getInscriptionsUtxo("DTest123", tx);
150
+ expect(result).toBeDefined();
151
+ expect(result.inscriptions).toEqual([{ id: "ins1" }]);
152
+ });
153
+ });
154
+
155
+ describe("getUnSpentUtxos", () => {
156
+ it("should return unspent UTXOs and filter by spentTxid", async () => {
157
+ const mockUtxos = [
158
+ { txid: "tx1", vout: 0, value: 100000000, spentTxid: null },
159
+ { txid: "tx2", vout: 1, value: 50000000, spentTxid: "spent-tx" },
160
+ ];
161
+ const mockApiInstance = {
162
+ get: vi.fn().mockResolvedValue({ data: mockUtxos }),
163
+ post: vi.fn(),
164
+ };
165
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() }); // mydoge
166
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() }); // tomoApi
167
+ (axios.create as any).mockReturnValueOnce(mockApiInstance); // api
168
+
169
+ vi.resetModules();
170
+ const freshRpc = await import("../rpc");
171
+ const result = await freshRpc.getUnSpentUtxos("DTest123");
172
+ expect(result.length).toBe(1);
173
+ expect(result[0].spentTxid).toBeNull();
174
+ });
175
+
176
+ it("should return empty array when API returns empty data", async () => {
177
+ const mockApiInstance = {
178
+ get: vi.fn().mockResolvedValue({ data: [] }),
179
+ post: vi.fn(),
180
+ };
181
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
182
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
183
+ (axios.create as any).mockReturnValueOnce(mockApiInstance);
184
+
185
+ vi.resetModules();
186
+ const freshRpc = await import("../rpc");
187
+ const result = await freshRpc.getUnSpentUtxos("DTest123");
188
+ expect(result).toEqual([]);
189
+ });
190
+
191
+ it("should return empty array on error", async () => {
192
+ const mockApiInstance = {
193
+ get: vi.fn().mockRejectedValue(new Error("API Error")),
194
+ post: vi.fn(),
195
+ };
196
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
197
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
198
+ (axios.create as any).mockReturnValueOnce(mockApiInstance);
199
+
200
+ vi.resetModules();
201
+ const freshRpc = await import("../rpc");
202
+ const result = await freshRpc.getUnSpentUtxos("DTest123");
203
+ expect(result).toEqual([]);
204
+ });
205
+ });
206
+
207
+ describe("sendTransaction", () => {
208
+ it("should send transaction", async () => {
209
+ (rpc.mydoge.post as any).mockResolvedValue({
210
+ data: {
211
+ result: "tx-hash",
212
+ },
213
+ });
214
+
215
+ const result = await rpc.sendTransaction({
216
+ signed: "signed-tx-hex",
217
+ senderAddress: "DTest123",
218
+ });
219
+ expect(result).toBeDefined();
220
+ });
221
+ });
222
+
223
+ describe("estimateSmartFee", () => {
224
+ it("should estimate smart fee", async () => {
225
+ (rpc.mydoge.post as any).mockResolvedValue({
226
+ data: {
227
+ result: {
228
+ feerate: 0.001,
229
+ },
230
+ },
231
+ });
232
+
233
+ const result = await rpc.estimateSmartFee({ senderAddress: "DTest123" });
234
+ expect(result).toHaveProperty("feePerKB");
235
+ });
236
+ });
237
+
238
+ describe("getTransactions", () => {
239
+ it("should get transactions", async () => {
240
+ const mockTxIds = ["tx1", "tx2"];
241
+ const mockTxDetail = {
242
+ txid: "tx1",
243
+ hex: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020602ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52daaf87de6c36dfd4115338ef46e897963355484b448fd40aadcbee1d4047e10ac00000000",
244
+ blockHeight: 100,
245
+ };
246
+ (rpc.mydoge.get as any)
247
+ .mockResolvedValueOnce({
248
+ data: {
249
+ txids: mockTxIds,
250
+ totalPages: 1,
251
+ page: 1,
252
+ },
253
+ })
254
+ .mockResolvedValueOnce({ data: mockTxDetail })
255
+ .mockResolvedValueOnce({ data: mockTxDetail });
256
+
257
+ const result = await rpc.getTransactions("DTest123", { pageSize: 10, pageNumber: 1 });
258
+ expect(result.transactions).toBeDefined();
259
+ expect(result.txIds).toEqual(mockTxIds);
260
+ });
261
+
262
+ it("should throw error on failure", async () => {
263
+ (rpc.mydoge.get as any).mockRejectedValue(new Error("API Error"));
264
+
265
+ await expect(rpc.getTransactions("DTest123")).rejects.toThrow("getTransactions failed");
266
+ });
267
+ });
268
+
269
+ describe("onCreateTransaction", () => {
270
+ it("should call sendResponse with rawTx and amountMismatch when resultAmount < amount - fee", async () => {
271
+ const sendResponse = vi.fn();
272
+ (rpc.mydoge.post as any).mockResolvedValue({
273
+ data: {
274
+ rawTx: "raw-hex",
275
+ fee: 0.001,
276
+ amount: 0.998, // less than 1 - 0.001
277
+ },
278
+ });
279
+
280
+ await rpc.onCreateTransaction({
281
+ data: {
282
+ senderAddress: "DFrom",
283
+ recipientAddress: "DTo",
284
+ dogeAmount: 1,
285
+ },
286
+ sendResponse,
287
+ });
288
+
289
+ expect(sendResponse).toHaveBeenCalledWith(
290
+ expect.objectContaining({
291
+ rawTx: "raw-hex",
292
+ fee: 0.001,
293
+ amount: 0.998,
294
+ amountMismatch: true,
295
+ }),
296
+ );
297
+ });
298
+
299
+ it("should call sendResponse with amountMismatch false when amount is sufficient", async () => {
300
+ const sendResponse = vi.fn();
301
+ (rpc.mydoge.post as any).mockResolvedValue({
302
+ data: {
303
+ rawTx: "raw-hex",
304
+ fee: 0.001,
305
+ amount: 0.999,
306
+ },
307
+ });
308
+
309
+ await rpc.onCreateTransaction({
310
+ data: {
311
+ senderAddress: "DFrom",
312
+ recipientAddress: "DTo",
313
+ dogeAmount: 1,
314
+ },
315
+ sendResponse,
316
+ });
317
+
318
+ expect(sendResponse).toHaveBeenCalledWith(
319
+ expect.objectContaining({
320
+ amountMismatch: false,
321
+ }),
322
+ );
323
+ });
324
+
325
+ it("should call sendResponse(false) on API error", async () => {
326
+ const sendResponse = vi.fn();
327
+ (rpc.mydoge.post as any).mockRejectedValue(new Error("API Error"));
328
+
329
+ await rpc.onCreateTransaction({
330
+ data: {
331
+ senderAddress: "DFrom",
332
+ recipientAddress: "DTo",
333
+ dogeAmount: 1,
334
+ },
335
+ sendResponse,
336
+ });
337
+
338
+ expect(sendResponse).toHaveBeenCalledWith(false);
339
+ });
340
+ });
341
+
342
+ describe("getDogeFeeByBlock", () => {
343
+ it("should get fee by block", async () => {
344
+ const mockApiInstance = {
345
+ get: vi.fn().mockResolvedValue({
346
+ data: {
347
+ feerate: 0.001,
348
+ },
349
+ }),
350
+ post: vi.fn(),
351
+ };
352
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
353
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
354
+ (axios.create as any).mockReturnValueOnce(mockApiInstance);
355
+
356
+ vi.resetModules();
357
+ const freshRpc = await import("../rpc");
358
+ const result = await freshRpc.getDogeFeeByBlock("DTest123", 22);
359
+ expect(result).toBeGreaterThan(0);
360
+ });
361
+ });
362
+
363
+ describe("sendDogeTx", () => {
364
+ it("should send doge transaction", async () => {
365
+ const mockTomoApi = {
366
+ get: vi.fn(),
367
+ post: vi.fn().mockResolvedValue({
368
+ data: {
369
+ result: "test-tx-id",
370
+ },
371
+ }),
372
+ };
373
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
374
+ (axios.create as any).mockReturnValueOnce(mockTomoApi);
375
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
376
+
377
+ vi.resetModules();
378
+ const freshRpc = await import("../rpc");
379
+ const result = await freshRpc.sendDogeTx("raw-tx-hex");
380
+ expect(result.txid).toBe("test-tx-id");
381
+ });
382
+
383
+ it("should reject with error message from response", async () => {
384
+ const mockError = {
385
+ response: {
386
+ data: "Transaction failed",
387
+ },
388
+ };
389
+ const mockTomoApi = {
390
+ get: vi.fn(),
391
+ post: vi.fn().mockRejectedValue(mockError),
392
+ };
393
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
394
+ (axios.create as any).mockReturnValueOnce(mockTomoApi);
395
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
396
+
397
+ vi.resetModules();
398
+ const freshRpc = await import("../rpc");
399
+ await expect(freshRpc.sendDogeTx("raw-tx-hex")).rejects.toThrow("Transaction failed");
400
+ });
401
+
402
+ it("should reject with error message from error object", async () => {
403
+ const mockError = {
404
+ message: "Network error",
405
+ };
406
+ const mockTomoApi = {
407
+ get: vi.fn(),
408
+ post: vi.fn().mockRejectedValue(mockError),
409
+ };
410
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
411
+ (axios.create as any).mockReturnValueOnce(mockTomoApi);
412
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
413
+
414
+ vi.resetModules();
415
+ const freshRpc = await import("../rpc");
416
+ await expect(freshRpc.sendDogeTx("raw-tx-hex")).rejects.toThrow("Network error");
417
+ });
418
+
419
+ it("should reject when response data contains error", async () => {
420
+ const mockTomoApi = {
421
+ get: vi.fn(),
422
+ post: vi.fn().mockResolvedValue({
423
+ data: { error: { message: "insufficient fee" } },
424
+ }),
425
+ };
426
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
427
+ (axios.create as any).mockReturnValueOnce(mockTomoApi);
428
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
429
+
430
+ vi.resetModules();
431
+ const freshRpc = await import("../rpc");
432
+ await expect(freshRpc.sendDogeTx("raw-tx-hex")).rejects.toThrow("insufficient fee");
433
+ });
434
+
435
+ it("should reject with error.message when catch has response.data.error.message", async () => {
436
+ const mockTomoApi = {
437
+ get: vi.fn(),
438
+ post: vi.fn().mockRejectedValue({
439
+ response: { data: { error: { message: "RPC error message" } } },
440
+ }),
441
+ };
442
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
443
+ (axios.create as any).mockReturnValueOnce(mockTomoApi);
444
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
445
+
446
+ vi.resetModules();
447
+ const freshRpc = await import("../rpc");
448
+ await expect(freshRpc.sendDogeTx("raw-tx-hex")).rejects.toThrow("RPC error message");
449
+ });
450
+
451
+ it("should reject with error when catch has no response.data", async () => {
452
+ const mockTomoApi = {
453
+ get: vi.fn(),
454
+ post: vi.fn().mockRejectedValue({ message: "Network failed" }),
455
+ };
456
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
457
+ (axios.create as any).mockReturnValueOnce(mockTomoApi);
458
+ (axios.create as any).mockReturnValueOnce({ get: vi.fn(), post: vi.fn() });
459
+
460
+ vi.resetModules();
461
+ const freshRpc = await import("../rpc");
462
+ await expect(freshRpc.sendDogeTx("raw-tx-hex")).rejects.toThrow("Network failed");
463
+ });
464
+ });
465
+ });