@swapkit/wallets 3.0.0-beta.9 → 4.0.0-beta.39

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 (159) hide show
  1. package/dist/chunk-0rgqnhd7.js +4 -0
  2. package/dist/{chunk-hxt2nqa8.js.map → chunk-0rgqnhd7.js.map} +3 -3
  3. package/dist/chunk-2aa1w78q.js +4 -0
  4. package/dist/chunk-2aa1w78q.js.map +10 -0
  5. package/dist/chunk-31bmhjxx.js +4 -0
  6. package/dist/chunk-31bmhjxx.js.map +10 -0
  7. package/dist/chunk-5mq0kpmy.js +5 -0
  8. package/dist/chunk-5mq0kpmy.js.map +10 -0
  9. package/dist/chunk-9sjqewve.js +5 -0
  10. package/dist/chunk-9sjqewve.js.map +10 -0
  11. package/dist/chunk-c11abmv4.js +5 -0
  12. package/dist/{chunk-6ndrbmhg.js.map → chunk-c11abmv4.js.map} +3 -3
  13. package/dist/chunk-cgt2fexr.js +4 -0
  14. package/dist/chunk-cgt2fexr.js.map +10 -0
  15. package/dist/chunk-etm8zfkk.js +4 -0
  16. package/dist/chunk-etm8zfkk.js.map +10 -0
  17. package/dist/chunk-hafkx3bw.js +4 -0
  18. package/dist/chunk-hafkx3bw.js.map +10 -0
  19. package/dist/chunk-qh8q7xr1.js +4 -0
  20. package/dist/chunk-qh8q7xr1.js.map +10 -0
  21. package/dist/{chunk-p1kdg37m.js → chunk-r308an05.js} +3 -2
  22. package/dist/{chunk-p1kdg37m.js.map → chunk-r308an05.js.map} +1 -1
  23. package/dist/chunk-sn6pgje5.js +4 -0
  24. package/dist/chunk-sn6pgje5.js.map +10 -0
  25. package/dist/chunk-vb4wtm2w.js +1 -0
  26. package/dist/chunk-wfattb4a.js +4 -0
  27. package/dist/chunk-wfattb4a.js.map +10 -0
  28. package/dist/src/bitget/index.cjs +3 -2
  29. package/dist/src/bitget/index.cjs.map +3 -3
  30. package/dist/src/bitget/index.js +3 -2
  31. package/dist/src/bitget/index.js.map +3 -3
  32. package/dist/src/coinbase/index.cjs +3 -2
  33. package/dist/src/coinbase/index.cjs.map +3 -3
  34. package/dist/src/coinbase/index.js +3 -2
  35. package/dist/src/coinbase/index.js.map +3 -3
  36. package/dist/src/cosmostation/index.cjs +4 -0
  37. package/dist/src/cosmostation/index.cjs.map +10 -0
  38. package/dist/src/cosmostation/index.js +4 -0
  39. package/dist/src/cosmostation/index.js.map +10 -0
  40. package/dist/src/ctrl/index.cjs +3 -2
  41. package/dist/src/ctrl/index.cjs.map +4 -4
  42. package/dist/src/ctrl/index.js +3 -2
  43. package/dist/src/ctrl/index.js.map +4 -4
  44. package/dist/src/evm-extensions/index.cjs +3 -2
  45. package/dist/src/evm-extensions/index.cjs.map +3 -3
  46. package/dist/src/evm-extensions/index.js +3 -2
  47. package/dist/src/evm-extensions/index.js.map +3 -3
  48. package/dist/src/exodus/index.cjs +3 -2
  49. package/dist/src/exodus/index.cjs.map +3 -3
  50. package/dist/src/exodus/index.js +3 -2
  51. package/dist/src/exodus/index.js.map +3 -3
  52. package/dist/src/index.cjs +1 -0
  53. package/dist/src/index.js +3 -2
  54. package/dist/src/index.js.map +1 -1
  55. package/dist/src/keepkey/index.cjs +3 -2
  56. package/dist/src/keepkey/index.cjs.map +9 -10
  57. package/dist/src/keepkey/index.js +3 -2
  58. package/dist/src/keepkey/index.js.map +9 -10
  59. package/dist/src/keepkey-bex/index.cjs +3 -2
  60. package/dist/src/keepkey-bex/index.cjs.map +4 -4
  61. package/dist/src/keepkey-bex/index.js +3 -2
  62. package/dist/src/keepkey-bex/index.js.map +4 -4
  63. package/dist/src/keplr/index.cjs +3 -2
  64. package/dist/src/keplr/index.cjs.map +3 -3
  65. package/dist/src/keplr/index.js +3 -2
  66. package/dist/src/keplr/index.js.map +3 -3
  67. package/dist/src/keystore/index.cjs +3 -2
  68. package/dist/src/keystore/index.cjs.map +4 -4
  69. package/dist/src/keystore/index.js +3 -2
  70. package/dist/src/keystore/index.js.map +4 -4
  71. package/dist/src/ledger/index.cjs +4 -3
  72. package/dist/src/ledger/index.cjs.map +17 -15
  73. package/dist/src/ledger/index.js +4 -3
  74. package/dist/src/ledger/index.js.map +17 -15
  75. package/dist/src/okx/index.cjs +3 -2
  76. package/dist/src/okx/index.cjs.map +4 -4
  77. package/dist/src/okx/index.js +3 -2
  78. package/dist/src/okx/index.js.map +4 -4
  79. package/dist/src/onekey/index.cjs +3 -2
  80. package/dist/src/onekey/index.cjs.map +3 -3
  81. package/dist/src/onekey/index.js +3 -2
  82. package/dist/src/onekey/index.js.map +3 -3
  83. package/dist/src/phantom/index.cjs +1 -0
  84. package/dist/src/phantom/index.js +3 -2
  85. package/dist/src/phantom/index.js.map +2 -2
  86. package/dist/src/polkadotjs/index.cjs +1 -0
  87. package/dist/src/polkadotjs/index.js +3 -2
  88. package/dist/src/polkadotjs/index.js.map +1 -1
  89. package/dist/src/radix/index.cjs +3 -2
  90. package/dist/src/radix/index.cjs.map +3 -3
  91. package/dist/src/radix/index.js +3 -2
  92. package/dist/src/radix/index.js.map +3 -3
  93. package/dist/src/talisman/index.cjs +1 -0
  94. package/dist/src/talisman/index.js +3 -2
  95. package/dist/src/talisman/index.js.map +1 -1
  96. package/dist/src/trezor/index.cjs +3 -2
  97. package/dist/src/trezor/index.cjs.map +3 -3
  98. package/dist/src/trezor/index.js +3 -2
  99. package/dist/src/trezor/index.js.map +3 -3
  100. package/dist/src/walletconnect/index.cjs +3 -2
  101. package/dist/src/walletconnect/index.cjs.map +6 -7
  102. package/dist/src/walletconnect/index.js +3 -2
  103. package/dist/src/walletconnect/index.js.map +6 -7
  104. package/package.json +73 -28
  105. package/src/bitget/helpers.ts +4 -4
  106. package/src/coinbase/signer.ts +4 -4
  107. package/src/cosmostation/index.ts +142 -0
  108. package/src/ctrl/index.ts +83 -0
  109. package/src/ctrl/walletHelpers.ts +98 -70
  110. package/src/evm-extensions/index.ts +4 -3
  111. package/src/exodus/index.ts +8 -9
  112. package/src/helpers/near-browser-provider.d.ts +286 -0
  113. package/src/helpers/near.ts +206 -0
  114. package/src/keepkey/chains/cosmos.ts +44 -50
  115. package/src/keepkey/chains/evm.ts +16 -8
  116. package/src/keepkey/chains/mayachain.ts +3 -2
  117. package/src/keepkey/chains/ripple.ts +118 -0
  118. package/src/keepkey/chains/thorchain.ts +3 -2
  119. package/src/keepkey/chains/utxo.ts +14 -3
  120. package/src/keepkey/coins.ts +11 -4
  121. package/src/keepkey/index.ts +20 -7
  122. package/src/keepkey-bex/index.ts +10 -14
  123. package/src/keepkey-bex/walletHelpers.ts +1 -1
  124. package/src/keplr/index.ts +4 -3
  125. package/src/keystore/helpers.ts +2 -4
  126. package/src/keystore/index.ts +2 -0
  127. package/src/ledger/clients/cosmos.ts +5 -4
  128. package/src/ledger/clients/evm.ts +7 -6
  129. package/src/ledger/clients/near.ts +86 -0
  130. package/src/ledger/clients/thorchain/helpers.ts +9 -4
  131. package/src/ledger/clients/thorchain/index.ts +3 -3
  132. package/src/ledger/clients/thorchain/lib.ts +3 -2
  133. package/src/ledger/clients/thorchain/utils.ts +20 -9
  134. package/src/ledger/clients/utxo.ts +3 -5
  135. package/src/ledger/clients/xrp.ts +66 -0
  136. package/src/ledger/cosmosTypes.ts +14 -10
  137. package/src/ledger/helpers/getLedgerAddress.ts +17 -3
  138. package/src/ledger/helpers/getLedgerClient.ts +63 -45
  139. package/src/ledger/helpers/getLedgerTransport.ts +5 -3
  140. package/src/ledger/index.ts +28 -7
  141. package/src/ledger/interfaces/CosmosLedgerInterface.ts +1 -2
  142. package/src/okx/helpers.ts +27 -9
  143. package/src/okx/index.ts +1 -0
  144. package/src/onekey/index.ts +3 -7
  145. package/src/radix/index.ts +4 -4
  146. package/src/trezor/evmSigner.ts +4 -4
  147. package/src/trezor/index.ts +14 -4
  148. package/src/types.ts +14 -0
  149. package/src/utils.ts +4 -0
  150. package/src/walletconnect/constants.ts +2 -0
  151. package/src/walletconnect/evmSigner.ts +8 -4
  152. package/src/walletconnect/helpers.ts +9 -2
  153. package/src/walletconnect/index.ts +134 -24
  154. package/dist/chunk-6ndrbmhg.js +0 -4
  155. package/dist/chunk-bhfpfqc3.js +0 -3
  156. package/dist/chunk-bhfpfqc3.js.map +0 -10
  157. package/dist/chunk-hxt2nqa8.js +0 -3
  158. package/dist/chunk-q81hzyra.js +0 -3
  159. package/dist/chunk-q81hzyra.js.map +0 -10
