@swapkit/toolboxes 4.3.9 → 4.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/dist/LICENSE +246 -0
  2. package/dist/src/aptos/index.cjs +1 -0
  3. package/dist/src/aptos/index.js +1 -0
  4. package/dist/src/cardano/index.cjs +1 -4
  5. package/dist/src/cardano/index.js +1 -4
  6. package/dist/src/cosmos/index.cjs +1 -4
  7. package/dist/src/cosmos/index.js +1 -4
  8. package/dist/src/evm/index.cjs +1 -4
  9. package/dist/src/evm/index.js +1 -4
  10. package/dist/src/index.cjs +1 -5
  11. package/dist/src/index.js +1 -5
  12. package/dist/src/near/index.cjs +1 -4
  13. package/dist/src/near/index.js +1 -4
  14. package/dist/src/radix/index.cjs +1 -4
  15. package/dist/src/radix/index.js +1 -4
  16. package/dist/src/ripple/index.cjs +1 -4
  17. package/dist/src/ripple/index.js +1 -4
  18. package/dist/src/solana/index.cjs +1 -4
  19. package/dist/src/solana/index.js +1 -4
  20. package/dist/src/starknet/index.cjs +1 -0
  21. package/dist/src/starknet/index.js +1 -0
  22. package/dist/src/stellar/index.cjs +1 -0
  23. package/dist/src/stellar/index.js +1 -0
  24. package/dist/src/substrate/index.cjs +1 -4
  25. package/dist/src/substrate/index.js +1 -4
  26. package/dist/src/sui/index.cjs +1 -4
  27. package/dist/src/sui/index.js +1 -4
  28. package/dist/src/ton/index.cjs +1 -4
  29. package/dist/src/ton/index.js +1 -4
  30. package/dist/src/tron/index.cjs +1 -4
  31. package/dist/src/tron/index.js +1 -4
  32. package/dist/src/utxo/index.cjs +1 -5
  33. package/dist/src/utxo/index.js +1 -5
  34. package/dist/types/aptos/index.d.ts +3 -0
  35. package/dist/types/aptos/index.d.ts.map +1 -0
  36. package/dist/types/aptos/toolbox.d.ts +21 -0
  37. package/dist/types/aptos/toolbox.d.ts.map +1 -0
  38. package/dist/types/aptos/types.d.ts +27 -0
  39. package/dist/types/aptos/types.d.ts.map +1 -0
  40. package/dist/types/cardano/toolbox.d.ts +19 -22
  41. package/dist/types/cardano/toolbox.d.ts.map +1 -1
  42. package/dist/types/cardano/types.d.ts +8 -3
  43. package/dist/types/cardano/types.d.ts.map +1 -1
  44. package/dist/types/cosmos/thorchainUtils/addressFormat.d.ts.map +1 -1
  45. package/dist/types/cosmos/thorchainUtils/messages.d.ts +3 -3
  46. package/dist/types/cosmos/thorchainUtils/messages.d.ts.map +1 -1
  47. package/dist/types/cosmos/toolbox/cosmos.d.ts +11 -9
  48. package/dist/types/cosmos/toolbox/cosmos.d.ts.map +1 -1
  49. package/dist/types/cosmos/toolbox/thorchain.d.ts +6 -51
  50. package/dist/types/cosmos/toolbox/thorchain.d.ts.map +1 -1
  51. package/dist/types/cosmos/types.d.ts +2 -2
  52. package/dist/types/cosmos/types.d.ts.map +1 -1
  53. package/dist/types/evm/helpers.d.ts +34 -1
  54. package/dist/types/evm/helpers.d.ts.map +1 -1
  55. package/dist/types/evm/toolbox/baseEVMToolbox.d.ts +14 -7
  56. package/dist/types/evm/toolbox/baseEVMToolbox.d.ts.map +1 -1
  57. package/dist/types/evm/toolbox/evm.d.ts +236 -96
  58. package/dist/types/evm/toolbox/evm.d.ts.map +1 -1
  59. package/dist/types/evm/toolbox/index.d.ts +3 -2
  60. package/dist/types/evm/toolbox/index.d.ts.map +1 -1
  61. package/dist/types/evm/toolbox/op.d.ts +13 -8
  62. package/dist/types/evm/toolbox/op.d.ts.map +1 -1
  63. package/dist/types/evm/types.d.ts +49 -27
  64. package/dist/types/evm/types.d.ts.map +1 -1
  65. package/dist/types/index.d.ts +31 -25
  66. package/dist/types/index.d.ts.map +1 -1
  67. package/dist/types/near/helpers/core.d.ts +1 -1
  68. package/dist/types/near/helpers/core.d.ts.map +1 -1
  69. package/dist/types/near/index.d.ts +1 -1
  70. package/dist/types/near/index.d.ts.map +1 -1
  71. package/dist/types/near/toolbox.d.ts +13 -10
  72. package/dist/types/near/toolbox.d.ts.map +1 -1
  73. package/dist/types/near/types/index.d.ts +4 -0
  74. package/dist/types/near/types/index.d.ts.map +1 -0
  75. package/dist/types/near/types/toolbox.d.ts +2 -0
  76. package/dist/types/near/types/toolbox.d.ts.map +1 -1
  77. package/dist/types/radix/index.d.ts +7 -7
  78. package/dist/types/radix/index.d.ts.map +1 -1
  79. package/dist/types/ripple/currency.d.ts +5 -0
  80. package/dist/types/ripple/currency.d.ts.map +1 -0
  81. package/dist/types/ripple/index.d.ts +60 -17
  82. package/dist/types/ripple/index.d.ts.map +1 -1
  83. package/dist/types/ripple/tokens.d.ts +15 -0
  84. package/dist/types/ripple/tokens.d.ts.map +1 -0
  85. package/dist/types/solana/index.d.ts +1 -1
  86. package/dist/types/solana/index.d.ts.map +1 -1
  87. package/dist/types/solana/toolbox.d.ts +12 -10
  88. package/dist/types/solana/toolbox.d.ts.map +1 -1
  89. package/dist/types/starknet/index.d.ts +5 -0
  90. package/dist/types/starknet/index.d.ts.map +1 -0
  91. package/dist/types/starknet/toolbox.d.ts +34 -0
  92. package/dist/types/starknet/toolbox.d.ts.map +1 -0
  93. package/dist/types/starknet/types.d.ts +26 -0
  94. package/dist/types/starknet/types.d.ts.map +1 -0
  95. package/dist/types/stellar/index.d.ts +3 -0
  96. package/dist/types/stellar/index.d.ts.map +1 -0
  97. package/dist/types/stellar/toolbox.d.ts +21 -0
  98. package/dist/types/stellar/toolbox.d.ts.map +1 -0
  99. package/dist/types/stellar/types.d.ts +10 -0
  100. package/dist/types/stellar/types.d.ts.map +1 -0
  101. package/dist/types/substrate/balance.d.ts +3 -3
  102. package/dist/types/substrate/balance.d.ts.map +1 -1
  103. package/dist/types/substrate/substrate.d.ts +22 -97
  104. package/dist/types/substrate/substrate.d.ts.map +1 -1
  105. package/dist/types/substrate/types.d.ts +2 -2
  106. package/dist/types/substrate/types.d.ts.map +1 -1
  107. package/dist/types/sui/toolbox.d.ts +17 -8
  108. package/dist/types/sui/toolbox.d.ts.map +1 -1
  109. package/dist/types/sui/types.d.ts +11 -3
  110. package/dist/types/sui/types.d.ts.map +1 -1
  111. package/dist/types/ton/toolbox.d.ts +23 -13
  112. package/dist/types/ton/toolbox.d.ts.map +1 -1
  113. package/dist/types/ton/types.d.ts +9 -8
  114. package/dist/types/ton/types.d.ts.map +1 -1
  115. package/dist/types/tron/helpers/proto.d.ts +9 -0
  116. package/dist/types/tron/helpers/proto.d.ts.map +1 -0
  117. package/dist/types/tron/helpers/trongrid.d.ts +43 -3
  118. package/dist/types/tron/helpers/trongrid.d.ts.map +1 -1
  119. package/dist/types/tron/helpers/utils.d.ts +17 -0
  120. package/dist/types/tron/helpers/utils.d.ts.map +1 -0
  121. package/dist/types/tron/index.d.ts +4 -5
  122. package/dist/types/tron/index.d.ts.map +1 -1
  123. package/dist/types/tron/toolbox.d.ts +20 -18
  124. package/dist/types/tron/toolbox.d.ts.map +1 -1
  125. package/dist/types/tron/types.d.ts +31 -57
  126. package/dist/types/tron/types.d.ts.map +1 -1
  127. package/dist/types/types.d.ts +6 -0
  128. package/dist/types/types.d.ts.map +1 -1
  129. package/dist/types/utxo/hdWallet.d.ts +33 -0
  130. package/dist/types/utxo/hdWallet.d.ts.map +1 -0
  131. package/dist/types/utxo/helpers/api.d.ts +49 -1
  132. package/dist/types/utxo/helpers/api.d.ts.map +1 -1
  133. package/dist/types/utxo/helpers/bchaddrjs.d.ts.map +1 -1
  134. package/dist/types/utxo/helpers/cashaddr.d.ts +13 -0
  135. package/dist/types/utxo/helpers/cashaddr.d.ts.map +1 -0
  136. package/dist/types/utxo/helpers/coinselect.d.ts +9 -5
  137. package/dist/types/utxo/helpers/coinselect.d.ts.map +1 -1
  138. package/dist/types/utxo/helpers/txSize.d.ts +4 -3
  139. package/dist/types/utxo/helpers/txSize.d.ts.map +1 -1
  140. package/dist/types/utxo/index.d.ts +2 -1
  141. package/dist/types/utxo/index.d.ts.map +1 -1
  142. package/dist/types/utxo/toolbox/bitcoinCash.d.ts +75 -15
  143. package/dist/types/utxo/toolbox/bitcoinCash.d.ts.map +1 -1
  144. package/dist/types/utxo/toolbox/index.d.ts +6 -5
  145. package/dist/types/utxo/toolbox/index.d.ts.map +1 -1
  146. package/dist/types/utxo/toolbox/params.d.ts +8 -16
  147. package/dist/types/utxo/toolbox/params.d.ts.map +1 -1
  148. package/dist/types/utxo/toolbox/utxo.d.ts +135 -46
  149. package/dist/types/utxo/toolbox/utxo.d.ts.map +1 -1
  150. package/dist/types/utxo/toolbox/validators.d.ts +1 -1
  151. package/dist/types/utxo/toolbox/validators.d.ts.map +1 -1
  152. package/dist/types/utxo/toolbox/zcash.d.ts +63 -10
  153. package/dist/types/utxo/toolbox/zcash.d.ts.map +1 -1
  154. package/dist/types/utxo/types.d.ts +78 -15
  155. package/dist/types/utxo/types.d.ts.map +1 -1
  156. package/package.json +43 -53
  157. package/dist/src/cardano/index.cjs.map +0 -11
  158. package/dist/src/cardano/index.js.map +0 -11
  159. package/dist/src/cosmos/index.cjs.map +0 -20
  160. package/dist/src/cosmos/index.js.map +0 -20
  161. package/dist/src/evm/index.cjs.map +0 -20
  162. package/dist/src/evm/index.js.map +0 -20
  163. package/dist/src/index.cjs.map +0 -67
  164. package/dist/src/index.js.map +0 -67
  165. package/dist/src/near/index.cjs.map +0 -16
  166. package/dist/src/near/index.js.map +0 -16
  167. package/dist/src/radix/index.cjs.map +0 -10
  168. package/dist/src/radix/index.js.map +0 -10
  169. package/dist/src/ripple/index.cjs.map +0 -10
  170. package/dist/src/ripple/index.js.map +0 -10
  171. package/dist/src/solana/index.cjs.map +0 -11
  172. package/dist/src/solana/index.js.map +0 -11
  173. package/dist/src/substrate/index.cjs.map +0 -13
  174. package/dist/src/substrate/index.js.map +0 -13
  175. package/dist/src/sui/index.cjs.map +0 -11
  176. package/dist/src/sui/index.js.map +0 -11
  177. package/dist/src/ton/index.cjs.map +0 -11
  178. package/dist/src/ton/index.js.map +0 -11
  179. package/dist/src/tron/index.cjs.map +0 -13
  180. package/dist/src/tron/index.js.map +0 -13
  181. package/dist/src/utxo/index.cjs.map +0 -21
  182. package/dist/src/utxo/index.js.map +0 -21
  183. package/dist/types/tron/helpers/trc20.abi.d.ts +0 -156
  184. package/dist/types/tron/helpers/trc20.abi.d.ts.map +0 -1
  185. package/src/__tests__/address-validation-all-chains.test.ts +0 -162
  186. package/src/__tests__/addressValidator.test.ts +0 -162
  187. package/src/cardano/__tests__/toolbox.test.ts +0 -48
  188. package/src/cardano/index.ts +0 -2
  189. package/src/cardano/toolbox.ts +0 -168
  190. package/src/cardano/types.ts +0 -10
  191. package/src/cosmos/__tests__/toolbox.test.ts +0 -95
  192. package/src/cosmos/index.ts +0 -4
  193. package/src/cosmos/thorchainUtils/addressFormat.ts +0 -22
  194. package/src/cosmos/thorchainUtils/index.ts +0 -4
  195. package/src/cosmos/thorchainUtils/messages.ts +0 -212
  196. package/src/cosmos/thorchainUtils/registry.ts +0 -43
  197. package/src/cosmos/thorchainUtils/types/MsgCompiled.ts +0 -2800
  198. package/src/cosmos/thorchainUtils/types/client-types.ts +0 -54
  199. package/src/cosmos/thorchainUtils/types/index.ts +0 -1
  200. package/src/cosmos/toolbox/cosmos.ts +0 -345
  201. package/src/cosmos/toolbox/index.ts +0 -35
  202. package/src/cosmos/toolbox/thorchain.ts +0 -249
  203. package/src/cosmos/types.ts +0 -48
  204. package/src/cosmos/util.ts +0 -214
  205. package/src/evm/__tests__/address-validation.test.ts +0 -84
  206. package/src/evm/__tests__/ethereum.test.ts +0 -137
  207. package/src/evm/__tests__/signMessage.test.ts +0 -60
  208. package/src/evm/api.ts +0 -10
  209. package/src/evm/contracts/eth/multicall.ts +0 -165
  210. package/src/evm/contracts/op/gasOracle.ts +0 -145
  211. package/src/evm/helpers.ts +0 -71
  212. package/src/evm/index.ts +0 -4
  213. package/src/evm/toolbox/baseEVMToolbox.ts +0 -698
  214. package/src/evm/toolbox/evm.ts +0 -66
  215. package/src/evm/toolbox/index.ts +0 -44
  216. package/src/evm/toolbox/op.ts +0 -143
  217. package/src/evm/types.ts +0 -146
  218. package/src/index.ts +0 -260
  219. package/src/near/__tests__/core.test.ts +0 -70
  220. package/src/near/helpers/core.ts +0 -85
  221. package/src/near/helpers/gasEstimation.ts +0 -96
  222. package/src/near/helpers/nep141.ts +0 -50
  223. package/src/near/index.ts +0 -21
  224. package/src/near/toolbox.ts +0 -421
  225. package/src/near/types/contract.ts +0 -32
  226. package/src/near/types/nep141.ts +0 -34
  227. package/src/near/types/toolbox.ts +0 -55
  228. package/src/near/types.ts +0 -44
  229. package/src/radix/index.ts +0 -138
  230. package/src/ripple/index.ts +0 -179
  231. package/src/solana/index.ts +0 -36
  232. package/src/solana/toolbox.ts +0 -409
  233. package/src/substrate/balance.ts +0 -88
  234. package/src/substrate/index.ts +0 -2
  235. package/src/substrate/substrate.ts +0 -281
  236. package/src/substrate/types.ts +0 -115
  237. package/src/sui/__tests__/toolbox.test.ts +0 -86
  238. package/src/sui/index.ts +0 -2
  239. package/src/sui/toolbox.ts +0 -166
  240. package/src/sui/types.ts +0 -11
  241. package/src/ton/__tests__/toolbox.test.ts +0 -67
  242. package/src/ton/index.ts +0 -2
  243. package/src/ton/toolbox.ts +0 -136
  244. package/src/ton/types.ts +0 -13
  245. package/src/tron/__tests__/toolbox.test.ts +0 -221
  246. package/src/tron/helpers/trc20.abi.ts +0 -107
  247. package/src/tron/helpers/trongrid.ts +0 -53
  248. package/src/tron/index.ts +0 -21
  249. package/src/tron/toolbox.ts +0 -585
  250. package/src/tron/types.ts +0 -83
  251. package/src/types.ts +0 -28
  252. package/src/utils.ts +0 -34
  253. package/src/utxo/__tests__/zcash-integration.test.ts +0 -97
  254. package/src/utxo/helpers/api.ts +0 -471
  255. package/src/utxo/helpers/bchaddrjs.ts +0 -166
  256. package/src/utxo/helpers/coinselect.ts +0 -92
  257. package/src/utxo/helpers/index.ts +0 -4
  258. package/src/utxo/helpers/txSize.ts +0 -137
  259. package/src/utxo/index.ts +0 -6
  260. package/src/utxo/toolbox/bitcoinCash.ts +0 -243
  261. package/src/utxo/toolbox/index.ts +0 -59
  262. package/src/utxo/toolbox/params.ts +0 -18
  263. package/src/utxo/toolbox/utxo.ts +0 -439
  264. package/src/utxo/toolbox/validators.ts +0 -36
  265. package/src/utxo/toolbox/zcash.ts +0 -242
  266. package/src/utxo/types.ts +0 -39
