@swapkit/toolboxes 1.0.0-beta.23 → 1.0.0-beta.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 (48) hide show
  1. package/dist/{chunk-12xtvbsp.js → chunk-6f98phv2.js} +2 -2
  2. package/dist/{chunk-12xtvbsp.js.map → chunk-6f98phv2.js.map} +1 -1
  3. package/dist/{chunk-kbnwrc5b.js → chunk-zcdeg6h9.js} +2 -2
  4. package/dist/{chunk-kbnwrc5b.js.map → chunk-zcdeg6h9.js.map} +1 -1
  5. package/dist/src/cosmos/index.cjs +2 -2
  6. package/dist/src/cosmos/index.cjs.map +6 -6
  7. package/dist/src/cosmos/index.js +2 -2
  8. package/dist/src/cosmos/index.js.map +6 -6
  9. package/dist/src/evm/index.js +2 -2
  10. package/dist/src/evm/index.js.map +1 -1
  11. package/dist/src/index.cjs +2 -2
  12. package/dist/src/index.cjs.map +3 -3
  13. package/dist/src/index.js +2 -2
  14. package/dist/src/index.js.map +3 -3
  15. package/dist/src/near/index.cjs +2 -2
  16. package/dist/src/near/index.cjs.map +3 -3
  17. package/dist/src/near/index.js +2 -2
  18. package/dist/src/near/index.js.map +3 -3
  19. package/dist/src/substrate/index.cjs +2 -2
  20. package/dist/src/substrate/index.cjs.map +5 -4
  21. package/dist/src/substrate/index.js +2 -2
  22. package/dist/src/substrate/index.js.map +5 -4
  23. package/dist/src/tron/index.cjs +2 -2
  24. package/dist/src/tron/index.cjs.map +3 -3
  25. package/dist/src/tron/index.js +2 -2
  26. package/dist/src/tron/index.js.map +3 -3
  27. package/dist/src/utxo/index.cjs +4 -2
  28. package/dist/src/utxo/index.cjs.map +8 -7
  29. package/dist/src/utxo/index.js +4 -2
  30. package/dist/src/utxo/index.js.map +8 -7
  31. package/package.json +2 -2
  32. package/src/cosmos/thorchainUtils/registry.ts +3 -3
  33. package/src/cosmos/toolbox/cosmos.ts +21 -7
  34. package/src/cosmos/toolbox/thorchain.ts +6 -6
  35. package/src/cosmos/util.ts +66 -3
  36. package/src/evm/__tests__/address-validation.test.ts +86 -0
  37. package/src/index.ts +1 -0
  38. package/src/near/toolbox.ts +22 -1
  39. package/src/substrate/balance.ts +92 -0
  40. package/src/substrate/substrate.ts +6 -4
  41. package/src/tron/toolbox.ts +1 -1
  42. package/src/utxo/__tests__/zcash-integration.test.ts +114 -0
  43. package/src/utxo/helpers/api.ts +36 -0
  44. package/src/utxo/helpers/coinselect.ts +2 -0
  45. package/src/utxo/index.ts +1 -0
  46. package/src/utxo/toolbox/index.ts +14 -3
  47. package/src/utxo/toolbox/utxo.ts +7 -0
  48. package/src/utxo/toolbox/zcash.ts +208 -0
