@uswap/toolboxes 4.3.6

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 (275) hide show
  1. package/dist/src/cardano/index.cjs +4 -0
  2. package/dist/src/cardano/index.cjs.map +11 -0
  3. package/dist/src/cardano/index.js +4 -0
  4. package/dist/src/cardano/index.js.map +11 -0
  5. package/dist/src/cosmos/index.cjs +4 -0
  6. package/dist/src/cosmos/index.cjs.map +20 -0
  7. package/dist/src/cosmos/index.js +4 -0
  8. package/dist/src/cosmos/index.js.map +20 -0
  9. package/dist/src/evm/index.cjs +4 -0
  10. package/dist/src/evm/index.cjs.map +20 -0
  11. package/dist/src/evm/index.js +4 -0
  12. package/dist/src/evm/index.js.map +20 -0
  13. package/dist/src/index.cjs +5 -0
  14. package/dist/src/index.cjs.map +67 -0
  15. package/dist/src/index.js +5 -0
  16. package/dist/src/index.js.map +67 -0
  17. package/dist/src/near/index.cjs +4 -0
  18. package/dist/src/near/index.cjs.map +16 -0
  19. package/dist/src/near/index.js +4 -0
  20. package/dist/src/near/index.js.map +16 -0
  21. package/dist/src/radix/index.cjs +4 -0
  22. package/dist/src/radix/index.cjs.map +10 -0
  23. package/dist/src/radix/index.js +4 -0
  24. package/dist/src/radix/index.js.map +10 -0
  25. package/dist/src/ripple/index.cjs +4 -0
  26. package/dist/src/ripple/index.cjs.map +10 -0
  27. package/dist/src/ripple/index.js +4 -0
  28. package/dist/src/ripple/index.js.map +10 -0
  29. package/dist/src/solana/index.cjs +4 -0
  30. package/dist/src/solana/index.cjs.map +11 -0
  31. package/dist/src/solana/index.js +4 -0
  32. package/dist/src/solana/index.js.map +11 -0
  33. package/dist/src/substrate/index.cjs +4 -0
  34. package/dist/src/substrate/index.cjs.map +13 -0
  35. package/dist/src/substrate/index.js +4 -0
  36. package/dist/src/substrate/index.js.map +13 -0
  37. package/dist/src/sui/index.cjs +4 -0
  38. package/dist/src/sui/index.cjs.map +11 -0
  39. package/dist/src/sui/index.js +4 -0
  40. package/dist/src/sui/index.js.map +11 -0
  41. package/dist/src/ton/index.cjs +4 -0
  42. package/dist/src/ton/index.cjs.map +11 -0
  43. package/dist/src/ton/index.js +4 -0
  44. package/dist/src/ton/index.js.map +11 -0
  45. package/dist/src/tron/index.cjs +4 -0
  46. package/dist/src/tron/index.cjs.map +13 -0
  47. package/dist/src/tron/index.js +4 -0
  48. package/dist/src/tron/index.js.map +13 -0
  49. package/dist/src/utxo/index.cjs +5 -0
  50. package/dist/src/utxo/index.cjs.map +21 -0
  51. package/dist/src/utxo/index.js +5 -0
  52. package/dist/src/utxo/index.js.map +21 -0
  53. package/dist/types/cardano/index.d.ts +3 -0
  54. package/dist/types/cardano/index.d.ts.map +1 -0
  55. package/dist/types/cardano/toolbox.d.ts +34 -0
  56. package/dist/types/cardano/toolbox.d.ts.map +1 -0
  57. package/dist/types/cardano/types.d.ts +11 -0
  58. package/dist/types/cardano/types.d.ts.map +1 -0
  59. package/dist/types/cosmos/index.d.ts +5 -0
  60. package/dist/types/cosmos/index.d.ts.map +1 -0
  61. package/dist/types/cosmos/thorchainUtils/addressFormat.d.ts +5 -0
  62. package/dist/types/cosmos/thorchainUtils/addressFormat.d.ts.map +1 -0
  63. package/dist/types/cosmos/thorchainUtils/index.d.ts +5 -0
  64. package/dist/types/cosmos/thorchainUtils/index.d.ts.map +1 -0
  65. package/dist/types/cosmos/thorchainUtils/messages.d.ts +208 -0
  66. package/dist/types/cosmos/thorchainUtils/messages.d.ts.map +1 -0
  67. package/dist/types/cosmos/thorchainUtils/registry.d.ts +4 -0
  68. package/dist/types/cosmos/thorchainUtils/registry.d.ts.map +1 -0
  69. package/dist/types/cosmos/thorchainUtils/types/MsgCompiled.d.ts +2 -0
  70. package/dist/types/cosmos/thorchainUtils/types/MsgCompiled.d.ts.map +1 -0
  71. package/dist/types/cosmos/thorchainUtils/types/client-types.d.ts +63 -0
  72. package/dist/types/cosmos/thorchainUtils/types/client-types.d.ts.map +1 -0
  73. package/dist/types/cosmos/thorchainUtils/types/index.d.ts +2 -0
  74. package/dist/types/cosmos/thorchainUtils/types/index.d.ts.map +1 -0
  75. package/dist/types/cosmos/toolbox/cosmos.d.ts +62 -0
  76. package/dist/types/cosmos/toolbox/cosmos.d.ts.map +1 -0
  77. package/dist/types/cosmos/toolbox/index.d.ts +15 -0
  78. package/dist/types/cosmos/toolbox/index.d.ts.map +1 -0
  79. package/dist/types/cosmos/toolbox/thorchain.d.ts +158 -0
  80. package/dist/types/cosmos/toolbox/thorchain.d.ts.map +1 -0
  81. package/dist/types/cosmos/types.d.ts +49 -0
  82. package/dist/types/cosmos/types.d.ts.map +1 -0
  83. package/dist/types/cosmos/util.d.ts +74 -0
  84. package/dist/types/cosmos/util.d.ts.map +1 -0
  85. package/dist/types/evm/api.d.ts +8 -0
  86. package/dist/types/evm/api.d.ts.map +1 -0
  87. package/dist/types/evm/contracts/eth/multicall.d.ts +36 -0
  88. package/dist/types/evm/contracts/eth/multicall.d.ts.map +1 -0
  89. package/dist/types/evm/contracts/op/gasOracle.d.ts +40 -0
  90. package/dist/types/evm/contracts/op/gasOracle.d.ts.map +1 -0
  91. package/dist/types/evm/helpers.d.ts +6 -0
  92. package/dist/types/evm/helpers.d.ts.map +1 -0
  93. package/dist/types/evm/index.d.ts +5 -0
  94. package/dist/types/evm/index.d.ts.map +1 -0
  95. package/dist/types/evm/toolbox/baseEVMToolbox.d.ts +83 -0
  96. package/dist/types/evm/toolbox/baseEVMToolbox.d.ts.map +1 -0
  97. package/dist/types/evm/toolbox/evm.d.ts +767 -0
  98. package/dist/types/evm/toolbox/evm.d.ts.map +1 -0
  99. package/dist/types/evm/toolbox/index.d.ts +7 -0
  100. package/dist/types/evm/toolbox/index.d.ts.map +1 -0
  101. package/dist/types/evm/toolbox/op.d.ts +76 -0
  102. package/dist/types/evm/toolbox/op.d.ts.map +1 -0
  103. package/dist/types/evm/types.d.ts +108 -0
  104. package/dist/types/evm/types.d.ts.map +1 -0
  105. package/dist/types/index.d.ts +75 -0
  106. package/dist/types/index.d.ts.map +1 -0
  107. package/dist/types/near/helpers/core.d.ts +15 -0
  108. package/dist/types/near/helpers/core.d.ts.map +1 -0
  109. package/dist/types/near/helpers/gasEstimation.d.ts +41 -0
  110. package/dist/types/near/helpers/gasEstimation.d.ts.map +1 -0
  111. package/dist/types/near/helpers/nep141.d.ts +36 -0
  112. package/dist/types/near/helpers/nep141.d.ts.map +1 -0
  113. package/dist/types/near/index.d.ts +10 -0
  114. package/dist/types/near/index.d.ts.map +1 -0
  115. package/dist/types/near/toolbox.d.ts +32 -0
  116. package/dist/types/near/toolbox.d.ts.map +1 -0
  117. package/dist/types/near/types/contract.d.ts +38 -0
  118. package/dist/types/near/types/contract.d.ts.map +1 -0
  119. package/dist/types/near/types/nep141.d.ts +29 -0
  120. package/dist/types/near/types/nep141.d.ts.map +1 -0
  121. package/dist/types/near/types/toolbox.d.ts +51 -0
  122. package/dist/types/near/types/toolbox.d.ts.map +1 -0
  123. package/dist/types/near/types.d.ts +47 -0
  124. package/dist/types/near/types.d.ts.map +1 -0
  125. package/dist/types/radix/index.d.ts +14 -0
  126. package/dist/types/radix/index.d.ts.map +1 -0
  127. package/dist/types/ripple/index.d.ts +46 -0
  128. package/dist/types/ripple/index.d.ts.map +1 -0
  129. package/dist/types/solana/index.d.ts +23 -0
  130. package/dist/types/solana/index.d.ts.map +1 -0
  131. package/dist/types/solana/toolbox.d.ts +51 -0
  132. package/dist/types/solana/toolbox.d.ts.map +1 -0
  133. package/dist/types/substrate/balance.d.ts +17 -0
  134. package/dist/types/substrate/balance.d.ts.map +1 -0
  135. package/dist/types/substrate/index.d.ts +3 -0
  136. package/dist/types/substrate/index.d.ts.map +1 -0
  137. package/dist/types/substrate/substrate.d.ts +148 -0
  138. package/dist/types/substrate/substrate.d.ts.map +1 -0
  139. package/dist/types/substrate/types.d.ts +100 -0
  140. package/dist/types/substrate/types.d.ts.map +1 -0
  141. package/dist/types/sui/index.d.ts +3 -0
  142. package/dist/types/sui/index.d.ts.map +1 -0
  143. package/dist/types/sui/toolbox.d.ts +19 -0
  144. package/dist/types/sui/toolbox.d.ts.map +1 -0
  145. package/dist/types/sui/types.d.ts +16 -0
  146. package/dist/types/sui/types.d.ts.map +1 -0
  147. package/dist/types/ton/index.d.ts +3 -0
  148. package/dist/types/ton/index.d.ts.map +1 -0
  149. package/dist/types/ton/toolbox.d.ts +14 -0
  150. package/dist/types/ton/toolbox.d.ts.map +1 -0
  151. package/dist/types/ton/types.d.ts +22 -0
  152. package/dist/types/ton/types.d.ts.map +1 -0
  153. package/dist/types/tron/helpers/trc20.abi.d.ts +156 -0
  154. package/dist/types/tron/helpers/trc20.abi.d.ts.map +1 -0
  155. package/dist/types/tron/helpers/trongrid.d.ts +8 -0
  156. package/dist/types/tron/helpers/trongrid.d.ts.map +1 -0
  157. package/dist/types/tron/index.d.ts +6 -0
  158. package/dist/types/tron/index.d.ts.map +1 -0
  159. package/dist/types/tron/toolbox.d.ts +26 -0
  160. package/dist/types/tron/toolbox.d.ts.map +1 -0
  161. package/dist/types/tron/types.d.ts +103 -0
  162. package/dist/types/tron/types.d.ts.map +1 -0
  163. package/dist/types/types.d.ts +26 -0
  164. package/dist/types/types.d.ts.map +1 -0
  165. package/dist/types/utils.d.ts +4 -0
  166. package/dist/types/utils.d.ts.map +1 -0
  167. package/dist/types/utxo/helpers/api.d.ts +101 -0
  168. package/dist/types/utxo/helpers/api.d.ts.map +1 -0
  169. package/dist/types/utxo/helpers/bchaddrjs.d.ts +10 -0
  170. package/dist/types/utxo/helpers/bchaddrjs.d.ts.map +1 -0
  171. package/dist/types/utxo/helpers/coinselect.d.ts +17 -0
  172. package/dist/types/utxo/helpers/coinselect.d.ts.map +1 -0
  173. package/dist/types/utxo/helpers/index.d.ts +5 -0
  174. package/dist/types/utxo/helpers/index.d.ts.map +1 -0
  175. package/dist/types/utxo/helpers/txSize.d.ts +21 -0
  176. package/dist/types/utxo/helpers/txSize.d.ts.map +1 -0
  177. package/dist/types/utxo/index.d.ts +7 -0
  178. package/dist/types/utxo/index.d.ts.map +1 -0
  179. package/dist/types/utxo/toolbox/bitcoinCash.d.ts +93 -0
  180. package/dist/types/utxo/toolbox/bitcoinCash.d.ts.map +1 -0
  181. package/dist/types/utxo/toolbox/index.d.ts +28 -0
  182. package/dist/types/utxo/toolbox/index.d.ts.map +1 -0
  183. package/dist/types/utxo/toolbox/params.d.ts +32 -0
  184. package/dist/types/utxo/toolbox/params.d.ts.map +1 -0
  185. package/dist/types/utxo/toolbox/utxo.d.ts +103 -0
  186. package/dist/types/utxo/toolbox/utxo.d.ts.map +1 -0
  187. package/dist/types/utxo/toolbox/validators.d.ts +4 -0
  188. package/dist/types/utxo/toolbox/validators.d.ts.map +1 -0
  189. package/dist/types/utxo/toolbox/zcash.d.ts +72 -0
  190. package/dist/types/utxo/toolbox/zcash.d.ts.map +1 -0
  191. package/dist/types/utxo/types.d.ts +46 -0
  192. package/dist/types/utxo/types.d.ts.map +1 -0
  193. package/package.json +205 -0
  194. package/src/__tests__/address-validation-all-chains.test.ts +162 -0
  195. package/src/__tests__/addressValidator.test.ts +162 -0
  196. package/src/cardano/__tests__/toolbox.test.ts +48 -0
  197. package/src/cardano/index.ts +2 -0
  198. package/src/cardano/toolbox.ts +168 -0
  199. package/src/cardano/types.ts +10 -0
  200. package/src/cosmos/__tests__/toolbox.test.ts +91 -0
  201. package/src/cosmos/index.ts +4 -0
  202. package/src/cosmos/thorchainUtils/addressFormat.ts +22 -0
  203. package/src/cosmos/thorchainUtils/index.ts +4 -0
  204. package/src/cosmos/thorchainUtils/messages.ts +212 -0
  205. package/src/cosmos/thorchainUtils/registry.ts +43 -0
  206. package/src/cosmos/thorchainUtils/types/MsgCompiled.ts +2800 -0
  207. package/src/cosmos/thorchainUtils/types/client-types.ts +54 -0
  208. package/src/cosmos/thorchainUtils/types/index.ts +1 -0
  209. package/src/cosmos/toolbox/cosmos.ts +345 -0
  210. package/src/cosmos/toolbox/index.ts +35 -0
  211. package/src/cosmos/toolbox/thorchain.ts +249 -0
  212. package/src/cosmos/types.ts +48 -0
  213. package/src/cosmos/util.ts +214 -0
  214. package/src/evm/__tests__/address-validation.test.ts +84 -0
  215. package/src/evm/__tests__/ethereum.test.ts +137 -0
  216. package/src/evm/__tests__/signMessage.test.ts +60 -0
  217. package/src/evm/api.ts +10 -0
  218. package/src/evm/contracts/eth/multicall.ts +165 -0
  219. package/src/evm/contracts/op/gasOracle.ts +145 -0
  220. package/src/evm/helpers.ts +73 -0
  221. package/src/evm/index.ts +4 -0
  222. package/src/evm/toolbox/baseEVMToolbox.ts +695 -0
  223. package/src/evm/toolbox/evm.ts +67 -0
  224. package/src/evm/toolbox/index.ts +44 -0
  225. package/src/evm/toolbox/op.ts +156 -0
  226. package/src/evm/types.ts +146 -0
  227. package/src/index.ts +260 -0
  228. package/src/near/__tests__/core.test.ts +70 -0
  229. package/src/near/helpers/core.ts +85 -0
  230. package/src/near/helpers/gasEstimation.ts +96 -0
  231. package/src/near/helpers/nep141.ts +50 -0
  232. package/src/near/index.ts +21 -0
  233. package/src/near/toolbox.ts +421 -0
  234. package/src/near/types/contract.ts +32 -0
  235. package/src/near/types/nep141.ts +34 -0
  236. package/src/near/types/toolbox.ts +55 -0
  237. package/src/near/types.ts +44 -0
  238. package/src/radix/index.ts +132 -0
  239. package/src/ripple/index.ts +179 -0
  240. package/src/solana/index.ts +36 -0
  241. package/src/solana/toolbox.ts +415 -0
  242. package/src/substrate/balance.ts +88 -0
  243. package/src/substrate/index.ts +2 -0
  244. package/src/substrate/substrate.ts +281 -0
  245. package/src/substrate/types.ts +115 -0
  246. package/src/sui/__tests__/toolbox.test.ts +82 -0
  247. package/src/sui/index.ts +2 -0
  248. package/src/sui/toolbox.ts +165 -0
  249. package/src/sui/types.ts +11 -0
  250. package/src/ton/__tests__/toolbox.test.ts +63 -0
  251. package/src/ton/index.ts +2 -0
  252. package/src/ton/toolbox.ts +136 -0
  253. package/src/ton/types.ts +13 -0
  254. package/src/tron/__tests__/toolbox.test.ts +221 -0
  255. package/src/tron/helpers/trc20.abi.ts +107 -0
  256. package/src/tron/helpers/trongrid.ts +53 -0
  257. package/src/tron/index.ts +21 -0
  258. package/src/tron/toolbox.ts +585 -0
  259. package/src/tron/types.ts +83 -0
  260. package/src/types.ts +28 -0
  261. package/src/utils.ts +27 -0
  262. package/src/utxo/__tests__/zcash-integration.test.ts +97 -0
  263. package/src/utxo/helpers/api.ts +471 -0
  264. package/src/utxo/helpers/bchaddrjs.ts +166 -0
  265. package/src/utxo/helpers/coinselect.ts +92 -0
  266. package/src/utxo/helpers/index.ts +4 -0
  267. package/src/utxo/helpers/txSize.ts +137 -0
  268. package/src/utxo/index.ts +6 -0
  269. package/src/utxo/toolbox/bitcoinCash.ts +243 -0
  270. package/src/utxo/toolbox/index.ts +59 -0
  271. package/src/utxo/toolbox/params.ts +18 -0
  272. package/src/utxo/toolbox/utxo.ts +439 -0
  273. package/src/utxo/toolbox/validators.ts +36 -0
  274. package/src/utxo/toolbox/zcash.ts +245 -0
  275. package/src/utxo/types.ts +39 -0