package/src/utils.ts DELETED
@@ -1,34 +0,0 @@
1
- import { AssetValue, type Chain, getChainConfig } from "@swapkit/helpers";
2
- import { SwapKitApi } from "@swapkit/helpers/api";
3
-
4
- const pid = typeof process !== "undefined" && process.pid ? process.pid.toString(36) : "";
5
-
6
- let last = 0;
7
- export function uniqid() {
8
- function now() {
9
- const time = Date.now();
10
- const lastTime = last || time;
11
- last = lastTime;
12
-
13
- return time > last ? time : lastTime + 1;
14
- }
15
-
16
- return pid + now().toString(36);
17
- }
18
-
19
- export function getBalance<T extends Chain>(chain: T) {
20
- return async function getBalance(address: string, scamFilter = true) {
21
- const balances = await SwapKitApi.getChainBalance({ address, chain, scamFilter });
22
- const { baseDecimal } = getChainConfig(chain);
23
- const assetValues = balances.map(({ identifier, value, decimal }) => {
24
- return new AssetValue({ decimal: decimal || baseDecimal, identifier, value });
25
- });
26
-
27
- const hasNativeAsset = assetValues.some((asset) => asset.isGasAsset);
28
- if (!hasNativeAsset) {
29
- return [AssetValue.from({ chain }), ...assetValues];
30
- }
31
-
32
- return assetValues;
33
- };
34
- }
@@ -1,97 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { Chain, DerivationPath } from "@swapkit/helpers";
3
- import { getUtxoToolbox } from "../toolbox";
4
-
5
- describe("UTXO Toolbox Zcash Integration", () => {
6
- const testPhrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
7
-
8
- it("should create Zcash toolbox through main UTXO toolbox factory", async () => {
9
- const toolbox = await getUtxoToolbox(Chain.Zcash);
10
-
11
- expect(toolbox).toBeDefined();
12
- expect(typeof toolbox.validateAddress).toBe("function");
13
- expect(typeof toolbox.getBalance).toBe("function");
14
- expect(typeof toolbox.getFeeRates).toBe("function");
15
- expect(typeof toolbox.broadcastTx).toBe("function");
16
- expect(typeof toolbox.createTransaction).toBe("function");
17
- expect(typeof toolbox.transfer).toBe("function");
18
- });
19
-
20
- it("should create Zcash toolbox with phrase", async () => {
21
- const toolbox = await getUtxoToolbox(Chain.Zcash, { phrase: testPhrase });
22
-
23
- expect(toolbox).toBeDefined();
24
- expect(() => toolbox.getAddress()).not.toThrow();
25
- });
26
-
27
- it("should generate valid Zcash addresses", async () => {
28
- const toolbox = await getUtxoToolbox(Chain.Zcash, { phrase: testPhrase });
29
-
30
- const address = await toolbox.getAddress();
31
- expect(address).toBeDefined();
32
- expect(typeof address).toBe("string");
33
- expect(address?.startsWith("t1")).toBe(true); // Zcash mainnet addresses start with t1
34
- expect(toolbox.validateAddress(address || "")).toBe(true);
35
- });
36
-
37
- it("should validate Zcash addresses correctly", async () => {
38
- const toolbox = await getUtxoToolbox(Chain.Zcash);
39
-
40
- // Valid Zcash mainnet address format
41
- expect(toolbox.validateAddress("t1XVXWCvpMgBvUaed4XDqWtgQgJSu1Ghz7F")).toBe(true);
42
-
43
- // Invalid addresses
44
- expect(toolbox.validateAddress("1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2")).toBe(false); // Bitcoin address
45
- expect(toolbox.validateAddress("zcash:qr5agtachyxvrwxu76vzszan5pnvuzy8dm")).toBe(false); // Wrong format
46
- expect(toolbox.validateAddress("")).toBe(false); // Empty string
47
- expect(toolbox.validateAddress("invalid")).toBe(false); // Invalid string
48
- });
49
-
50
- it("should reject shielded addresses", async () => {
51
- const toolbox = await getUtxoToolbox(Chain.Zcash);
52
-
53
- // Test z-address (shielded) - should be rejected with warning
54
- const originalWarn = console.warn;
55
- let warnCalled = false;
56
- let warnMessage = "";
57
-
58
- console.warn = (message: string) => {
59
- warnCalled = true;
60
- warnMessage = message;
61
- };
62
-
63
- const isValid = toolbox.validateAddress("zs1z7rejlpsa98s2rrrfkwmaxu2xldqmfq5nj2m3hq6s7r8qjq8eqqqq9p4e7x");
64
-
65
- expect(isValid).toBe(false);
66
- expect(warnCalled).toBe(true);
67
- expect(warnMessage).toBe(
68
- "Shielded Zcash addresses (z-addresses) are not supported. Use transparent addresses (t1/t3) only.",
69
- );
70
-
71
- console.warn = originalWarn;
72
- });
73
-
74
- it("should create keys for derivation path", async () => {
75
- const toolbox = await getUtxoToolbox(Chain.Zcash, { phrase: testPhrase });
76
-
77
- const keys = await toolbox.createKeysForPath({ derivationPath: DerivationPath.ZEC, phrase: testPhrase });
78
-
79
- expect(keys).toBeDefined();
80
- expect(keys.publicKey).toBeDefined();
81
- expect(keys.privateKey).toBeDefined();
82
- expect(typeof keys.toWIF).toBe("function");
83
-
84
- const address = await toolbox.getAddress();
85
- expect(address).toBeDefined();
86
- expect(address?.startsWith("t1")).toBe(true);
87
- });
88
-
89
- it("should get WIF private key from mnemonic", async () => {
90
- const toolbox = await getUtxoToolbox(Chain.Zcash, { phrase: testPhrase });
91
-
92
- const wif = await toolbox.getPrivateKeyFromMnemonic({ derivationPath: DerivationPath.ZEC, phrase: testPhrase });
93
-
94
- expect(typeof wif).toBe("string");
95
- expect(wif.length).toBeGreaterThan(50); // WIF keys are typically 51-52 characters
96
- });
97
- });
@@ -1,471 +0,0 @@
1
- import { networks as zcashNetworks } from "@bitgo/utxo-lib";
2
- import { Chain, getRPCUrl, RequestClient, SKConfig, SwapKitError, type UTXOChain, warnOnce } from "@swapkit/helpers";
3
- import { networks } from "bitcoinjs-lib";
4
- // @ts-expect-error
5
- import coininfo from "coininfo";
6
- import { uniqid } from "../../utils";
7
-
8
- type BlockchairParams<T> = T & { chain: Chain; apiKey?: string };
9
- type BlockchairFetchUnspentUtxoParams = BlockchairParams<{
10
- offset?: number;
11
- limit?: number;
12
- address: string;
13
- targetValue?: number;
14
- accumulativeValue?: number;
15
- }>;
16
-
17
- async function broadcastUTXOTx({ chain, txHash }: { chain: Chain; txHash: string }) {
18
- // Use Blockchair's push transaction endpoint (no API key needed)
19
- const url = `${baseUrl(chain)}/push/transaction`;
20
- const body = JSON.stringify({ data: txHash });
21
-
22
- try {
23
- const response = await RequestClient.post<{
24
- data: { transaction_hash: string } | null;
25
- context: { code: number; error?: string };
26
- }>(url, { body, headers: { "Content-Type": "application/json" } });
27
-
28
- if (response.context.code !== 200) {
29
- throw new SwapKitError("toolbox_utxo_broadcast_failed", {
30
- error: response.context.error || "Transaction broadcast failed",
31
- });
32
- }
33
-
34
- return response.data?.transaction_hash || txHash;
35
- } catch (error) {
36
- // Fallback to RPC if Blockchair fails
37
- const rpcUrl = await getRPCUrl(chain);
38
- if (rpcUrl) {
39
- const rpcBody = JSON.stringify({ id: uniqid(), jsonrpc: "2.0", method: "sendrawtransaction", params: [txHash] });
40
-
41
- const rpcResponse = await RequestClient.post<{
42
- id: string;
43
- result: string;
44
- error: { message: string; code?: number } | null;
45
- }>(rpcUrl, { body: rpcBody, headers: { "Content-Type": "application/json" } });
46
-
47
- if (rpcResponse.error) {
48
- throw new SwapKitError("toolbox_utxo_broadcast_failed", { error: rpcResponse.error?.message });
49
- }
50
-
51
- if (rpcResponse.result.includes('"code":-26')) {
52
- throw new SwapKitError("toolbox_utxo_invalid_transaction", { error: "Transaction amount was too low" });
53
- }
54
-
55
- return rpcResponse.result;
56
- }
57
-
58
- throw error;
59
- }
60
- }
61
-
62
- function baseUrl(chain: Chain) {
63
- return `https://api.blockchair.com/${mapChainToBlockchairChain(chain)}`;
64
- }
65
-
66
- function getDefaultTxFeeByChain(chain: Chain) {
67
- switch (chain) {
68
- case Chain.Bitcoin:
69
- return 5;
70
- case Chain.Dogecoin:
71
- return 10000;
72
- case Chain.Litecoin:
73
- return 1;
74
- case Chain.Zcash:
75
- return 1;
76
- default:
77
- return 2;
78
- }
79
- }
80
-
81
- function mapChainToBlockchairChain(chain: Chain) {
82
- switch (chain) {
83
- case Chain.BitcoinCash:
84
- return "bitcoin-cash";
85
- case Chain.Litecoin:
86
- return "litecoin";
87
- case Chain.Dash:
88
- return "dash";
89
- case Chain.Dogecoin:
90
- return "dogecoin";
91
- case Chain.Zcash:
92
- return "zcash";
93
- case Chain.Polkadot:
94
- return "polkadot";
95
- default:
96
- return "bitcoin";
97
- }
98
- }
99
-
100
- async function getSuggestedTxFee(chain: Chain) {
101
- try {
102
- //Use Bitgo API for fee estimation
103
- //Refer: https://app.bitgo.com/docs/#operation/v2.tx.getfeeestimate
104
- const { feePerKb } = await RequestClient.get<{
105
- feePerKb: number;
106
- cpfpFeePerKb: number;
107
- numBlocks: number;
108
- feeByBlockTarget: { 1: number; 3: number };
109
- }>(`https://app.bitgo.com/api/v2/${chain.toLowerCase()}/tx/fee`);
110
- const suggestedFee = feePerKb / 1000;
111
-
112
- return Math.max(suggestedFee, getDefaultTxFeeByChain(chain));
113
- } catch {
114
- return getDefaultTxFeeByChain(chain);
115
- }
116
- }
117
-
118
- async function blockchairRequest<T>(url: string, apiKey?: string): Promise<T> {
119
- const response = await RequestClient.get<BlockchairResponse<T>>(
120
- `${url}${apiKey ? `${url.includes("?") ? "&" : "?"}key=${apiKey}` : ""}`,
121
- );
122
-
123
- if (!response || response.context.code !== 200)
124
- throw new SwapKitError("toolbox_utxo_api_error", { error: `Failed to query ${url}` });
125
-
126
- return response.data as T;
127
- }
128
-
129
- async function getAddressData({ address, chain, apiKey }: BlockchairParams<{ address?: string }>) {
130
- if (!address) throw new SwapKitError("toolbox_utxo_invalid_params", { error: "Address is required" });
131
-
132
- try {
133
- const response = await blockchairRequest<BlockchairAddressResponse>(
134
- `${baseUrl(chain)}/dashboards/address/${address}?transaction_details=true`,
135
- apiKey,
136
- );
137
-
138
- return response[address];
139
- } catch {
140
- return { address: { balance: 0, transaction_count: 0 }, utxo: [] };
141
- }
142
- }
143
-
144
- async function getUnconfirmedBalance({ address, chain, apiKey }: BlockchairParams<{ address?: string }>) {
145
- const response = await getAddressData({ address, apiKey, chain });
146
-
147
- return response?.address.balance || 0;
148
- }
149
-
150
- async function getRawTx({ chain, apiKey, txHash }: BlockchairParams<{ txHash?: string }>) {
151
- if (!txHash) throw new SwapKitError("toolbox_utxo_invalid_params", { error: "TxHash is required" });
152
-
153
- try {
154
- const rawTxResponse = await blockchairRequest<BlockchairRawTransactionResponse>(
155
- `${baseUrl(chain)}/raw/transaction/${txHash}`,
156
- apiKey,
157
- );
158
- return rawTxResponse?.[txHash]?.raw_transaction || "";
159
- } catch (error) {
160
- const errorMessage = error instanceof Error ? error.message : String(error);
161
- console.error(`Failed to fetch raw transaction: ${errorMessage}`);
162
- return "";
163
- }
164
- }
165
-
166
- async function fetchUtxosBatch({ chain, address, apiKey, offset = 0, limit = 30 }: BlockchairFetchUnspentUtxoParams) {
167
- // Only fetch the fields we need to reduce payload size
168
- const fields = "is_spent,transaction_hash,index,value,script_hex,block_id,spending_signature_hex";
169
-
170
- const response = await blockchairRequest<BlockchairOutputsResponse[]>(
171
- // TODO - remove max value limit once we updated bitcoinjs-lib to support larger values
172
- `${baseUrl(chain)}/outputs?q=recipient(${address}),is_spent(false),value(..2000000000000000)&s=value(desc)&fields=${fields}&limit=${limit}&offset=${offset}`,
173
- apiKey,
174
- );
175
-
176
- const txs = response.map(
177
- ({ is_spent, script_hex, block_id, transaction_hash, index, value, spending_signature_hex }) => ({
178
- hash: transaction_hash,
179
- index,
180
- is_confirmed: block_id !== -1,
181
- is_spent,
182
- script_hex,
183
- txHex: spending_signature_hex,
184
- value,
185
- }),
186
- );
187
-
188
- return txs;
189
- }
190
-
191
- function getTxsValue(txs: Awaited<ReturnType<typeof fetchUtxosBatch>>) {
192
- return txs.reduce((total, tx) => total + tx.value, 0);
193
- }
194
-
195
- function pickMostValuableTxs(
196
- txs: Awaited<ReturnType<typeof fetchUtxosBatch>>,
197
- targetValue?: number,
198
- ): Awaited<ReturnType<typeof fetchUtxosBatch>> {
199
- const sortedTxs = [...txs].sort((a, b) => b.value - a.value);
200
-
201
- if (targetValue) {
202
- const result = [];
203
- let accumulated = 0;
204
-
205
- for (const utxo of sortedTxs) {
206
- result.push(utxo);
207
- accumulated += utxo.value;
208
- if (accumulated >= targetValue) break;
209
- }
210
-
211
- return result;
212
- }
213
-
214
- return sortedTxs;
215
- }
216
-
217
- async function getUnspentUtxos({
218
- chain,
219
- address,
220
- apiKey,
221
- targetValue,
222
- accumulativeValue = 0,
223
- offset = 0,
224
- limit = 30,
225
- }: BlockchairFetchUnspentUtxoParams): Promise<Awaited<ReturnType<typeof fetchUtxosBatch>>> {
226
- if (!address) throw new SwapKitError("toolbox_utxo_invalid_params", { error: "Address is required" });
227
-
228
- try {
229
- const utxos = await fetchUtxosBatch({ address, apiKey, chain, limit, offset, targetValue });
230
- const utxosCount = utxos.length;
231
- const isComplete = utxosCount < limit;
232
-
233
- const unspentUtxos = utxos.filter(({ is_spent }) => !is_spent);
234
-
235
- const unspentUtxosValue = getTxsValue(unspentUtxos);
236
- const totalCurrentValue = accumulativeValue + unspentUtxosValue;
237
-
238
- const limitReached = targetValue && totalCurrentValue >= targetValue;
239
-
240
- if (isComplete || limitReached) {
241
- return pickMostValuableTxs(unspentUtxos, targetValue);
242
- }
243
-
244
- const nextBatch = await getUnspentUtxos({
245
- accumulativeValue: totalCurrentValue,
246
- address,
247
- apiKey,
248
- chain,
249
- limit,
250
- offset: offset + limit,
251
- targetValue,
252
- });
253
-
254
- const allUtxos = [...unspentUtxos, ...nextBatch];
255
-
256
- return pickMostValuableTxs(allUtxos, targetValue);
257
- } catch (error) {
258
- const errorMessage = error instanceof Error ? error.message : String(error);
259
- console.error(`Failed to fetch unspent UTXOs: ${errorMessage}`);
260
- return [];
261
- }
262
- }
263
-
264
- async function getUtxos({
265
- address,
266
- chain,
267
- apiKey,
268
- fetchTxHex = true,
269
- targetValue,
270
- }: BlockchairParams<{ address: string; fetchTxHex?: boolean; targetValue?: number }>) {
271
- const utxos = await getUnspentUtxos({ address, apiKey, chain, targetValue });
272
-
273
- const results = [];
274
-
275
- for (const { hash, index, script_hex, value } of utxos) {
276
- let txHex: string | undefined;
277
- if (fetchTxHex) {
278
- txHex = await getRawTx({ apiKey, chain, txHash: hash });
279
- }
280
- results.push({
281
- address,
282
- hash,
283
- index,
284
- txHex,
285
- value,
286
- witnessUtxo: { script: Buffer.from(script_hex, "hex"), value },
287
- });
288
- }
289
- return results;
290
- }
291
-
292
- export function getUtxoApi(chain: UTXOChain) {
293
- const apiKey = SKConfig.get("apiKeys").blockchair || "";
294
-
295
- warnOnce({
296
- condition: !apiKey,
297
- id: "no_blockchair_api_key_warning",
298
- warning: "No Blockchair API key found. Functionality will be limited.",
299
- });
300
-
301
- return {
302
- broadcastTx: (txHash: string) => broadcastUTXOTx({ chain, txHash }),
303
- getAddressData: (address: string) => getAddressData({ address, apiKey, chain }),
304
- getBalance: (address: string) => getUnconfirmedBalance({ address, apiKey, chain }),
305
- getRawTx: (txHash: string) => getRawTx({ apiKey, chain, txHash }),
306
- getSuggestedTxFee: () => getSuggestedTxFee(chain),
307
- getUtxos: (params: { address: string; fetchTxHex?: boolean; targetValue?: number }) =>
308
- getUtxos({ ...params, apiKey, chain }),
309
- };
310
- }
311
-
312
- /**
313
- * "Factory" to ensure typing for custom UTXO APIs
314
- */
315
- export function createCustomUtxoApi(methods: ReturnType<typeof getUtxoApi>) {
316
- return methods;
317
- }
318
-
319
- export function getUtxoNetwork() {
320
- return function getNetwork(chain: Chain) {
321
- switch (chain) {
322
- case Chain.Bitcoin:
323
- return networks.bitcoin;
324
- case Chain.BitcoinCash:
325
- return coininfo.bitcoincash.main.toBitcoinJS();
326
- case Chain.Dash:
327
- return coininfo.dash.main.toBitcoinJS();
328
- case Chain.Litecoin:
329
- return coininfo.litecoin.main.toBitcoinJS();
330
-
331
- case Chain.Dogecoin: {
332
- const bip32 = { private: 0x04358394, public: 0x043587cf };
333
- const test = coininfo.dogecoin.test;
334
- test.versions.bip32 = bip32;
335
- return coininfo.dogecoin.main.toBitcoinJS();
336
- }
337
-
338
- case Chain.Zcash: {
339
- return zcashNetworks.zcash;
340
- }
341
-
342
- default:
343
- throw new SwapKitError("toolbox_utxo_not_supported", { chain });
344
- }
345
- };
346
- }
347
-
348
- interface BlockchairVin {
349
- txid: string;
350
- vout: number;
351
- scriptSig: { asm: string; hex: string };
352
- sequence: number;
353
- }
354
-
355
- interface BlockchairVout {
356
- value: number;
357
- n: number;
358
- scriptPubKey: { asm: string; hex: string; address: string; type: string; addresses: string[]; reqSigs: number };
359
- }
360
-
361
- interface BlockchairTransaction {
362
- block_id: number;
363
- hash: string;
364
- time: string;
365
- balance_change: number;
366
- }
367
-
368
- interface BlockchairUtxo {
369
- block_id: number;
370
- transaction_hash: string;
371
- index: number;
372
- value: number;
373
- }
374
-
375
- interface BlockchairAddressCoreData {
376
- type: string;
377
- script_hex: string;
378
- balance: number;
379
- balance_usd: number;
380
- received: number;
381
- received_usd: number;
382
- spent: number;
383
- spent_usd: number;
384
- output_count: number;
385
- unspent_output_count: number;
386
- first_seen_receiving: string;
387
- last_seen_receiving: string;
388
- first_seen_spending: null | string;
389
- last_seen_spending: null | string;
390
- transaction_count: number;
391
- scripthash_type: null | string;
392
- }
393
-
394
- interface BlockchairInputOutputCommonData {
395
- block_id: number;
396
- transaction_id: number;
397
- index: number;
398
- transaction_hash: string;
399
- date: string;
400
- time: string;
401
- value: number;
402
- value_usd: number;
403
- recipient: string;
404
- type: string;
405
- script_hex: string;
406
- is_from_coinbase: boolean;
407
- is_spendable: boolean | null;
408
- is_spent: boolean;
409
- lifespan: number | null;
410
- cdd: number | null;
411
- }
412
-
413
- interface BlockchairSpendingBlockData {
414
- spending_block_id: number | null;
415
- spending_transaction_id: number | null;
416
- spending_index: number | null;
417
- spending_transaction_hash: string | null;
418
- spending_date: string | null;
419
- spending_time: string | null;
420
- spending_value_usd: number | null;
421
- spending_sequence: number | null;
422
- spending_signature_hex: string | null;
423
- spending_witness: string | null;
424
- }
425
-
426
- interface BlockchairAddressResponse {
427
- [key: string]: { address: BlockchairAddressCoreData; transactions: BlockchairTransaction[]; utxo: BlockchairUtxo[] };
428
- }
429
-
430
- interface BlockchairOutputsResponse extends BlockchairSpendingBlockData, BlockchairInputOutputCommonData {}
431
-
432
- interface BlockchairRawTransactionResponse {
433
- [key: string]: {
434
- raw_transaction: string;
435
- decoded_raw_transaction: {
436
- txid: string;
437
- hash: string;
438
- version: number;
439
- size: number;
440
- vsize: number;
441
- weight: number;
442
- locktime: number;
443
- vin: BlockchairVin[];
444
- vout: BlockchairVout[];
445
- };
446
- };
447
- }
448
-
449
- interface BlockchairResponse<T> {
450
- data: T;
451
- context: {
452
- code: number;
453
- source: string;
454
- results: number;
455
- state: number;
456
- market_price_usd: number;
457
- cache: { live: boolean; duration: number; since: string; until: string; time: any };
458
- api: {
459
- version: string;
460
- last_major_update: string;
461
- next_major_update: null | string;
462
- documentation: string;
463
- notice: string;
464
- };
465
- servers: string;
466
- time: number;
467
- render_time: number;
468
- full_time: number;
469
- request_cost: number;
470
- };
471
- }