@@ -0,0 +1,86 @@
1
+ import { beforeAll, describe, expect, test } from "bun:test";
2
+ import { Chain } from "@swapkit/helpers";
3
+ import { getEvmToolbox } from "../toolbox";
4
+
5
+ const context: {
6
+ validateAddress: (address: string) => boolean;
7
+ } = {} as any;
8
+
9
+ beforeAll(async () => {
10
+ // Get EVM toolbox for address validation
11
+ const toolbox = await getEvmToolbox(Chain.Ethereum);
12
+ context.validateAddress = toolbox.validateAddress;
13
+ });
14
+
15
+ describe("EVM Address Validation", () => {
16
+ test("should validate valid EVM addresses", () => {
17
+ const validAddresses = [
18
+ "0xa052Ddf1c1739419B90FB7bf722843AD3e63114B", // User provided address
19
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC contract
20
+ "0x6d6e022eE439C8aB8B7a7dBb0576f8090319CDc6", // Test address
21
+ "0xE29E61479420Dd1029A9946710Ac31A0d140e77F", // Another valid address
22
+ "0x0000000000000000000000000000000000000000", // Zero address
23
+ "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF", // Max address
24
+ "0x1234567890123456789012345678901234567890", // Mixed case
25
+ ];
26
+
27
+ for (const address of validAddresses) {
28
+ expect(context.validateAddress(address)).toBe(true);
29
+ }
30
+ });
31
+
32
+ test("should reject invalid EVM addresses", () => {
33
+ const invalidAddresses = [
34
+ "", // Empty string
35
+ "invalid", // Random string
36
+ "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", // TRON address
37
+ "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", // Bitcoin address
38
+ "cosmos1abc123", // Cosmos address
39
+ "0xa052Ddf1c1739419B90FB7bf722843AD3e63114", // Too short (missing 1 char)
40
+ "0xa052Ddf1c1739419B90FB7bf722843AD3e63114BB", // Too long (extra char)
41
+ "0XA052DDF1C1739419B90FB7BF722843AD3E63114B", // Uppercase 0X prefix
42
+ "0xG052Ddf1c1739419B90FB7bf722843AD3e63114B", // Invalid hex character
43
+ "0x", // Only prefix
44
+ ];
45
+
46
+ for (const address of invalidAddresses) {
47
+ expect(context.validateAddress(address)).toBe(false);
48
+ }
49
+ });
50
+
51
+ test("should handle case normalization properly", () => {
52
+ const address = "0xa052Ddf1c1739419B90FB7bf722843AD3e63114B"; // Proper checksum
53
+ const lowerCase = address.toLowerCase();
54
+
55
+ // Valid case variations should be accepted
56
+ expect(context.validateAddress(address)).toBe(true);
57
+ expect(context.validateAddress(lowerCase)).toBe(true);
58
+ });
59
+
60
+ test("should reject invalid checksum addresses", () => {
61
+ const invalidChecksumAddress = "0xA052dDF1C1739419b90fb7BF722843ad3E63114b"; // Invalid checksum
62
+
63
+ // Should reject mixed case with invalid checksum
64
+ expect(context.validateAddress(invalidChecksumAddress)).toBe(false);
65
+ });
66
+
67
+ test("should handle edge cases", () => {
68
+ const edgeCases = [null, undefined, 123, {}, [], true, false];
69
+
70
+ for (const testCase of edgeCases) {
71
+ // Should not throw but return false for invalid inputs
72
+ expect(context.validateAddress(testCase as any)).toBe(false);
73
+ }
74
+ });
75
+
76
+ test("should validate checksummed addresses", () => {
77
+ const checksummedAddresses = [
78
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC with proper checksum
79
+ "0x6d6e022eE439C8aB8B7a7dBb0576f8090319CDc6", // Another checksummed address
80
+ ];
81
+
82
+ for (const address of checksummedAddresses) {
83
+ expect(context.validateAddress(address)).toBe(true);
84
+ }
85
+ });
86
+ });
package/src/index.ts CHANGED
@@ -192,6 +192,7 @@ export async function getToolbox<T extends keyof Toolboxes>(
192
192
  Chain.Dogecoin,
193
193
  Chain.BitcoinCash,
194
194
  Chain.Bitcoin,
195
+ Chain.Zcash,
195
196
  async () => {
196
197
  const { getUtxoToolbox } = await import("@swapkit/toolboxes/utxo");
197
198
  const utxoToolbox = await getUtxoToolbox(
@@ -117,8 +117,29 @@ export async function getNearToolbox(toolboxParams?: NearToolboxParams) {
117
117
  async function createTransaction(params: NearCreateTransactionParams) {
118
118
  const { recipient, assetValue, memo, feeRate: gas, attachedDeposit, sender: signerId } = params;
119
119
 
120
- const { publicKey, nonce } = await getFullAccessPublicKey(provider, signerId);
120
+ // Handle NEP-141 token transfers
121
+ if (!assetValue.isGasAsset) {
122
+ const contractId = assetValue.address;
123
+ if (!contractId) {
124
+ throw new SwapKitError("toolbox_near_missing_contract_address");
125
+ }
126
+
127
+ return createContractFunctionCall({
128
+ sender: signerId,
129
+ contractId,
130
+ methodName: "ft_transfer",
131
+ args: {
132
+ receiver_id: recipient,
133
+ amount: assetValue.getBaseValue("string"),
134
+ memo: memo || null,
135
+ },
136
+ gas: gas.toString() || "100000000000000", // 100 TGas default
137
+ attachedDeposit: "1", // 1 yoctoNEAR required for NEP-141 transfers
138
+ });
139
+ }
121
140
 
141
+ // Native NEAR transfer
142
+ const { publicKey, nonce } = await getFullAccessPublicKey(provider, signerId);
122
143
  const baseAmount = assetValue.getBaseValue("bigint");
123
144
 
124
145
  const { SCHEMA } = await import("near-api-js/lib/transaction");
@@ -0,0 +1,92 @@
1
+ import type { ApiPromise } from "@polkadot/api";
2
+ import { AssetValue, Chain, SwapKitNumber } from "@swapkit/helpers";
3
+
4
+ /**
5
+ * Get balance for standard Substrate chains (Polkadot, etc.)
6
+ * Uses api.query.system.account to query free and reserved balances
7
+ */
8
+ export async function getSubstrateBalance(
9
+ api: ApiPromise,
10
+ gasAsset: AssetValue,
11
+ address: string,
12
+ ): Promise<AssetValue[]> {
13
+ try {
14
+ const account = await api.query.system?.account?.(address);
15
+
16
+ if (!account) {
17
+ return [gasAsset.set(0)];
18
+ }
19
+
20
+ const {
21
+ // @ts-expect-error
22
+ data: { free },
23
+ } = account;
24
+
25
+ // Convert the free balance to string using SwapKitNumber for proper decimal handling
26
+ const freeBalance = SwapKitNumber.fromBigInt(
27
+ BigInt(free.toString()),
28
+ gasAsset.decimal,
29
+ ).getValue("string");
30
+
31
+ return [gasAsset.set(freeBalance)];
32
+ } catch (error) {
33
+ console.error("Error fetching substrate balance:", error);
34
+ return [gasAsset.set(0)];
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Get balance for Chainflip chain
40
+ * Uses api.query.flip.account to query FLIP balances
41
+ */
42
+ export async function getChainflipBalance(
43
+ api: ApiPromise,
44
+ gasAsset: AssetValue,
45
+ address: string,
46
+ ): Promise<AssetValue[]> {
47
+ try {
48
+ // Chainflip uses a custom flip pallet for account balances
49
+ const flipAccount = await api.query.flip?.account?.(address);
50
+
51
+ if (!flipAccount) {
52
+ return [gasAsset.set(0)];
53
+ }
54
+
55
+ // Extract balance from the flip account structure
56
+ // The structure has a balance field directly
57
+ //@ts-expect-error
58
+ const balance = flipAccount.balance || flipAccount.data?.balance;
59
+
60
+ if (!balance || balance.isEmpty) {
61
+ return [gasAsset.set(0)];
62
+ }
63
+
64
+ // Convert balance to string using SwapKitNumber
65
+ const balanceStr = SwapKitNumber.fromBigInt(
66
+ BigInt(balance.toString()),
67
+ gasAsset.decimal,
68
+ ).getValue("string");
69
+
70
+ return [gasAsset.set(balanceStr)];
71
+ } catch (error) {
72
+ console.error("Error fetching chainflip balance:", error);
73
+ return [gasAsset.set(0)];
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Factory function to create chain-specific balance getter
79
+ */
80
+ export function createBalanceGetter(chain: Chain, api: ApiPromise) {
81
+ return function getBalance(address: string): Promise<AssetValue[]> {
82
+ const gasAsset = AssetValue.from({ chain });
83
+
84
+ switch (chain) {
85
+ case Chain.Chainflip:
86
+ return getChainflipBalance(api, gasAsset, address);
87
+
88
+ default:
89
+ return getSubstrateBalance(api, gasAsset, address);
90
+ }
91
+ };
92
+ }
@@ -19,7 +19,7 @@ import {
19
19
  } from "@swapkit/helpers";
20
20
 
21
21
  import { P, match } from "ts-pattern";
22
- import { getBalance } from "../utils";
22
+ import { createBalanceGetter } from "./balance";
23
23
  import { SubstrateNetwork, type SubstrateTransferParams } from "./types";
24
24
 
25
25
  export const PolkadotToolbox = ({ generic = false, ...signerParams }: ToolboxParams = {}) => {
@@ -36,7 +36,7 @@ export const ChainflipToolbox = async ({
36
36
  ...signerParams,
37
37
  });
38
38
 
39
- return { ...toolbox, getBalance: getBalance(Chain.Chainflip) };
39
+ return { ...toolbox };
40
40
  };
41
41
 
42
42
  export type SubstrateToolboxes = {
@@ -208,11 +208,13 @@ export const BaseSubstrateToolbox = ({
208
208
  network,
209
209
  gasAsset,
210
210
  signer,
211
+ chain,
211
212
  }: {
212
213
  api: ApiPromise;
213
214
  network: SubstrateNetwork;
214
215
  gasAsset: AssetValue;
215
216
  signer?: IKeyringPair | Signer;
217
+ chain?: SubstrateChain;
216
218
  }) => ({
217
219
  api,
218
220
  network,
@@ -220,7 +222,7 @@ export const BaseSubstrateToolbox = ({
220
222
  decodeAddress,
221
223
  encodeAddress,
222
224
  convertAddress,
223
- getBalance: getBalance(Chain.Polkadot),
225
+ getBalance: createBalanceGetter(chain || Chain.Polkadot, api),
224
226
  createKeyring: (phrase: string) => createKeyring(phrase, network.prefix),
225
227
  getAddress: (keyring?: IKeyringPair | Signer) => {
226
228
  const keyringPair = keyring || signer;
@@ -301,7 +303,7 @@ export async function createSubstrateToolbox({
301
303
  .with({ signer: P.any }, ({ signer }) => signer)
302
304
  .otherwise(() => undefined);
303
305
 
304
- return BaseSubstrateToolbox({ api, signer, gasAsset, network });
306
+ return BaseSubstrateToolbox({ api, signer, gasAsset, network, chain });
305
307
  }
306
308
 
307
309
  export type ToolboxParams = {
@@ -96,7 +96,7 @@ async function createKeysForPath({
96
96
  }
97
97
 
98
98
  export const createTronToolbox = async (options: TronToolboxOptions = {}) => {
99
- const { TronWeb } = require("tronweb");
99
+ const { TronWeb } = await import("tronweb");
100
100
  // Always get configuration from SKConfig
101
101
  const rpcUrl = SKConfig.get("rpcUrls")[Chain.Tron];
102
102
  // Note: TRON API key support can be added to SKConfig apiKeys when needed
@@ -0,0 +1,114 @@
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 =
7
+ "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
8
+
9
+ it("should create Zcash toolbox through main UTXO toolbox factory", async () => {
10
+ const toolbox = await getUtxoToolbox(Chain.Zcash);
11
+
12
+ expect(toolbox).toBeDefined();
13
+ expect(typeof toolbox.validateAddress).toBe("function");
14
+ expect(typeof toolbox.getBalance).toBe("function");
15
+ expect(typeof toolbox.getFeeRates).toBe("function");
16
+ expect(typeof toolbox.broadcastTx).toBe("function");
17
+ expect(typeof toolbox.createTransaction).toBe("function");
18
+ expect(typeof toolbox.transfer).toBe("function");
19
+ });
20
+
21
+ it("should create Zcash toolbox with phrase", async () => {
22
+ const toolbox = await getUtxoToolbox(Chain.Zcash, {
23
+ phrase: testPhrase,
24
+ });
25
+
26
+ expect(toolbox).toBeDefined();
27
+ expect(() => toolbox.getAddress()).not.toThrow();
28
+ });
29
+
30
+ it("should generate valid Zcash addresses", async () => {
31
+ const toolbox = await getUtxoToolbox(Chain.Zcash, {
32
+ phrase: testPhrase,
33
+ });
34
+
35
+ const address = await toolbox.getAddress();
36
+ expect(address).toBeDefined();
37
+ expect(typeof address).toBe("string");
38
+ expect(address?.startsWith("t1")).toBe(true); // Zcash mainnet addresses start with t1
39
+ expect(toolbox.validateAddress(address || "")).toBe(true);
40
+ });
41
+
42
+ it("should validate Zcash addresses correctly", async () => {
43
+ const toolbox = await getUtxoToolbox(Chain.Zcash);
44
+
45
+ // Valid Zcash mainnet address format
46
+ expect(toolbox.validateAddress("t1XVXWCvpMgBvUaed4XDqWtgQgJSu1Ghz7F")).toBe(true);
47
+
48
+ // Invalid addresses
49
+ expect(toolbox.validateAddress("1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2")).toBe(false); // Bitcoin address
50
+ expect(toolbox.validateAddress("zcash:qr5agtachyxvrwxu76vzszan5pnvuzy8dm")).toBe(false); // Wrong format
51
+ expect(toolbox.validateAddress("")).toBe(false); // Empty string
52
+ expect(toolbox.validateAddress("invalid")).toBe(false); // Invalid string
53
+ });
54
+
55
+ it("should reject shielded addresses", async () => {
56
+ const toolbox = await getUtxoToolbox(Chain.Zcash);
57
+
58
+ // Test z-address (shielded) - should be rejected with warning
59
+ const originalWarn = console.warn;
60
+ let warnCalled = false;
61
+ let warnMessage = "";
62
+
63
+ console.warn = (message: string) => {
64
+ warnCalled = true;
65
+ warnMessage = message;
66
+ };
67
+
68
+ const isValid = toolbox.validateAddress(
69
+ "zs1z7rejlpsa98s2rrrfkwmaxu2xldqmfq5nj2m3hq6s7r8qjq8eqqqq9p4e7x",
70
+ );
71
+
72
+ expect(isValid).toBe(false);
73
+ expect(warnCalled).toBe(true);
74
+ expect(warnMessage).toBe(
75
+ "Shielded Zcash addresses (z-addresses) are not supported. Use transparent addresses (t1/t3) only.",
76
+ );
77
+
78
+ console.warn = originalWarn;
79
+ });
80
+
81
+ it("should create keys for derivation path", async () => {
82
+ const toolbox = await getUtxoToolbox(Chain.Zcash, {
83
+ phrase: testPhrase,
84
+ });
85
+
86
+ const keys = await toolbox.createKeysForPath({
87
+ phrase: testPhrase,
88
+ derivationPath: DerivationPath.ZEC,
89
+ });
90
+
91
+ expect(keys).toBeDefined();
92
+ expect(keys.publicKey).toBeDefined();
93
+ expect(keys.privateKey).toBeDefined();
94
+ expect(typeof keys.toWIF).toBe("function");
95
+
96
+ const address = await toolbox.getAddress();
97
+ expect(address).toBeDefined();
98
+ expect(address?.startsWith("t1")).toBe(true);
99
+ });
100
+
101
+ it("should get WIF private key from mnemonic", async () => {
102
+ const toolbox = await getUtxoToolbox(Chain.Zcash, {
103
+ phrase: testPhrase,
104
+ });
105
+
106
+ const wif = await toolbox.getPrivateKeyFromMnemonic({
107
+ phrase: testPhrase,
108
+ derivationPath: DerivationPath.ZEC,
109
+ });
110
+
111
+ expect(typeof wif).toBe("string");
112
+ expect(wif.length).toBeGreaterThan(50); // WIF keys are typically 51-52 characters
113
+ });
114
+ });
@@ -59,6 +59,8 @@ function getDefaultTxFeeByChain(chain: Chain) {
59
59
  return 10000;
60
60
  case Chain.Litecoin:
61
61
  return 1;
62
+ case Chain.Zcash:
63
+ return 1;
62
64
  default:
63
65
  return 2;
64
66
  }
@@ -74,6 +76,8 @@ function mapChainToBlockchairChain(chain: Chain) {
74
76
  return "dash";
75
77
  case Chain.Dogecoin:
76
78
  return "dogecoin";
79
+ case Chain.Zcash:
80
+ return "zcash";
77
81
  case Chain.Polkadot:
78
82
  return "polkadot";
79
83
  default:
@@ -277,6 +281,31 @@ export function getUtxoApi(chain: UTXOChain) {
277
281
  return utxoApi(chain);
278
282
  }
279
283
 
284
+ // Define Zcash network objects that match ECPair's expected interface
285
+ const ZCASH_MAINNET = {
286
+ messagePrefix: "\x19Zcash Signed Message:\n",
287
+ bech32: "zc",
288
+ bip32: {
289
+ public: 0x0488b21e,
290
+ private: 0x0488ade4,
291
+ },
292
+ pubKeyHash: 0x1c, // 28 in decimal - correct for Zcash mainnet
293
+ scriptHash: 0x1c, // 28 in decimal
294
+ wif: 0x80, // 128 in decimal
295
+ };
296
+
297
+ const ZCASH_TESTNET = {
298
+ messagePrefix: "\x19Zcash Signed Message:\n",
299
+ bech32: "ztestsapling",
300
+ bip32: {
301
+ public: 0x043587cf,
302
+ private: 0x04358394,
303
+ },
304
+ pubKeyHash: 0x1d, // 29 in decimal - correct for Zcash testnet
305
+ scriptHash: 0x1c, // 28 in decimal
306
+ wif: 0xef, // 239 in decimal
307
+ };
308
+
280
309
  export function getUtxoNetwork() {
281
310
  return function getNetwork(chain: Chain) {
282
311
  switch (chain) {
@@ -295,6 +324,13 @@ export function getUtxoNetwork() {
295
324
  test.versions.bip32 = bip32;
296
325
  return coininfo.dogecoin.main.toBitcoinJS();
297
326
  }
327
+
328
+ case Chain.Zcash: {
329
+ // Get Zcash network configuration using our custom objects
330
+ const { isStagenet } = SKConfig.get("envs");
331
+ return isStagenet ? ZCASH_TESTNET : ZCASH_MAINNET;
332
+ }
333
+
298
334
  default:
299
335
  throw new SwapKitError("toolbox_utxo_not_supported", { chain });
300
336
  }
@@ -20,6 +20,8 @@ export const getDustThreshold = (chain: UTXOChain) => {
20
20
  return 5500;
21
21
  case Chain.Dogecoin:
22
22
  return 100000;
23
+ case Chain.Zcash:
24
+ return 546;
23
25
  default:
24
26
  throw new SwapKitError("toolbox_utxo_not_supported", { chain });
25
27
  }
package/src/utxo/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from "./toolbox";
2
2
  export * from "./toolbox/bitcoinCash";
3
3
  export * from "./toolbox/utxo";
4
+ export * from "./toolbox/zcash";
4
5
  export * from "./helpers";
5
6
  export * from "./types";
@@ -10,11 +10,13 @@ import type { Psbt } from "bitcoinjs-lib";
10
10
  import type { TransactionBuilderType, TransactionType, UTXOType } from "../types";
11
11
  import { createBCHToolbox } from "./bitcoinCash";
12
12
  import { createUTXOToolbox } from "./utxo";
13
+ import { createZcashToolbox } from "./zcash";
13
14
 
14
15
  type BCHToolbox = Awaited<ReturnType<typeof createBCHToolbox>>;
15
16
  type CommonUTXOToolbox = Awaited<
16
- ReturnType<typeof createUTXOToolbox<Exclude<UTXOChain, Chain.BitcoinCash>>>
17
+ ReturnType<typeof createUTXOToolbox<Exclude<UTXOChain, Chain.BitcoinCash | Chain.Zcash>>>
17
18
  >;
19
+ type ZcashToolbox = Awaited<ReturnType<typeof createZcashToolbox>>;
18
20
 
19
21
  export type UTXOToolboxes = {
20
22
  [Chain.BitcoinCash]: BCHToolbox;
@@ -22,6 +24,7 @@ export type UTXOToolboxes = {
22
24
  [Chain.Dogecoin]: CommonUTXOToolbox;
23
25
  [Chain.Litecoin]: CommonUTXOToolbox;
24
26
  [Chain.Dash]: CommonUTXOToolbox;
27
+ [Chain.Zcash]: ZcashToolbox;
25
28
  };
26
29
 
27
30
  export type UTXOWallets = {
@@ -36,6 +39,9 @@ export type UtxoToolboxParams = {
36
39
  [Chain.Dogecoin]: { signer: ChainSigner<Psbt, Psbt> };
37
40
  [Chain.Litecoin]: { signer: ChainSigner<Psbt, Psbt> };
38
41
  [Chain.Dash]: { signer: ChainSigner<Psbt, Psbt> };
42
+ [Chain.Zcash]: {
43
+ signer?: ChainSigner<Psbt, Psbt>;
44
+ };
39
45
  };
40
46
 
41
47
  export async function getUtxoToolbox<T extends keyof UTXOToolboxes>(
@@ -54,15 +60,20 @@ export async function getUtxoToolbox<T extends keyof UTXOToolboxes>(
54
60
  return toolbox as UTXOToolboxes[T];
55
61
  }
56
62
 
63
+ case Chain.Zcash: {
64
+ const toolbox = await createZcashToolbox(params as UtxoToolboxParams[Chain.Zcash]);
65
+ return toolbox as UTXOToolboxes[T];
66
+ }
67
+
57
68
  case Chain.Bitcoin:
58
69
  case Chain.Dogecoin:
59
70
  case Chain.Litecoin:
60
71
  case Chain.Dash: {
61
72
  const toolbox = await createUTXOToolbox({
62
73
  chain,
63
- ...(params as UtxoToolboxParams[Exclude<T, Chain.BitcoinCash>]),
74
+ ...(params as UtxoToolboxParams[Exclude<T, Chain.BitcoinCash | Chain.Zcash>]),
64
75
  });
65
- return toolbox as UTXOToolboxes[Exclude<T, Chain.BitcoinCash>];
76
+ return toolbox as UTXOToolboxes[Exclude<T, Chain.BitcoinCash | Chain.Zcash>];
66
77
  }
67
78
 
68
79
  default:
@@ -42,6 +42,7 @@ import secp256k1 from "@bitcoinerlab/secp256k1";
42
42
  import { ECPair, HDNode } from "@psf/bitcoincashjs-lib";
43
43
  import { HDKey } from "@scure/bip32";
44
44
  import { mnemonicToSeedSync } from "@scure/bip39";
45
+ import { validateZcashAddress } from "./zcash";
45
46
 
46
47
  export const nonSegwitChains = [Chain.Dash, Chain.Dogecoin];
47
48
 
@@ -153,6 +154,10 @@ export async function getUTXOAddressValidator() {
153
154
  return bchValidateAddress(address);
154
155
  }
155
156
 
157
+ if (chain === Chain.Zcash) {
158
+ return validateZcashAddress(address);
159
+ }
160
+
156
161
  try {
157
162
  initEccLib(secp256k1);
158
163
  btcLibAddress.toOutputScript(address, getNetwork(chain));
@@ -351,6 +356,7 @@ type CreateKeysForPathReturnType = {
351
356
  [Chain.Dash]: ECPairInterface;
352
357
  [Chain.Dogecoin]: ECPairInterface;
353
358
  [Chain.Litecoin]: ECPairInterface;
359
+ [Chain.Zcash]: ECPairInterface;
354
360
  };
355
361
 
356
362
  export async function getCreateKeysForPath<T extends keyof CreateKeysForPathReturnType>(
@@ -395,6 +401,7 @@ export async function getCreateKeysForPath<T extends keyof CreateKeysForPathRetu
395
401
  case Chain.Bitcoin:
396
402
  case Chain.Dogecoin:
397
403
  case Chain.Litecoin:
404
+ case Chain.Zcash:
398
405
  case Chain.Dash: {
399
406
  return function createKeysForPath({
400
407
  phrase,