@@ -3,6 +3,7 @@ import {
3
3
  type DerivationPathArray,
4
4
  NetworkDerivationPath,
5
5
  SKConfig,
6
+ SwapKitError,
6
7
  WalletOption,
7
8
  createWallet,
8
9
  filterSupportedChains,
@@ -32,6 +33,7 @@ export const keepkeyWallet = createWallet({
32
33
  Chain.Dash,
33
34
  Chain.Ethereum,
34
35
  Chain.Litecoin,
36
+ Chain.Ripple,
35
37
  Chain.Optimism,
36
38
  Chain.Polygon,
37
39
  Chain.THORChain,
@@ -44,15 +46,22 @@ export const keepkeyWallet = createWallet({
44
46
  derivationPathMap?: Record<Chain, DerivationPathArray>,
45
47
  ) {
46
48
  const filteredChains = filterSupportedChains({ chains, supportedChains, walletType });
47
- const config = SKConfig.get("integrations").keepKey;
49
+ const pairingInfo = SKConfig.get("integrations").keepKey;
50
+ if (!pairingInfo) throw new Error("KeepKey config not found");
48
51
 
49
- if (!config) throw new Error("KeepKey config not found");
52
+ const initialApiKey = SKConfig.get("apiKeys").keepKey || "1234";
50
53
 
51
54
  await checkAndLaunch();
52
55
 
53
- const keepkeyConfig = { ...config, apiKey: SKConfig.get("apiKeys").keepKey };
56
+ // Conform to the expected { apiKey, pairingInfo } structure
57
+ const keepkeyConfig = { apiKey: initialApiKey, pairingInfo };
54
58
  const keepKeySdk = await KeepKeySdk.create(keepkeyConfig);
55
59
 
60
+ // Persist the new API key via SKConfig after pairing
61
+ if (keepkeyConfig.apiKey && keepkeyConfig.apiKey !== initialApiKey) {
62
+ SKConfig.setApiKey("keepKey", keepkeyConfig.apiKey);
63
+ }
64
+
56
65
  await Promise.all(
57
66
  filteredChains.map(async (chain) => {
58
67
  const walletMethods = await getWalletMethods({
@@ -84,6 +93,7 @@ async function getWalletMethods({
84
93
  case Chain.Optimism:
85
94
  case Chain.Polygon:
86
95
  case Chain.Avalanche:
96
+ case Chain.Base:
87
97
  case Chain.Ethereum: {
88
98
  const provider = await getProvider(chain);
89
99
  const signer = new KeepKeySigner({ sdk, chain, derivationPath, provider });
@@ -107,12 +117,16 @@ async function getWalletMethods({
107
117
  case Chain.Litecoin: {
108
118
  return utxoWalletMethods({ sdk, chain, derivationPath });
109
119
  }
120
+ case Chain.Ripple: {
121
+ const { rippleWalletMethods } = await import("./chains/ripple");
122
+ return rippleWalletMethods({ sdk, derivationPath });
123
+ }
110
124
  default:
111
- throw new Error(`Chain not supported ${chain}`);
125
+ throw new SwapKitError("wallet_keepkey_chain_not_supported", { chain });
112
126
  }
113
127
  }
114
128
 
115
- // kk-sdk docs: https://medium.com/@highlander_35968/building-on-the-keepkey-sdk-2023fda41f38
129
+ // kk-sdk docs: https://keepkey.com/blog/building_on_the_keepkey_sdk
116
130
  // test spec: if offline, launch keepkey-bridge
117
131
  async function checkAndLaunch(attempts = 0) {
118
132
  if (attempts >= 3) {
@@ -133,8 +147,7 @@ async function checkKeepkeyAvailability(spec = "http://localhost:1646/spec/swagg
133
147
  try {
134
148
  const response = await fetch(spec);
135
149
  return response.status === 200;
136
- } catch (error) {
137
- console.error(error);
150
+ } catch (_error) {
138
151
  return false;
139
152
  }
140
153
  }
@@ -36,6 +36,7 @@ export const keepkeyBexWallet = createWallet({
36
36
  Chain.Maya,
37
37
  Chain.Optimism,
38
38
  Chain.Polygon,
39
+ Chain.Ripple,
39
40
  Chain.Solana,
40
41
  Chain.THORChain,
41
42
  ],
@@ -83,11 +84,11 @@ async function getWalletMethods(chain: (typeof KEEPKEY_BEX_SUPPORTED_CHAINS)[num
83
84
 
84
85
  // @ts-expect-error assumed available connection
85
86
  const signer = window.keepkey?.cosmos?.getOfflineSignerOnlyAmino(ChainIdToChain[chain]);
86
- if (!signer) throw new Error("Could not load signer");
87
+ if (!signer) throw new SwapKitError("wallet_keepkey_signer_not_found");
87
88
  const toolbox = getCosmosToolbox(chain, { signer });
88
89
 
89
90
  const accounts = await signer.getAccounts();
90
- if (!accounts?.[0]?.address) throw new Error("No accounts found");
91
+ if (!accounts?.[0]?.address) throw new SwapKitError("wallet_keepkey_no_accounts");
91
92
 
92
93
  const [{ address }] = accounts;
93
94
 
@@ -103,18 +104,13 @@ async function getWalletMethods(chain: (typeof KEEPKEY_BEX_SUPPORTED_CHAINS)[num
103
104
  const toolbox = await getUtxoToolbox(chain);
104
105
 
105
106
  const getBalance = async () => {
106
- try {
107
- const providerChain = getProviderNameFromChain(chain);
108
- // @ts-expect-error We assuming there chains via switch
109
- const balance = await window?.keepkey?.[providerChain]?.request({
110
- method: "request_balance",
111
- });
112
- const assetValue = AssetValue.from({ chain, value: balance[0].balance });
113
- return [assetValue];
114
- } catch (error) {
115
- console.error("Error fetching balance:", error);
116
- throw error;
117
- }
107
+ const providerChain = getProviderNameFromChain(chain);
108
+ // @ts-expect-error We assuming there chains via switch
109
+ const balance = await window?.keepkey?.[providerChain]?.request({
110
+ method: "request_balance",
111
+ });
112
+ const assetValue = AssetValue.from({ chain, value: balance[0].balance });
113
+ return [assetValue];
118
114
  };
119
115
 
120
116
  return { ...toolbox, getBalance, transfer: walletTransfer };
@@ -60,7 +60,7 @@ export const getProviderNameFromChain = (chain: Chain): string => {
60
60
  case Chain.Litecoin:
61
61
  return "litecoin";
62
62
  default:
63
- throw new Error("Unsupported chain");
63
+ throw new SwapKitError("wallet_keepkey_chain_not_supported", { chain });
64
64
  }
65
65
  };
66
66
 
@@ -2,6 +2,7 @@ import {
2
2
  Chain,
3
3
  ChainId,
4
4
  ChainToChainId,
5
+ SwapKitError,
5
6
  WalletOption,
6
7
  createWallet,
7
8
  filterSupportedChains,
@@ -28,19 +29,19 @@ export const keplrWallet = createWallet({
28
29
 
29
30
  if (!keplrSupportedChainIds.includes(chainId)) {
30
31
  const chainConfig = chainRegistry.get(chainId);
31
- if (!chainConfig) throw new Error(`Unsupported chain ${chain}`);
32
+ if (!chainConfig) throw new SwapKitError("wallet_keplr_chain_not_supported", { chain });
32
33
 
33
34
  await keplrClient.experimentalSuggestChain(chainConfig);
34
35
  }
35
36
 
36
37
  keplrClient?.enable(chainId);
37
38
  const signer = keplrClient?.getOfflineSignerOnlyAmino(chainId);
38
- if (!signer) throw new Error("Could not load signer");
39
+ if (!signer) throw new SwapKitError("wallet_keplr_signer_not_found");
39
40
 
40
41
  const { getCosmosToolbox } = await import("@swapkit/toolboxes/cosmos");
41
42
 
42
43
  const accounts = await signer.getAccounts();
43
- if (!accounts?.[0]?.address) throw new Error("No accounts found");
44
+ if (!accounts?.[0]?.address) throw new SwapKitError("wallet_keplr_no_accounts");
44
45
 
45
46
  const [{ address }] = accounts;
46
47
  const toolbox = getCosmosToolbox(chain, { signer });
@@ -1,3 +1,4 @@
1
+ import { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from "node:crypto";
1
2
  import { generateMnemonic, validateMnemonic } from "@scure/bip39";
2
3
  import { wordlist } from "@scure/bip39/wordlists/english";
3
4
 
@@ -15,7 +16,7 @@ export type Keystore = {
15
16
  };
16
17
 
17
18
  async function blake256(initData: Buffer | string) {
18
- const { blake2bFinal, blake2bInit, blake2bUpdate } = await import("blakejs");
19
+ const { blake2bFinal, blake2bInit, blake2bUpdate } = (await import("blakejs")).default;
19
20
  let data = initData;
20
21
 
21
22
  if (!(data instanceof Buffer)) {
@@ -32,8 +33,6 @@ async function blake256(initData: Buffer | string) {
32
33
  }
33
34
 
34
35
  export async function encryptToKeyStore(phrase: string, password: string) {
35
- const { pbkdf2Sync, randomBytes, createCipheriv } = await import("crypto");
36
-
37
36
  const cipher = "aes-128-ctr";
38
37
  const iv = randomBytes(16);
39
38
  const salt = randomBytes(32);
@@ -71,7 +70,6 @@ export function validatePhrase(phrase: string) {
71
70
  }
72
71
 
73
72
  export async function decryptFromKeystore(keystore: Keystore, password: string) {
74
- const { createDecipheriv, pbkdf2Sync } = await import("crypto");
75
73
  const { SwapKitError } = await import("@swapkit/helpers");
76
74
 
77
75
  switch (keystore.version) {
@@ -23,6 +23,8 @@ export const keystoreWallet = createWallet({
23
23
  Chain.Chainflip,
24
24
  Chain.Ripple,
25
25
  Chain.Solana,
26
+ Chain.Tron,
27
+ Chain.Near,
26
28
  ],
27
29
  connect: ({ addChain, supportedChains, walletType }) =>
28
30
  async function connectKeystore(
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  type DerivationPathArray,
3
3
  NetworkDerivationPath,
4
+ SwapKitError,
4
5
  derivationPathToString,
5
6
  } from "@swapkit/helpers";
6
7
  import { CosmosLedgerInterface } from "../interfaces/CosmosLedgerInterface";
@@ -41,7 +42,7 @@ export class CosmosLedger extends CosmosLedgerInterface {
41
42
  rawTx,
42
43
  );
43
44
 
44
- if (!this.pubKey) throw new Error("Public Key not found");
45
+ if (!this.pubKey) throw new SwapKitError("wallet_ledger_pubkey_not_found");
45
46
 
46
47
  this.validateResponse(return_code, error_message);
47
48
 
@@ -61,11 +62,11 @@ export class CosmosLedger extends CosmosLedgerInterface {
61
62
  const accountIndex = accounts.findIndex((account) => account.address === signerAddress);
62
63
 
63
64
  if (accountIndex === -1) {
64
- throw new Error(`Address ${signerAddress} not found in wallet`);
65
+ throw new SwapKitError("wallet_ledger_address_not_found", { address: signerAddress });
65
66
  }
66
67
 
67
- const { encodeSecp256k1Signature, serializeSignDoc } = await import("@cosmjs/amino");
68
- const { Secp256k1Signature } = await import("@cosmjs/crypto");
68
+ const { encodeSecp256k1Signature, serializeSignDoc } = (await import("@cosmjs/amino")).default;
69
+ const { Secp256k1Signature } = (await import("@cosmjs/crypto")).default;
69
70
 
70
71
  const message = serializeSignDoc(signDoc);
71
72
  const signature = await this.ledgerApp.sign(this.derivationPath, message);
@@ -3,6 +3,7 @@ import {
3
3
  ChainId,
4
4
  type DerivationPathArray,
5
5
  NetworkDerivationPath,
6
+ SwapKitError,
6
7
  derivationPathToString,
7
8
  } from "@swapkit/helpers";
8
9
  import { AbstractSigner, type Provider, type TransactionRequest } from "ethers";
@@ -51,14 +52,14 @@ class EVMLedgerInterface extends AbstractSigner {
51
52
 
52
53
  createTransportAndLedger = async () => {
53
54
  const transport = await getLedgerTransport();
54
- const { default: EthereumApp } = await import("@ledgerhq/hw-app-eth");
55
+ const EthereumApp = (await import("@ledgerhq/hw-app-eth")).default;
55
56
 
56
57
  this.ledgerApp = new EthereumApp(transport);
57
58
  };
58
59
 
59
60
  getAddress = async () => {
60
61
  const response = await this.getAddressAndPubKey();
61
- if (!response) throw new Error("Could not get Address");
62
+ if (!response) throw new SwapKitError("wallet_ledger_failed_to_get_address");
62
63
  return response.address;
63
64
  };
64
65
 
@@ -78,7 +79,7 @@ class EVMLedgerInterface extends AbstractSigner {
78
79
 
79
80
  const sig = await this.ledgerApp?.signPersonalMessage(this.derivationPath, messageHex);
80
81
 
81
- if (!sig) throw new Error("Signing failed");
82
+ if (!sig) throw new SwapKitError("wallet_ledger_signing_error");
82
83
 
83
84
  sig.r = `0x${sig.r}`;
84
85
  sig.s = `0x${sig.s}`;
@@ -86,7 +87,7 @@ class EVMLedgerInterface extends AbstractSigner {
86
87
  };
87
88
 
88
89
  sendTransaction = async (tx: TransactionRequest): Promise<any> => {
89
- if (!this.provider) throw new Error("No provider set");
90
+ if (!this.provider) throw new SwapKitError("wallet_ledger_no_provider");
90
91
 
91
92
  const signedTxHex = await this.signTransaction(tx);
92
93
 
@@ -94,7 +95,7 @@ class EVMLedgerInterface extends AbstractSigner {
94
95
  };
95
96
 
96
97
  signTypedData(): Promise<string> {
97
- throw new Error("Method not implemented.");
98
+ throw new SwapKitError("wallet_ledger_method_not_supported", { method: "signTypedData" });
98
99
  }
99
100
 
100
101
  signTransaction = async (tx: TransactionRequest) => {
@@ -141,7 +142,7 @@ class EVMLedgerInterface extends AbstractSigner {
141
142
  resolution,
142
143
  );
143
144
 
144
- if (!signature) throw new Error("Could not sign transaction");
145
+ if (!signature) throw new SwapKitError("wallet_ledger_signing_error");
145
146
 
146
147
  const { r, s, v } = signature;
147
148
 
@@ -0,0 +1,86 @@
1
+ import type Transport from "@ledgerhq/hw-transport";
2
+ import type { DerivationPathArray } from "@swapkit/helpers";
3
+ import type { NearSigner } from "@swapkit/toolboxes/near";
4
+ import type { SignedTransaction, Transaction } from "near-api-js/lib/transaction";
5
+
6
+ export async function getNearLedgerClient(
7
+ transport: Transport,
8
+ derivationPath?: DerivationPathArray,
9
+ ) {
10
+ const Near = await import("@ledgerhq/hw-app-near");
11
+ const { Chain, DerivationPath, derivationPathToString, SwapKitError } = await import(
12
+ "@swapkit/helpers"
13
+ );
14
+ const nearApp = new Near.default(transport);
15
+
16
+ // NEAR uses m/44'/397'/0'/0'/0' by default
17
+ const path = derivationPath ? derivationPathToString(derivationPath) : DerivationPath[Chain.Near];
18
+
19
+ // Get address and public key from Ledger
20
+ const { address, publicKey: pubKeyHex } = await nearApp.getAddress(path);
21
+
22
+ const signer = {
23
+ async getPublicKey() {
24
+ const { utils } = await import("near-api-js");
25
+ // Convert hex public key to NEAR PublicKey format
26
+ return utils.PublicKey.fromString(`ed25519:${pubKeyHex}`);
27
+ },
28
+
29
+ signNep413Message(
30
+ _message: string,
31
+ _accountId: string,
32
+ _recipient: string,
33
+ _nonce: Uint8Array,
34
+ _callbackUrl?: string,
35
+ ) {
36
+ // Most NEAR Ledger apps don't support arbitrary message signing
37
+ return Promise.reject(
38
+ new SwapKitError("wallet_ledger_method_not_supported", {
39
+ wallet: "Ledger",
40
+ method: "signNep413Message",
41
+ }),
42
+ );
43
+ },
44
+
45
+ getAddress() {
46
+ return Promise.resolve(address);
47
+ },
48
+
49
+ async signTransaction(transaction: Transaction) {
50
+ const { Signature, SignedTransaction } = await import("near-api-js/lib/transaction");
51
+ try {
52
+ const signatureArray = await nearApp.signTransaction(transaction.encode(), path);
53
+ if (!signatureArray) {
54
+ throw new Error("Signature undefined");
55
+ }
56
+
57
+ const signature = new Signature({
58
+ keyType: 0,
59
+ data: signatureArray,
60
+ });
61
+
62
+ const signedTransaction = new SignedTransaction({ transaction, signature });
63
+
64
+ return [signatureArray, signedTransaction] as [
65
+ Uint8Array<ArrayBufferLike>,
66
+ SignedTransaction,
67
+ ];
68
+ } catch (error) {
69
+ throw new SwapKitError("wallet_ledger_signing_error", {
70
+ error,
71
+ });
72
+ }
73
+ },
74
+
75
+ signDelegateAction(_delegateAction: any) {
76
+ return Promise.reject(
77
+ new SwapKitError("wallet_ledger_method_not_supported", {
78
+ wallet: "Ledger",
79
+ method: "signDelegateAction",
80
+ }),
81
+ );
82
+ },
83
+ };
84
+
85
+ return signer as NearSigner;
86
+ }
@@ -1,3 +1,4 @@
1
+ import { SwapKitError } from "@swapkit/helpers";
1
2
  import {
2
3
  CLA,
3
4
  ERROR_CODE,
@@ -10,10 +11,10 @@ import {
10
11
 
11
12
  export function serializePathv1(path: number[]) {
12
13
  if (path == null || path.length < 3) {
13
- throw new Error("Invalid path.");
14
+ throw new SwapKitError("wallet_ledger_invalid_params", { reason: "Path too short" });
14
15
  }
15
16
  if (path.length > 10) {
16
- throw new Error("Invalid path. Length should be <= 10");
17
+ throw new SwapKitError("wallet_ledger_invalid_params", { reason: "Path too long" });
17
18
  }
18
19
  const buf = Buffer.alloc(1 + 4 * path.length);
19
20
  buf.writeUInt8(path.length, 0);
@@ -61,7 +62,9 @@ export async function signSendChunkv1(
61
62
 
62
63
  function compressPublicKey(publicKey: Buffer) {
63
64
  if (publicKey.length !== 65) {
64
- throw new Error("decompressed public key length should be 65 bytes");
65
+ throw new SwapKitError("wallet_ledger_invalid_params", {
66
+ reason: "decompressed public key length should be 65 bytes",
67
+ });
65
68
  }
66
69
  const y = publicKey.slice(33, 65);
67
70
 
@@ -90,7 +93,9 @@ export async function publicKeyv1(app: any, data: Buffer) {
90
93
 
91
94
  export function serializePathv2(path: number[]) {
92
95
  if (!path || path.length !== 5) {
93
- throw new Error("Invalid path.");
96
+ throw new SwapKitError("wallet_ledger_invalid_params", {
97
+ reason: "Path must be exactly 5 elements",
98
+ });
94
99
  }
95
100
 
96
101
  const buf = Buffer.alloc(20);
@@ -1,5 +1,5 @@
1
1
  import { base64 } from "@scure/base";
2
- import { type DerivationPathArray, NetworkDerivationPath } from "@swapkit/helpers";
2
+ import { type DerivationPathArray, NetworkDerivationPath, SwapKitError } from "@swapkit/helpers";
3
3
 
4
4
  import { CosmosLedgerInterface } from "../../interfaces/CosmosLedgerInterface";
5
5
  import type { GetAddressAndPubKeyResponse } from "../../types";
@@ -64,7 +64,7 @@ export class THORChainLedger extends CosmosLedgerInterface {
64
64
  rawTx,
65
65
  );
66
66
 
67
- if (!this.pubKey) throw new Error("Public Key not found");
67
+ if (!this.pubKey) throw new SwapKitError("wallet_ledger_pubkey_not_found");
68
68
 
69
69
  this.validateResponse(return_code, error_message);
70
70
 
@@ -85,7 +85,7 @@ export class THORChainLedger extends CosmosLedgerInterface {
85
85
  message,
86
86
  );
87
87
 
88
- if (!this.pubKey) throw new Error("Public Key not found");
88
+ if (!this.pubKey) throw new SwapKitError("wallet_ledger_pubkey_not_found");
89
89
 
90
90
  this.validateResponse(return_code, error_message);
91
91
 
@@ -1,4 +1,5 @@
1
1
  import type Transport from "@ledgerhq/hw-transport";
2
+ import { SwapKitError } from "@swapkit/helpers";
2
3
  /** ******************************************************************************
3
4
  * (c) 2019 ZondaX GmbH
4
5
  * (c) 2016-2017 Ledger
@@ -42,7 +43,7 @@ export class THORChainApp {
42
43
 
43
44
  constructor(transport: any) {
44
45
  if (!transport) {
45
- throw new Error("Transport has not been defined");
46
+ throw new SwapKitError("wallet_ledger_transport_not_defined");
46
47
  }
47
48
 
48
49
  this.transport = transport;
@@ -50,7 +51,7 @@ export class THORChainApp {
50
51
 
51
52
  static serializeHRP(hrp: string) {
52
53
  if (hrp == null || hrp.length < 3 || hrp.length > 83) {
53
- throw new Error("Invalid HRP");
54
+ throw new SwapKitError("wallet_ledger_invalid_params", { reason: "Invalid HRP" });
54
55
  }
55
56
  const buf = Buffer.alloc(1 + hrp.length);
56
57
  buf.writeUInt8(hrp.length, 0);
@@ -1,19 +1,26 @@
1
1
  import { base64 } from "@scure/base";
2
+ import { SwapKitError } from "@swapkit/helpers";
2
3
 
3
4
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: any: refactor
4
5
  export const getSignature = (signatureArray: any) => {
5
6
  // Check Type Length Value encoding
6
7
  if (signatureArray.length < 64) {
7
- throw new Error("Invalid Signature: Too short");
8
+ throw new SwapKitError("wallet_ledger_invalid_signature", { reason: "Too short" });
8
9
  }
9
10
  if (signatureArray[0] !== 0x30) {
10
- throw new Error("Invalid Ledger Signature TLV encoding: expected first byte 0x30");
11
+ throw new SwapKitError("wallet_ledger_invalid_signature", {
12
+ reason: "TLV encoding: expected first byte 0x30",
13
+ });
11
14
  }
12
15
  if (signatureArray[1] + 2 !== signatureArray.length) {
13
- throw new Error("Invalid Signature: signature length does not match TLV");
16
+ throw new SwapKitError("wallet_ledger_invalid_signature", {
17
+ reason: "signature length does not match TLV",
18
+ });
14
19
  }
15
20
  if (signatureArray[2] !== 0x02) {
16
- throw new Error("Invalid Ledger Signature TLV encoding: expected length type 0x02");
21
+ throw new SwapKitError("wallet_ledger_invalid_signature", {
22
+ reason: "TLV encoding: expected length type 0x02",
23
+ });
17
24
  }
18
25
 
19
26
  // r signature
@@ -24,7 +31,7 @@ export const getSignature = (signatureArray: any) => {
24
31
  if (rSignature.length === 33 && rSignature[0] === 0) {
25
32
  rSignature = rSignature.slice(1, 33);
26
33
  } else if (rSignature.length === 33) {
27
- throw new Error('Invalid signature: "r" too long');
34
+ throw new SwapKitError("wallet_ledger_invalid_signature", { reason: "r too long" });
28
35
  }
29
36
 
30
37
  // add leading zero's to pad to 32 bytes
@@ -34,13 +41,17 @@ export const getSignature = (signatureArray: any) => {
34
41
 
35
42
  // s signature
36
43
  if (signatureArray[rLength + 4] !== 0x02) {
37
- throw new Error("Invalid Ledger Signature TLV encoding: expected length type 0x02");
44
+ throw new SwapKitError("wallet_ledger_invalid_signature", {
45
+ reason: "TLV encoding: expected length type 0x02 for s",
46
+ });
38
47
  }
39
48
 
40
49
  const sLength = signatureArray[rLength + 5];
41
50
 
42
51
  if (4 + rLength + 2 + sLength !== signatureArray.length) {
43
- throw new Error("Invalid Ledger Signature: TLV byte lengths do not match message length");
52
+ throw new SwapKitError("wallet_ledger_invalid_signature", {
53
+ reason: "TLV byte lengths do not match message length",
54
+ });
44
55
  }
45
56
 
46
57
  let sSignature = signatureArray.slice(rLength + 6, signatureArray.length);
@@ -49,7 +60,7 @@ export const getSignature = (signatureArray: any) => {
49
60
  if (sSignature.length === 33 && sSignature[0] === 0) {
50
61
  sSignature = sSignature.slice(1, 33);
51
62
  } else if (sSignature.length === 33) {
52
- throw new Error('Invalid signature: "s" too long');
63
+ throw new SwapKitError("wallet_ledger_invalid_signature", { reason: "s too long" });
53
64
  }
54
65
 
55
66
  // add leading zero's to pad to 32 bytes
@@ -58,7 +69,7 @@ export const getSignature = (signatureArray: any) => {
58
69
  }
59
70
 
60
71
  if (rSignature.length !== 32 || sSignature.length !== 32) {
61
- throw new Error("Invalid signatures: must be 32 bytes each");
72
+ throw new SwapKitError("wallet_ledger_invalid_signature", { reason: "must be 32 bytes each" });
62
73
  }
63
74
 
64
75
  return base64.encode(Buffer.concat([rSignature, sSignature]));
@@ -7,7 +7,7 @@ import {
7
7
  getWalletFormatFor,
8
8
  } from "@swapkit/helpers";
9
9
  import type { UTXOType } from "@swapkit/toolboxes/utxo";
10
- import type { Psbt } from "bitcoinjs-lib";
10
+ import { type Psbt, Transaction } from "bitcoinjs-lib";
11
11
 
12
12
  import { getLedgerTransport } from "../helpers/getLedgerTransport";
13
13
 
@@ -22,8 +22,6 @@ const signUTXOTransaction = async (
22
22
  { psbt, inputUtxos, btcApp, derivationPath }: Params,
23
23
  options?: Partial<CreateTransactionArg>,
24
24
  ) => {
25
- const { Transaction } = await import("bitcoinjs-lib");
26
-
27
25
  const inputs = inputUtxos.map((item) => {
28
26
  const utxoTx = Transaction.fromHex(item.txHex || "");
29
27
  const splitTx = btcApp.splitTransaction(utxoTx.toHex(), utxoTx.hasWitnesses());
@@ -75,7 +73,7 @@ const BaseLedgerUTXO = ({
75
73
 
76
74
  async function createTransportWebUSB() {
77
75
  transport = await getLedgerTransport();
78
- const { default: BitcoinApp } = await import("@ledgerhq/hw-app-btc");
76
+ const BitcoinApp = (await import("@ledgerhq/hw-app-btc")).default;
79
77
 
80
78
  btcApp = new BitcoinApp({ transport, currency: chain });
81
79
  }
@@ -91,7 +89,7 @@ const BaseLedgerUTXO = ({
91
89
  return {
92
90
  connect: async () => {
93
91
  await checkBtcAppAndCreateTransportWebUSB(false);
94
- const { default: BitcoinApp } = await import("@ledgerhq/hw-app-btc");
92
+ const BitcoinApp = (await import("@ledgerhq/hw-app-btc")).default;
95
93
 
96
94
  btcApp = new BitcoinApp({ transport, currency: chain });
97
95
  },
@@ -0,0 +1,66 @@
1
+ import type Xrp from "@ledgerhq/hw-app-xrp";
2
+ import type Transport from "@ledgerhq/hw-transport";
3
+ import {
4
+ Chain,
5
+ type DerivationPathArray,
6
+ NetworkDerivationPath,
7
+ derivationPathToString,
8
+ } from "@swapkit/helpers";
9
+ import type { Transaction } from "@swapkit/toolboxes/ripple";
10
+ import { encode } from "ripple-binary-codec";
11
+ import type { Payment } from "xrpl";
12
+ import { getLedgerTransport } from "../helpers";
13
+
14
+ const TF_FULLY_CANONICAL_SIG = 2147483648;
15
+
16
+ function cleanTransactionObject(obj: Record<string, any>) {
17
+ const cleaned: Record<string, any> = {};
18
+ for (const key in obj) {
19
+ if (obj[key] !== null && obj[key] !== undefined) {
20
+ cleaned[key] = obj[key];
21
+ }
22
+ }
23
+ return cleaned;
24
+ }
25
+
26
+ async function establishConnection(transport: Transport) {
27
+ const { default: Xrp } = await import("@ledgerhq/hw-app-xrp");
28
+ return new Xrp(transport);
29
+ }
30
+
31
+ function fetchAddressAndPublicKey({
32
+ instance,
33
+ derivationPath,
34
+ }: { instance: Xrp; derivationPath: string }) {
35
+ return instance.getAddress(derivationPath);
36
+ }
37
+
38
+ export const XRPLedger = async (derivationPath?: DerivationPathArray) => {
39
+ const path = derivationPathToString(derivationPath || NetworkDerivationPath[Chain.Ripple]);
40
+ const transport = await getLedgerTransport();
41
+ const xrpInstance = await establishConnection(transport);
42
+
43
+ const { address, publicKey } = await fetchAddressAndPublicKey({
44
+ instance: xrpInstance,
45
+ derivationPath: path,
46
+ });
47
+
48
+ async function sign(transaction: Payment | Transaction) {
49
+ const { hashes } = await import("@swapkit/toolboxes/ripple");
50
+ const cleanedTxWithPubKey = cleanTransactionObject(transaction);
51
+ const transactionJSON = {
52
+ ...cleanedTxWithPubKey,
53
+ Flags: transaction.Flags || TF_FULLY_CANONICAL_SIG,
54
+ SigningPubKey: publicKey.toUpperCase(),
55
+ };
56
+
57
+ const transactionToSignOnLedger = encode(transactionJSON);
58
+ const txnSignature = await xrpInstance.signTransaction(path, transactionToSignOnLedger);
59
+ const tx_blob = encode({ ...transactionJSON, TxnSignature: txnSignature });
60
+ const hash = hashes.hashSignedTx(tx_blob);
61
+
62
+ return { tx_blob, hash };
63
+ }
64
+
65
+ return { address, sign };
66
+ };