@@ -0,0 +1,166 @@
1
+ import { SwapKitError } from "@uswap/helpers";
2
+ import base58check from "bs58check";
3
+ // @ts-expect-error
4
+ import cashaddr from "cashaddrjs";
5
+
6
+ enum Format {
7
+ Legacy = "legacy",
8
+ Bitpay = "bitpay",
9
+ Cashaddr = "cashaddr",
10
+ }
11
+ enum UtxoNetwork {
12
+ Mainnet = "mainnet",
13
+ Testnet = "testnet",
14
+ }
15
+ enum Type {
16
+ P2PKH = "p2pkh",
17
+ P2SH = "p2sh",
18
+ }
19
+
20
+ const VERSION_BYTE = {
21
+ [Format.Legacy]: {
22
+ [UtxoNetwork.Mainnet]: { [Type.P2PKH]: 0, [Type.P2SH]: 5 },
23
+ [UtxoNetwork.Testnet]: { [Type.P2PKH]: 111, [Type.P2SH]: 196 },
24
+ },
25
+ [Format.Bitpay]: {
26
+ [UtxoNetwork.Mainnet]: { [Type.P2PKH]: 28, [Type.P2SH]: 40 },
27
+ [UtxoNetwork.Testnet]: { [Type.P2PKH]: 111, [Type.P2SH]: 196 },
28
+ },
29
+ };
30
+
31
+ type DecodedType = { format: Format; network: UtxoNetwork; type: Type; hash: any };
32
+
33
+ function isValidAddress(input: any) {
34
+ try {
35
+ decodeAddress(input);
36
+ return true;
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
41
+
42
+ function detectAddressNetwork(address: string) {
43
+ return decodeAddress(address)?.network;
44
+ }
45
+
46
+ function toLegacyAddress(address: string): string {
47
+ const decoded = decodeAddress(address);
48
+ if (decoded?.format === Format.Legacy) {
49
+ return address;
50
+ }
51
+ return encodeAsLegacy(decoded);
52
+ }
53
+
54
+ function toCashAddress(address: string): string {
55
+ const decoded = decodeAddress(address);
56
+ return encodeAsCashaddr(decoded);
57
+ }
58
+
59
+ function decodeAddress(address: string) {
60
+ try {
61
+ const decoded = decodeBase58Address(address);
62
+ if (decoded) {
63
+ return decoded;
64
+ }
65
+ } catch {
66
+ // Try to decode as cashaddr if base58 decoding fails.
67
+ }
68
+ try {
69
+ const decoded = decodeCashAddress(address);
70
+ if (decoded) {
71
+ return decoded;
72
+ }
73
+ } catch {
74
+ // Try to decode as bitpay if cashaddr decoding fails.
75
+ }
76
+ throw new SwapKitError("toolbox_utxo_invalid_address", { address });
77
+ }
78
+
79
+ function decodeBase58Address(address: string) {
80
+ try {
81
+ const payload = base58check.decode(address);
82
+
83
+ // BASE_58_CHECK_PAYLOAD_LENGTH
84
+ if (payload.length !== 21) throw new SwapKitError("toolbox_utxo_invalid_address", { address });
85
+ const versionByte = payload[0];
86
+ const hash = Array.prototype.slice.call(payload, 1);
87
+
88
+ switch (versionByte) {
89
+ case VERSION_BYTE[Format.Legacy][UtxoNetwork.Mainnet][Type.P2PKH]:
90
+ return { format: Format.Legacy, hash, network: UtxoNetwork.Mainnet, type: Type.P2PKH };
91
+
92
+ case VERSION_BYTE[Format.Legacy][UtxoNetwork.Mainnet][Type.P2SH]:
93
+ return { format: Format.Legacy, hash, network: UtxoNetwork.Mainnet, type: Type.P2SH };
94
+
95
+ case VERSION_BYTE[Format.Legacy][UtxoNetwork.Testnet][Type.P2PKH]:
96
+ return { format: Format.Legacy, hash, network: UtxoNetwork.Testnet, type: Type.P2PKH };
97
+
98
+ case VERSION_BYTE[Format.Legacy][UtxoNetwork.Testnet][Type.P2SH]:
99
+ return { format: Format.Legacy, hash, network: UtxoNetwork.Testnet, type: Type.P2SH };
100
+
101
+ case VERSION_BYTE[Format.Bitpay][UtxoNetwork.Mainnet][Type.P2PKH]:
102
+ return { format: Format.Bitpay, hash, network: UtxoNetwork.Mainnet, type: Type.P2PKH };
103
+
104
+ case VERSION_BYTE[Format.Bitpay][UtxoNetwork.Mainnet][Type.P2SH]:
105
+ return { format: Format.Bitpay, hash, network: UtxoNetwork.Mainnet, type: Type.P2SH };
106
+
107
+ default:
108
+ return;
109
+ }
110
+ } catch {
111
+ return;
112
+ }
113
+ }
114
+
115
+ function decodeCashAddress(address: string) {
116
+ if (address.indexOf(":") !== -1) {
117
+ try {
118
+ return decodeCashAddressWithPrefix(address);
119
+ } catch {
120
+ // Try to decode as legacy if cashaddr decoding fails.
121
+ }
122
+ } else {
123
+ const prefixes = ["bitcoincash", "bchtest", "bchreg"];
124
+ for (const prefix of prefixes) {
125
+ try {
126
+ return decodeCashAddressWithPrefix(`${prefix}:${address}`);
127
+ } catch {
128
+ // Try next prefix if decoding fails.
129
+ }
130
+ }
131
+ }
132
+
133
+ return;
134
+ }
135
+
136
+ function decodeCashAddressWithPrefix(address: string) {
137
+ try {
138
+ const { hash, prefix, type } = cashaddr.decode(address);
139
+
140
+ return {
141
+ format: Format.Cashaddr,
142
+ hash: Array.prototype.slice.call(hash, 0),
143
+ network: prefix === "bitcoincash" ? UtxoNetwork.Mainnet : UtxoNetwork.Testnet,
144
+ type: type === "P2PKH" ? Type.P2PKH : Type.P2SH,
145
+ };
146
+ } catch {
147
+ return;
148
+ }
149
+ }
150
+
151
+ function encodeAsLegacy(decoded: DecodedType) {
152
+ const versionByte = VERSION_BYTE[Format.Legacy][decoded.network][decoded.type];
153
+ const buffer = Buffer.alloc(1 + decoded.hash.length);
154
+ buffer[0] = versionByte;
155
+ buffer.set(decoded.hash, 1);
156
+ return base58check.encode(buffer);
157
+ }
158
+
159
+ function encodeAsCashaddr(decoded: DecodedType) {
160
+ const prefix = decoded.network === UtxoNetwork.Mainnet ? "bitcoincash" : "bchtest";
161
+ const type = decoded.type === Type.P2PKH ? "P2PKH" : "P2SH";
162
+ const hash = new Uint8Array(decoded.hash);
163
+ return cashaddr.encode(prefix, type, hash);
164
+ }
165
+
166
+ export { detectAddressNetwork, isValidAddress, UtxoNetwork, toCashAddress, toLegacyAddress };
@@ -0,0 +1,92 @@
1
+ import { Chain, SwapKitError, type UTXOChain } from "@uswap/helpers";
2
+
3
+ import {
4
+ calculateTxSize,
5
+ getInputSize,
6
+ getOutputSize,
7
+ getScriptTypeForAddress,
8
+ TX_OVERHEAD,
9
+ UTXOScriptType,
10
+ } from "../helpers/txSize";
11
+ import type { TargetOutput, UTXOCalculateTxSizeParams, UTXOType } from "../types";
12
+
13
+ export function getDustThreshold(chain: UTXOChain) {
14
+ switch (chain) {
15
+ case Chain.Bitcoin:
16
+ case Chain.BitcoinCash:
17
+ return 550;
18
+ case Chain.Dash:
19
+ case Chain.Litecoin:
20
+ return 5500;
21
+ case Chain.Dogecoin:
22
+ return 100000;
23
+ case Chain.Zcash:
24
+ return 546;
25
+ default:
26
+ throw new SwapKitError("toolbox_utxo_not_supported", { chain });
27
+ }
28
+ }
29
+
30
+ export function accumulative({
31
+ inputs,
32
+ outputs,
33
+ feeRate: initialFeeRate = 1,
34
+ chain = Chain.Bitcoin,
35
+ changeAddress = "",
36
+ }: UTXOCalculateTxSizeParams & { outputs: TargetOutput[]; chain: UTXOChain; changeAddress?: string }) {
37
+ const feeRate = Math.ceil(initialFeeRate);
38
+
39
+ const newTxType =
40
+ inputs[0] && "address" in inputs[0] && inputs[0].address
41
+ ? getScriptTypeForAddress(inputs[0].address)
42
+ : UTXOScriptType.P2PKH;
43
+ // skip input if adding it would cost more than input is worth
44
+ const filteredInputs = inputs.filter((input) => getInputSize(input) * feeRate <= input.value);
45
+
46
+ const txSizeWithoutInputs =
47
+ TX_OVERHEAD + outputs.reduce((total, output) => total + getOutputSize(output, newTxType), 0);
48
+
49
+ const amountToSend = outputs.reduce((total, output) => total + output.value, 0);
50
+
51
+ let fees = txSizeWithoutInputs * feeRate;
52
+ let inputsValue = 0;
53
+ const inputsToUse: typeof inputs = [];
54
+
55
+ for (const input of filteredInputs) {
56
+ const inputSize = getInputSize(input);
57
+ const inputFee = feeRate * inputSize;
58
+
59
+ fees += inputFee;
60
+ inputsValue += input.value;
61
+
62
+ inputsToUse.push(input);
63
+
64
+ const totalCost = fees + amountToSend;
65
+
66
+ // we need more inputs
67
+ if (inputsValue < totalCost) continue;
68
+
69
+ const remainder = inputsValue - totalCost;
70
+
71
+ const feeForExtraOutput = feeRate * getOutputSize({ address: "", value: 0 }, newTxType);
72
+
73
+ // potential change address
74
+ if (remainder > feeForExtraOutput) {
75
+ const feeAfterExtraOutput = feeForExtraOutput + fees;
76
+ const remainderAfterExtraOutput = inputsValue - (amountToSend + feeAfterExtraOutput);
77
+
78
+ // is it worth a change output aka can we send it in the future?
79
+ if (remainderAfterExtraOutput > Math.max(getInputSize({} as UTXOType) * feeRate, getDustThreshold(chain))) {
80
+ return {
81
+ fee: feeAfterExtraOutput,
82
+ inputs: inputsToUse,
83
+ outputs: outputs.concat({ address: changeAddress, value: remainderAfterExtraOutput }),
84
+ };
85
+ }
86
+ }
87
+ return { fee: fees, inputs: inputsToUse, outputs };
88
+ }
89
+
90
+ // We don't have enough inputs, let's calculate transaction fee accrude to the last input
91
+ return { fee: feeRate * calculateTxSize({ feeRate, inputs, outputs }) };
92
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./api";
2
+ export * from "./bchaddrjs";
3
+ export * from "./coinselect";
4
+ export * from "./txSize";
@@ -0,0 +1,137 @@
1
+ import { SwapKitError } from "@uswap/helpers";
2
+ import { opcodes, script } from "bitcoinjs-lib";
3
+ import type { TargetOutput, UTXOCalculateTxSizeParams, UTXOInputWithScriptType, UTXOType } from "../types";
4
+
5
+ /**
6
+ * Minimum transaction fee
7
+ * 1000 satoshi/kB (similar to current `minrelaytxfee`)
8
+ * @see https://github.com/bitcoin/bitcoin/blob/db88db47278d2e7208c50d16ab10cb355067d071/src/validation.h#L56
9
+ */
10
+ export const MIN_TX_FEE = 1000;
11
+ export const TX_OVERHEAD = 4 + 1 + 1 + 4; //10
12
+ export const OP_RETURN_OVERHEAD = 1 + 8 + 1; //10
13
+ const TX_INPUT_BASE = 32 + 4 + 1 + 4; // 41
14
+ const TX_INPUT_PUBKEYHASH = 107;
15
+
16
+ export function compileMemo(memo: string) {
17
+ const data = Buffer.from(memo, "utf8"); // converts MEMO to buffer
18
+ return script.compile([opcodes.OP_RETURN as number, data]); // Compile OP_RETURN script
19
+ }
20
+
21
+ export enum UTXOScriptType {
22
+ P2PKH = "P2PKH", // legacy
23
+ // P2SH = 'P2SH', // multisig
24
+ P2WPKH = "P2WPKH", // bech32 - native segwit
25
+ // P2TR = "P2TR", // taproot
26
+ }
27
+
28
+ export const InputSizes: Record<UTXOScriptType, number> = {
29
+ [UTXOScriptType.P2PKH]: 148,
30
+ // [UTXOScriptType.P2SH]: 91,
31
+ [UTXOScriptType.P2WPKH]: 68,
32
+ };
33
+
34
+ export const OutputSizes: Record<UTXOScriptType, number> = {
35
+ [UTXOScriptType.P2PKH]: 34,
36
+ // [UTXOScriptType.P2SH]: 91,
37
+ [UTXOScriptType.P2WPKH]: 31,
38
+ };
39
+
40
+ export const getScriptTypeForAddress = (address: string) => {
41
+ // Native SegWit (Bech32) addresses - P2WPKH
42
+ // Bitcoin: bc1 (mainnet), tb1 (testnet)
43
+ // Litecoin: ltc1 (mainnet), tltc1 (testnet)
44
+ if (
45
+ address.startsWith("bc1") ||
46
+ address.startsWith("tb1") ||
47
+ address.startsWith("ltc1") ||
48
+ address.startsWith("tltc1")
49
+ ) {
50
+ // Note: bc1p/tb1p are Taproot (P2TR) addresses, but we're treating them as P2WPKH for now
51
+ // since P2TR is not yet implemented
52
+ return UTXOScriptType.P2WPKH;
53
+ }
54
+
55
+ // P2SH addresses (Pay-to-Script-Hash) - Currently commented out but kept for future use
56
+ // Bitcoin: 3 (mainnet), 2 (testnet)
57
+ // Litecoin: M or 2 (mainnet), Q (testnet)
58
+ // Dash: 7 (mainnet)
59
+ // if (address.startsWith('3') || address.startsWith('2') ||
60
+ // address.startsWith('M') || address.startsWith('Q') ||
61
+ // address.startsWith('7')) {
62
+ // return UTXOScriptType.P2SH;
63
+ // }
64
+
65
+ // Legacy P2PKH addresses
66
+ // Bitcoin: 1 (mainnet), m/n (testnet)
67
+ // Bitcoin Cash: bitcoincash:q (CashAddr format), q (legacy), 1 (legacy)
68
+ // Litecoin: L (mainnet), m/n (testnet)
69
+ // Dogecoin: D (mainnet), n (testnet)
70
+ // Dash: X (mainnet), y (testnet)
71
+ // Zcash: t1 (transparent mainnet), tm (testnet)
72
+ if (
73
+ // Bitcoin legacy
74
+ address.startsWith("1") ||
75
+ address.startsWith("m") ||
76
+ address.startsWith("n") ||
77
+ // Bitcoin Cash
78
+ address.startsWith("bitcoincash:q") ||
79
+ address.startsWith("bitcoincash:p") ||
80
+ address.startsWith("q") ||
81
+ address.startsWith("p") ||
82
+ // Litecoin legacy (also uses 3 for P2SH but treating as P2PKH for now)
83
+ address.startsWith("L") ||
84
+ address.startsWith("M") ||
85
+ address.startsWith("3") ||
86
+ // Dogecoin
87
+ address.startsWith("D") ||
88
+ address.startsWith("A") ||
89
+ address.startsWith("9") ||
90
+ // Dash
91
+ address.startsWith("X") ||
92
+ address.startsWith("7") ||
93
+ address.startsWith("y") ||
94
+ // Zcash transparent addresses
95
+ address.startsWith("t1") ||
96
+ address.startsWith("t3") ||
97
+ address.startsWith("tm")
98
+ ) {
99
+ return UTXOScriptType.P2PKH;
100
+ }
101
+
102
+ throw new SwapKitError("toolbox_utxo_invalid_address", { address });
103
+ };
104
+
105
+ export const calculateTxSize = ({ inputs, outputs, feeRate }: UTXOCalculateTxSizeParams) => {
106
+ const newTxType =
107
+ inputs[0] && "address" in inputs[0] && inputs[0].address
108
+ ? getScriptTypeForAddress(inputs[0].address)
109
+ : UTXOScriptType.P2PKH;
110
+ const inputSize = inputs
111
+ .filter((utxo) => utxo.value >= InputSizes["type" in utxo ? utxo.type : UTXOScriptType.P2PKH] * Math.ceil(feeRate))
112
+ .reduce((total, utxo) => total + getInputSize(utxo), 0);
113
+
114
+ const outputSize = outputs?.reduce((total, output) => total + getOutputSize(output), 0) || OutputSizes[newTxType];
115
+
116
+ return TX_OVERHEAD + inputSize + outputSize;
117
+ };
118
+
119
+ export const getInputSize = (input: UTXOInputWithScriptType | UTXOType) => {
120
+ if ("type" in input) {
121
+ return InputSizes[input.type];
122
+ }
123
+ if ("address" in input && input.address) {
124
+ return InputSizes[getScriptTypeForAddress(input.address as string)];
125
+ }
126
+ return TX_INPUT_BASE + TX_INPUT_PUBKEYHASH;
127
+ };
128
+
129
+ export const getOutputSize = (output: TargetOutput, scriptType?: UTXOScriptType) => {
130
+ if (output?.script) {
131
+ return OP_RETURN_OVERHEAD + output.script.length + (output.script.length >= 74 ? 2 : 1);
132
+ }
133
+ if (scriptType) {
134
+ return OutputSizes[scriptType];
135
+ }
136
+ return OutputSizes[UTXOScriptType.P2PKH];
137
+ };
@@ -0,0 +1,6 @@
1
+ export * from "./helpers";
2
+ export * from "./toolbox";
3
+ export * from "./toolbox/bitcoinCash";
4
+ export * from "./toolbox/utxo";
5
+ export * from "./toolbox/zcash";
6
+ export * from "./types";
@@ -0,0 +1,243 @@
1
+ import {
2
+ address as bchAddress,
3
+ Transaction,
4
+ TransactionBuilder,
5
+ // @ts-expect-error
6
+ } from "@psf/bitcoincashjs-lib";
7
+ import {
8
+ Chain,
9
+ type ChainSigner,
10
+ type DerivationPathArray,
11
+ derivationPathToString,
12
+ FeeOption,
13
+ NetworkDerivationPath,
14
+ SwapKitError,
15
+ updateDerivationPath,
16
+ } from "@uswap/helpers";
17
+ import { Psbt } from "bitcoinjs-lib";
18
+ import { accumulative, compileMemo, getUtxoApi, getUtxoNetwork, toCashAddress, toLegacyAddress } from "../helpers";
19
+ import type {
20
+ BchECPair,
21
+ TargetOutput,
22
+ TransactionBuilderType,
23
+ TransactionType,
24
+ UTXOBuildTxParams,
25
+ UTXOTransferParams,
26
+ UTXOType,
27
+ } from "../types";
28
+ import type { UtxoToolboxParams } from "./params";
29
+ import { createUTXOToolbox, getCreateKeysForPath } from "./utxo";
30
+ import { bchValidateAddress, stripPrefix } from "./validators";
31
+
32
+ const chain = Chain.BitcoinCash;
33
+
34
+ export function stripToCashAddress(address: string) {
35
+ return stripPrefix(toCashAddress(address));
36
+ }
37
+
38
+ function createSignerWithKeys(keys: BchECPair) {
39
+ function signTransaction({ builder, utxos }: { builder: TransactionBuilderType; utxos: UTXOType[] }) {
40
+ utxos.forEach((utxo, index) => {
41
+ builder.sign(index, keys, undefined, 0x41, utxo.witnessUtxo?.value);
42
+ });
43
+
44
+ return builder.build();
45
+ }
46
+
47
+ const getAddress = () => {
48
+ const address = keys.getAddress(0);
49
+ return Promise.resolve(stripToCashAddress(address));
50
+ };
51
+
52
+ return { getAddress, signTransaction };
53
+ }
54
+
55
+ export async function createBCHToolbox<T extends typeof Chain.BitcoinCash>(
56
+ toolboxParams: UtxoToolboxParams[T] | { phrase?: string; derivationPath?: DerivationPathArray; index?: number },
57
+ ) {
58
+ const phrase = "phrase" in toolboxParams ? toolboxParams.phrase : undefined;
59
+
60
+ const index = "index" in toolboxParams ? toolboxParams.index || 0 : 0;
61
+
62
+ const derivationPath = derivationPathToString(
63
+ "derivationPath" in toolboxParams && toolboxParams.derivationPath
64
+ ? toolboxParams.derivationPath
65
+ : updateDerivationPath(NetworkDerivationPath[chain], { index }),
66
+ );
67
+
68
+ const keys = phrase ? (await getCreateKeysForPath(chain))({ derivationPath, phrase }) : undefined;
69
+
70
+ const signer = keys ? createSignerWithKeys(keys) : "signer" in toolboxParams ? toolboxParams.signer : undefined;
71
+
72
+ function getAddress() {
73
+ return Promise.resolve(signer?.getAddress());
74
+ }
75
+
76
+ const { getBalance, getFeeRates, broadcastTx, ...toolbox } = await createUTXOToolbox({ chain });
77
+
78
+ function handleGetBalance(address: string, _scamFilter = true) {
79
+ return getBalance(stripPrefix(toCashAddress(address)));
80
+ }
81
+
82
+ return {
83
+ ...toolbox,
84
+ broadcastTx,
85
+ buildTx,
86
+ createTransaction,
87
+ getAddress,
88
+ getAddressFromKeys,
89
+ getBalance: handleGetBalance,
90
+ getFeeRates,
91
+ stripPrefix,
92
+ stripToCashAddress,
93
+ transfer: transfer({ broadcastTx, getFeeRates, signer }),
94
+ validateAddress: bchValidateAddress,
95
+ };
96
+ }
97
+
98
+ async function createTransaction({ assetValue, recipient, memo, feeRate, sender }: UTXOBuildTxParams) {
99
+ if (!bchValidateAddress(recipient)) throw new SwapKitError("toolbox_utxo_invalid_address", { address: recipient });
100
+
101
+ // Overestimate by 7500 byte * feeRate to ensure we have enough UTXOs for fees and change
102
+ const targetValue = Math.ceil(assetValue.getBaseValue("number") + feeRate * 7500);
103
+
104
+ const utxos = await getUtxoApi(chain).getUtxos({
105
+ address: stripToCashAddress(sender),
106
+ fetchTxHex: true,
107
+ targetValue,
108
+ });
109
+
110
+ const compiledMemo = memo ? await compileMemo(memo) : null;
111
+
112
+ const targetOutputs: TargetOutput[] = [];
113
+ // output to recipient
114
+ targetOutputs.push({ address: recipient, value: assetValue.getBaseValue("number") });
115
+ const { inputs, outputs } = accumulative({ chain, feeRate, inputs: utxos, outputs: targetOutputs });
116
+
117
+ // .inputs and .outputs will be undefined if no solution was found
118
+ if (!(inputs && outputs)) throw new SwapKitError("toolbox_utxo_insufficient_balance", { assetValue, sender });
119
+ const getNetwork = await getUtxoNetwork();
120
+ const builder = new TransactionBuilder(getNetwork(chain)) as TransactionBuilderType;
121
+
122
+ await Promise.all(
123
+ inputs.map(async (utxo: UTXOType) => {
124
+ const txHex = await getUtxoApi(chain).getRawTx(utxo.hash);
125
+
126
+ builder.addInput(Transaction.fromBuffer(Buffer.from(txHex, "hex")), utxo.index);
127
+ }),
128
+ );
129
+
130
+ for (const output of outputs) {
131
+ const address = "address" in output && output.address ? output.address : toLegacyAddress(sender);
132
+ const getNetwork = await getUtxoNetwork();
133
+ const outputScript = bchAddress.toOutputScript(toLegacyAddress(address), getNetwork(chain));
134
+
135
+ builder.addOutput(outputScript, output.value);
136
+ }
137
+
138
+ // add output for memo
139
+ if (compiledMemo) {
140
+ builder.addOutput(compiledMemo, 0); // Add OP_RETURN {script, value}
141
+ }
142
+
143
+ return { builder, utxos: inputs };
144
+ }
145
+
146
+ function transfer({
147
+ broadcastTx,
148
+ getFeeRates,
149
+ signer,
150
+ }: {
151
+ broadcastTx: (txHash: string) => Promise<string>;
152
+ getFeeRates: () => Promise<Record<FeeOption, number>>;
153
+ signer?: ChainSigner<{ builder: TransactionBuilderType; utxos: UTXOType[] }, TransactionType>;
154
+ }) {
155
+ return async function transfer({
156
+ recipient,
157
+ assetValue,
158
+ feeOptionKey = FeeOption.Fast,
159
+ ...rest
160
+ }: UTXOTransferParams) {
161
+ const from = await signer?.getAddress();
162
+ if (!(signer && from)) throw new SwapKitError("toolbox_utxo_no_signer");
163
+ if (!recipient)
164
+ throw new SwapKitError("toolbox_utxo_invalid_params", { error: "Recipient address must be provided" });
165
+
166
+ const feeRate = rest.feeRate || (await getFeeRates())[feeOptionKey];
167
+
168
+ // try out if psbt tx is faster/better/nicer
169
+ const { builder, utxos } = await createTransaction({ ...rest, assetValue, feeRate, recipient, sender: from });
170
+
171
+ const tx = await signer.signTransaction({ builder, utxos });
172
+ const txHex = tx.toHex();
173
+
174
+ return broadcastTx(txHex);
175
+ };
176
+ }
177
+
178
+ async function buildTx({
179
+ assetValue,
180
+ recipient,
181
+ memo,
182
+ feeRate,
183
+ sender,
184
+ setSigHashType,
185
+ }: UTXOBuildTxParams & { setSigHashType?: boolean }) {
186
+ const recipientCashAddress = toCashAddress(recipient);
187
+ if (!bchValidateAddress(recipientCashAddress))
188
+ throw new SwapKitError("toolbox_utxo_invalid_address", { address: recipientCashAddress });
189
+
190
+ // Overestimate by 7500 byte * feeRate to ensure we have enough UTXOs for fees and change
191
+ const targetValue = Math.ceil(assetValue.getBaseValue("number") + feeRate * 7500);
192
+
193
+ const utxos = await getUtxoApi(chain).getUtxos({
194
+ address: stripToCashAddress(sender),
195
+ fetchTxHex: false,
196
+ targetValue,
197
+ });
198
+
199
+ const feeRateWhole = Number(feeRate.toFixed(0));
200
+ const compiledMemo = memo ? await compileMemo(memo) : null;
201
+
202
+ const targetOutputs = [] as TargetOutput[];
203
+
204
+ // output to recipient
205
+ targetOutputs.push({ address: toLegacyAddress(recipient), value: assetValue.getBaseValue("number") });
206
+
207
+ //2. add output memo to targets (optional)
208
+ if (compiledMemo) {
209
+ targetOutputs.push({ script: compiledMemo, value: 0 });
210
+ }
211
+
212
+ const { inputs, outputs } = accumulative({ chain, feeRate: feeRateWhole, inputs: utxos, outputs: targetOutputs });
213
+
214
+ // .inputs and .outputs will be undefined if no solution was found
215
+ if (!(inputs && outputs)) throw new SwapKitError("toolbox_utxo_insufficient_balance", { assetValue, sender });
216
+ const getNetwork = await getUtxoNetwork();
217
+ const psbt = new Psbt({ network: getNetwork(chain) }); // Network-specific
218
+
219
+ for (const { hash, index, witnessUtxo } of inputs) {
220
+ psbt.addInput({ hash, index, sighashType: setSigHashType ? 0x41 : undefined, witnessUtxo });
221
+ }
222
+
223
+ // Outputs
224
+ for (const output of outputs) {
225
+ const address = "address" in output && output.address ? output.address : toLegacyAddress(sender);
226
+ const params = output.script
227
+ ? compiledMemo
228
+ ? { script: compiledMemo, value: 0 }
229
+ : undefined
230
+ : { address, value: output.value };
231
+
232
+ if (params) {
233
+ psbt.addOutput(params);
234
+ }
235
+ }
236
+
237
+ return { inputs: inputs as UTXOType[], psbt, utxos };
238
+ }
239
+
240
+ function getAddressFromKeys(keys: { getAddress: (index?: number) => string }) {
241
+ const address = keys.getAddress(0);
242
+ return stripToCashAddress(address);
243
+ }