@tcswap/wallet-hardware 4.2.16
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.
- package/dist/chunk-1w9rn6fj.js +5 -0
- package/dist/chunk-1w9rn6fj.js.map +10 -0
- package/dist/chunk-1z3vq8v6.js +4 -0
- package/dist/chunk-1z3vq8v6.js.map +10 -0
- package/dist/chunk-3jd7804n.js +4 -0
- package/dist/chunk-3jd7804n.js.map +10 -0
- package/dist/chunk-4pybhxzx.js +4 -0
- package/dist/chunk-4pybhxzx.js.map +10 -0
- package/dist/chunk-9kbkdt6e.js +4 -0
- package/dist/chunk-9kbkdt6e.js.map +10 -0
- package/dist/chunk-eng8tyvd.js +4 -0
- package/dist/chunk-eng8tyvd.js.map +10 -0
- package/dist/chunk-fazw0jvt.js +4 -0
- package/dist/chunk-fazw0jvt.js.map +9 -0
- package/dist/chunk-zzfbcc7e.js +5 -0
- package/dist/chunk-zzfbcc7e.js.map +9 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +9 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +9 -0
- package/dist/keepkey/index.cjs +4 -0
- package/dist/keepkey/index.cjs.map +15 -0
- package/dist/keepkey/index.js +4 -0
- package/dist/keepkey/index.js.map +15 -0
- package/dist/ledger/index.cjs +5 -0
- package/dist/ledger/index.cjs.map +25 -0
- package/dist/ledger/index.js +5 -0
- package/dist/ledger/index.js.map +25 -0
- package/dist/trezor/index.cjs +4 -0
- package/dist/trezor/index.cjs.map +10 -0
- package/dist/trezor/index.js +4 -0
- package/dist/trezor/index.js.map +10 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/keepkey/chains/cosmos.d.ts +7 -0
- package/dist/types/keepkey/chains/cosmos.d.ts.map +1 -0
- package/dist/types/keepkey/chains/evm.d.ts +29 -0
- package/dist/types/keepkey/chains/evm.d.ts.map +1 -0
- package/dist/types/keepkey/chains/mayachain.d.ts +10 -0
- package/dist/types/keepkey/chains/mayachain.d.ts.map +1 -0
- package/dist/types/keepkey/chains/ripple.d.ts +37 -0
- package/dist/types/keepkey/chains/ripple.d.ts.map +1 -0
- package/dist/types/keepkey/chains/thorchain.d.ts +10 -0
- package/dist/types/keepkey/chains/thorchain.d.ts.map +1 -0
- package/dist/types/keepkey/chains/utxo.d.ts +25 -0
- package/dist/types/keepkey/chains/utxo.d.ts.map +1 -0
- package/dist/types/keepkey/coins.d.ts +15 -0
- package/dist/types/keepkey/coins.d.ts.map +1 -0
- package/dist/types/keepkey/index.d.ts +15 -0
- package/dist/types/keepkey/index.d.ts.map +1 -0
- package/dist/types/ledger/clients/cosmos.d.ts +23 -0
- package/dist/types/ledger/clients/cosmos.d.ts.map +1 -0
- package/dist/types/ledger/clients/evm.d.ts +52 -0
- package/dist/types/ledger/clients/evm.d.ts.map +1 -0
- package/dist/types/ledger/clients/near.d.ts +7 -0
- package/dist/types/ledger/clients/near.d.ts.map +1 -0
- package/dist/types/ledger/clients/thorchain/common.d.ts +28 -0
- package/dist/types/ledger/clients/thorchain/common.d.ts.map +1 -0
- package/dist/types/ledger/clients/thorchain/helpers.d.ts +10 -0
- package/dist/types/ledger/clients/thorchain/helpers.d.ts.map +1 -0
- package/dist/types/ledger/clients/thorchain/index.d.ts +25 -0
- package/dist/types/ledger/clients/thorchain/index.d.ts.map +1 -0
- package/dist/types/ledger/clients/thorchain/lib.d.ts +25 -0
- package/dist/types/ledger/clients/thorchain/lib.d.ts.map +1 -0
- package/dist/types/ledger/clients/thorchain/utils.d.ts +5 -0
- package/dist/types/ledger/clients/thorchain/utils.d.ts.map +1 -0
- package/dist/types/ledger/clients/tron.d.ts +26 -0
- package/dist/types/ledger/clients/tron.d.ts.map +1 -0
- package/dist/types/ledger/clients/utxo.d.ts +43 -0
- package/dist/types/ledger/clients/utxo.d.ts.map +1 -0
- package/dist/types/ledger/clients/xrp.d.ts +11 -0
- package/dist/types/ledger/clients/xrp.d.ts.map +1 -0
- package/dist/types/ledger/cosmosTypes.d.ts +43 -0
- package/dist/types/ledger/cosmosTypes.d.ts.map +1 -0
- package/dist/types/ledger/helpers/getLedgerAddress.d.ts +10 -0
- package/dist/types/ledger/helpers/getLedgerAddress.d.ts.map +1 -0
- package/dist/types/ledger/helpers/getLedgerClient.d.ts +42 -0
- package/dist/types/ledger/helpers/getLedgerClient.d.ts.map +1 -0
- package/dist/types/ledger/helpers/getLedgerTransport.d.ts +6 -0
- package/dist/types/ledger/helpers/getLedgerTransport.d.ts.map +1 -0
- package/dist/types/ledger/helpers/index.d.ts +4 -0
- package/dist/types/ledger/helpers/index.d.ts.map +1 -0
- package/dist/types/ledger/index.d.ts +14 -0
- package/dist/types/ledger/index.d.ts.map +1 -0
- package/dist/types/ledger/interfaces/CosmosLedgerInterface.d.ts +14 -0
- package/dist/types/ledger/interfaces/CosmosLedgerInterface.d.ts.map +1 -0
- package/dist/types/ledger/types.d.ts +16 -0
- package/dist/types/ledger/types.d.ts.map +1 -0
- package/dist/types/trezor/evmSigner.d.ts +32 -0
- package/dist/types/trezor/evmSigner.d.ts.map +1 -0
- package/dist/types/trezor/index.d.ts +14 -0
- package/dist/types/trezor/index.d.ts.map +1 -0
- package/package.json +101 -0
- package/src/index.ts +1 -0
- package/src/keepkey/chains/cosmos.ts +69 -0
- package/src/keepkey/chains/evm.ts +117 -0
- package/src/keepkey/chains/mayachain.ts +102 -0
- package/src/keepkey/chains/ripple.ts +88 -0
- package/src/keepkey/chains/thorchain.ts +97 -0
- package/src/keepkey/chains/utxo.ts +141 -0
- package/src/keepkey/coins.ts +70 -0
- package/src/keepkey/index.ts +159 -0
- package/src/ledger/clients/cosmos.ts +83 -0
- package/src/ledger/clients/evm.ts +145 -0
- package/src/ledger/clients/near.ts +67 -0
- package/src/ledger/clients/thorchain/common.ts +93 -0
- package/src/ledger/clients/thorchain/helpers.ts +124 -0
- package/src/ledger/clients/thorchain/index.ts +91 -0
- package/src/ledger/clients/thorchain/lib.ts +282 -0
- package/src/ledger/clients/thorchain/utils.ts +71 -0
- package/src/ledger/clients/tron.ts +84 -0
- package/src/ledger/clients/utxo.ts +158 -0
- package/src/ledger/clients/xrp.ts +50 -0
- package/src/ledger/cosmosTypes.ts +102 -0
- package/src/ledger/helpers/getLedgerAddress.ts +73 -0
- package/src/ledger/helpers/getLedgerClient.ts +121 -0
- package/src/ledger/helpers/getLedgerTransport.ts +106 -0
- package/src/ledger/helpers/index.ts +3 -0
- package/src/ledger/index.ts +303 -0
- package/src/ledger/interfaces/CosmosLedgerInterface.ts +58 -0
- package/src/ledger/types.ts +40 -0
- package/src/trezor/evmSigner.ts +181 -0
- package/src/trezor/index.ts +350 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modifications © 2025 Horizontal Systems.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Chain,
|
|
7
|
+
type DerivationPathArray,
|
|
8
|
+
FeeOption,
|
|
9
|
+
filterSupportedChains,
|
|
10
|
+
type GenericTransferParams,
|
|
11
|
+
getRPCUrl,
|
|
12
|
+
THORConfig,
|
|
13
|
+
USwapError,
|
|
14
|
+
WalletOption,
|
|
15
|
+
} from "@tcswap/helpers";
|
|
16
|
+
import type { ThorchainDepositParams } from "@tcswap/toolboxes/cosmos";
|
|
17
|
+
import type { UTXOBuildTxParams } from "@tcswap/toolboxes/utxo";
|
|
18
|
+
|
|
19
|
+
import { createWallet, getWalletSupportedChains } from "@tcswap/wallet-core";
|
|
20
|
+
import { getLedgerAddress, getLedgerClient } from "./helpers";
|
|
21
|
+
|
|
22
|
+
export const ledgerWallet = createWallet({
|
|
23
|
+
connect: ({ addChain, supportedChains, walletType }) =>
|
|
24
|
+
async function connectLedger(chains: Chain[], derivationPath?: DerivationPathArray) {
|
|
25
|
+
const [chain] = filterSupportedChains({ chains, supportedChains, walletType });
|
|
26
|
+
|
|
27
|
+
if (!chain) return false;
|
|
28
|
+
|
|
29
|
+
const walletMethods = await getWalletMethods({ chain, derivationPath });
|
|
30
|
+
|
|
31
|
+
addChain({ ...walletMethods, chain, walletType: WalletOption.LEDGER });
|
|
32
|
+
|
|
33
|
+
return true;
|
|
34
|
+
},
|
|
35
|
+
name: "connectLedger",
|
|
36
|
+
supportedChains: [
|
|
37
|
+
Chain.Arbitrum,
|
|
38
|
+
Chain.Aurora,
|
|
39
|
+
Chain.Avalanche,
|
|
40
|
+
Chain.Base,
|
|
41
|
+
Chain.BinanceSmartChain,
|
|
42
|
+
Chain.Bitcoin,
|
|
43
|
+
Chain.BitcoinCash,
|
|
44
|
+
Chain.Cosmos,
|
|
45
|
+
Chain.Dash,
|
|
46
|
+
Chain.Dogecoin,
|
|
47
|
+
Chain.Ethereum,
|
|
48
|
+
Chain.Gnosis,
|
|
49
|
+
Chain.Litecoin,
|
|
50
|
+
Chain.Monad,
|
|
51
|
+
Chain.Near,
|
|
52
|
+
Chain.Optimism,
|
|
53
|
+
Chain.Polygon,
|
|
54
|
+
Chain.Ripple,
|
|
55
|
+
Chain.THORChain,
|
|
56
|
+
Chain.XLayer,
|
|
57
|
+
Chain.Tron,
|
|
58
|
+
Chain.Zcash,
|
|
59
|
+
],
|
|
60
|
+
walletType: WalletOption.LEDGER,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const LEDGER_SUPPORTED_CHAINS = getWalletSupportedChains(ledgerWallet);
|
|
64
|
+
|
|
65
|
+
// reduce memo length by removing trade limit
|
|
66
|
+
function reduceMemo(memo?: string, affiliateAddress = "t") {
|
|
67
|
+
if (!memo?.includes("=:")) return memo;
|
|
68
|
+
|
|
69
|
+
const removedAffiliate = memo.includes(`:${affiliateAddress}:`) ? memo.split(`:${affiliateAddress}:`)[0] : memo;
|
|
70
|
+
|
|
71
|
+
return removedAffiliate?.substring(0, removedAffiliate.lastIndexOf(":"));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function recursivelyOrderKeys(unordered: any) {
|
|
75
|
+
// If it's an array - recursively order any
|
|
76
|
+
// dictionary items within the array
|
|
77
|
+
if (Array.isArray(unordered)) {
|
|
78
|
+
unordered.forEach((item, index) => {
|
|
79
|
+
unordered[index] = recursivelyOrderKeys(item);
|
|
80
|
+
});
|
|
81
|
+
return unordered;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// If it's an object - let's order the keys
|
|
85
|
+
if (typeof unordered !== "object") return unordered;
|
|
86
|
+
const ordered: any = {};
|
|
87
|
+
const sortedKeys = Object.keys(unordered).sort();
|
|
88
|
+
|
|
89
|
+
for (const key of sortedKeys) {
|
|
90
|
+
ordered[key] = recursivelyOrderKeys(unordered[key]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return ordered;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function stringifyKeysInOrder(data: any) {
|
|
97
|
+
return JSON.stringify(recursivelyOrderKeys(data));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function getWalletMethods({ chain, derivationPath }: { chain: Chain; derivationPath?: DerivationPathArray }) {
|
|
101
|
+
switch (chain) {
|
|
102
|
+
case Chain.BitcoinCash:
|
|
103
|
+
case Chain.Bitcoin:
|
|
104
|
+
case Chain.Dash:
|
|
105
|
+
case Chain.Dogecoin:
|
|
106
|
+
case Chain.Litecoin:
|
|
107
|
+
case Chain.Zcash: {
|
|
108
|
+
const { getUtxoToolbox } = await import("@tcswap/toolboxes/utxo");
|
|
109
|
+
const toolbox = await getUtxoToolbox(chain as typeof Chain.Bitcoin);
|
|
110
|
+
|
|
111
|
+
const signer = await getLedgerClient({ chain, derivationPath });
|
|
112
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
113
|
+
|
|
114
|
+
const transfer = async (params: UTXOBuildTxParams) => {
|
|
115
|
+
const feeRate = params.feeRate || (await toolbox.getFeeRates())[FeeOption.Average];
|
|
116
|
+
const memo = [Chain.Bitcoin].includes(chain as typeof Chain.Bitcoin) ? params.memo : reduceMemo(params.memo);
|
|
117
|
+
|
|
118
|
+
const { psbt, inputs } = await toolbox.createTransaction({
|
|
119
|
+
...params,
|
|
120
|
+
feeRate,
|
|
121
|
+
fetchTxHex: true,
|
|
122
|
+
memo,
|
|
123
|
+
sender: address,
|
|
124
|
+
});
|
|
125
|
+
const txHex = await signer.signTransaction(psbt, inputs);
|
|
126
|
+
const tx = await toolbox.broadcastTx(txHex);
|
|
127
|
+
|
|
128
|
+
return tx;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return { ...toolbox, address, transfer };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
case Chain.Ethereum:
|
|
135
|
+
case Chain.Avalanche:
|
|
136
|
+
case Chain.Arbitrum:
|
|
137
|
+
case Chain.Optimism:
|
|
138
|
+
case Chain.Polygon:
|
|
139
|
+
case Chain.BinanceSmartChain:
|
|
140
|
+
case Chain.Base:
|
|
141
|
+
case Chain.Aurora:
|
|
142
|
+
case Chain.Gnosis:
|
|
143
|
+
case Chain.Monad:
|
|
144
|
+
case Chain.XLayer: {
|
|
145
|
+
const { getEvmToolbox } = await import("@tcswap/toolboxes/evm");
|
|
146
|
+
const signer = await getLedgerClient({ chain, derivationPath });
|
|
147
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
148
|
+
const toolbox = await getEvmToolbox(chain, { signer });
|
|
149
|
+
|
|
150
|
+
return { ...toolbox, address };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
case Chain.Cosmos: {
|
|
154
|
+
const { createSigningStargateClient, getMsgSendDenom, getCosmosToolbox } = await import(
|
|
155
|
+
"@tcswap/toolboxes/cosmos"
|
|
156
|
+
);
|
|
157
|
+
const toolbox = await getCosmosToolbox(Chain.Cosmos);
|
|
158
|
+
const signer = await getLedgerClient({ chain, derivationPath });
|
|
159
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
160
|
+
|
|
161
|
+
const transfer = async ({ assetValue, recipient, memo }: GenericTransferParams) => {
|
|
162
|
+
if (!assetValue) throw new USwapError("wallet_ledger_invalid_asset");
|
|
163
|
+
|
|
164
|
+
const sendCoinsMessage = {
|
|
165
|
+
amount: [
|
|
166
|
+
{
|
|
167
|
+
amount: assetValue.getBaseValue("string"),
|
|
168
|
+
denom: getMsgSendDenom(`u${assetValue.symbol}`).toLowerCase(),
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
fromAddress: address,
|
|
172
|
+
toAddress: recipient,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const rpcUrl = await getRPCUrl(chain);
|
|
176
|
+
const signingClient = await createSigningStargateClient(rpcUrl, signer, "0.007uatom");
|
|
177
|
+
|
|
178
|
+
const { transactionHash } = await signingClient.signAndBroadcast(
|
|
179
|
+
address,
|
|
180
|
+
[{ typeUrl: "/cosmos.bank.v1beta1.MsgSend", value: sendCoinsMessage }],
|
|
181
|
+
2,
|
|
182
|
+
memo,
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
return transactionHash;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
return { ...toolbox, address, transfer };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
case Chain.THORChain: {
|
|
192
|
+
const { SignMode } = await import("cosmjs-types/cosmos/tx/signing/v1beta1/signing.js");
|
|
193
|
+
const { TxRaw } = await import("cosmjs-types/cosmos/tx/v1beta1/tx.js");
|
|
194
|
+
const importedSigning = await import("@cosmjs/proto-signing");
|
|
195
|
+
const encodePubkey = importedSigning.encodePubkey ?? importedSigning.default?.encodePubkey;
|
|
196
|
+
const makeAuthInfoBytes = importedSigning.makeAuthInfoBytes ?? importedSigning.default?.makeAuthInfoBytes;
|
|
197
|
+
const {
|
|
198
|
+
createStargateClient,
|
|
199
|
+
buildEncodedTxBody,
|
|
200
|
+
getCosmosToolbox,
|
|
201
|
+
buildAminoMsg,
|
|
202
|
+
getDefaultChainFee,
|
|
203
|
+
fromBase64,
|
|
204
|
+
parseAminoMessageForDirectSigning,
|
|
205
|
+
} = await import("@tcswap/toolboxes/cosmos");
|
|
206
|
+
const toolbox = await getCosmosToolbox(chain);
|
|
207
|
+
const signer = await getLedgerClient({ chain, derivationPath });
|
|
208
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
209
|
+
|
|
210
|
+
const fee = getDefaultChainFee(chain);
|
|
211
|
+
const { pubkey: value, signTransaction, sign: signMessage } = signer;
|
|
212
|
+
|
|
213
|
+
// ANCHOR (@Chillios): Same parts in methods + can extract StargateClient init to toolbox
|
|
214
|
+
const thorchainTransfer = async ({
|
|
215
|
+
memo = "",
|
|
216
|
+
assetValue,
|
|
217
|
+
...rest
|
|
218
|
+
}: GenericTransferParams | ThorchainDepositParams) => {
|
|
219
|
+
const account = await toolbox.getAccount(address);
|
|
220
|
+
if (!account) throw new USwapError("wallet_ledger_invalid_account");
|
|
221
|
+
if (!assetValue) throw new USwapError("wallet_ledger_invalid_asset");
|
|
222
|
+
if (!value) throw new USwapError("wallet_ledger_pubkey_not_found");
|
|
223
|
+
|
|
224
|
+
const { accountNumber, sequence: sequenceNumber } = account;
|
|
225
|
+
const sequence = (sequenceNumber || 0).toString();
|
|
226
|
+
|
|
227
|
+
const orderedMessages = recursivelyOrderKeys([buildAminoMsg({ assetValue, memo, sender: address, ...rest })]);
|
|
228
|
+
|
|
229
|
+
// get tx signing msg
|
|
230
|
+
const rawSendTx = stringifyKeysInOrder({
|
|
231
|
+
account_number: accountNumber?.toString(),
|
|
232
|
+
chain_id: THORConfig.chainId,
|
|
233
|
+
fee,
|
|
234
|
+
memo,
|
|
235
|
+
msgs: orderedMessages,
|
|
236
|
+
sequence,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const signatures = await signTransaction(rawSendTx, sequence);
|
|
240
|
+
if (!signatures) throw new USwapError("wallet_ledger_signing_error");
|
|
241
|
+
|
|
242
|
+
const pubkey = encodePubkey({ type: "tendermint/PubKeySecp256k1", value });
|
|
243
|
+
const msgs = orderedMessages.map(parseAminoMessageForDirectSigning);
|
|
244
|
+
const bodyBytes = await buildEncodedTxBody({ chain, memo, msgs });
|
|
245
|
+
|
|
246
|
+
const authInfoBytes = makeAuthInfoBytes(
|
|
247
|
+
[{ pubkey, sequence: Number(sequence) }],
|
|
248
|
+
fee.amount,
|
|
249
|
+
Number.parseInt(fee.gas, 10),
|
|
250
|
+
undefined,
|
|
251
|
+
undefined,
|
|
252
|
+
SignMode.SIGN_MODE_LEGACY_AMINO_JSON,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const signature = signatures?.[0]?.signature ? fromBase64(signatures[0].signature) : Uint8Array.from([]);
|
|
256
|
+
|
|
257
|
+
const txRaw = TxRaw.fromPartial({ authInfoBytes, bodyBytes, signatures: [signature] });
|
|
258
|
+
const txBytes = TxRaw.encode(txRaw).finish();
|
|
259
|
+
const rpcUrl = await getRPCUrl(Chain.THORChain);
|
|
260
|
+
|
|
261
|
+
const broadcaster = await createStargateClient(rpcUrl);
|
|
262
|
+
const { transactionHash } = await broadcaster.broadcastTx(txBytes);
|
|
263
|
+
|
|
264
|
+
return transactionHash;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const transfer = (params: GenericTransferParams) => thorchainTransfer(params);
|
|
268
|
+
const deposit = (params: ThorchainDepositParams) => thorchainTransfer(params);
|
|
269
|
+
|
|
270
|
+
return { ...toolbox, address, deposit, signMessage, transfer };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
case Chain.Near: {
|
|
274
|
+
const { getNearToolbox } = await import("@tcswap/toolboxes/near");
|
|
275
|
+
const signer = await getLedgerClient({ chain, derivationPath });
|
|
276
|
+
const accountId = await signer.getAddress();
|
|
277
|
+
const toolbox = await getNearToolbox({ signer });
|
|
278
|
+
|
|
279
|
+
return { ...toolbox, address: accountId };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
case Chain.Ripple: {
|
|
283
|
+
const { getRippleToolbox } = await import("@tcswap/toolboxes/ripple");
|
|
284
|
+
const signer = await getLedgerClient({ chain, derivationPath });
|
|
285
|
+
const address = signer.getAddress();
|
|
286
|
+
const toolbox = await getRippleToolbox({ signer });
|
|
287
|
+
|
|
288
|
+
return { ...toolbox, address };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
case Chain.Tron: {
|
|
292
|
+
const { createTronToolbox } = await import("@tcswap/toolboxes/tron");
|
|
293
|
+
const signer = await getLedgerClient({ chain, derivationPath });
|
|
294
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
295
|
+
const toolbox = await createTronToolbox({ signer });
|
|
296
|
+
|
|
297
|
+
return { ...toolbox, address };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
default:
|
|
301
|
+
throw new USwapError("wallet_ledger_chain_not_supported", { chain });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modifications © 2025 Horizontal Systems.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { type DerivationPathArray, LedgerErrorCode, NetworkDerivationPath, USwapError } from "@tcswap/helpers";
|
|
6
|
+
|
|
7
|
+
import { THORChainApp } from "../clients/thorchain/lib";
|
|
8
|
+
import { getLedgerTransport } from "../helpers/getLedgerTransport";
|
|
9
|
+
|
|
10
|
+
export abstract class CosmosLedgerInterface {
|
|
11
|
+
ledgerTimeout = 50000;
|
|
12
|
+
derivationPath: DerivationPathArray | string = NetworkDerivationPath.GAIA;
|
|
13
|
+
transport: any;
|
|
14
|
+
ledgerApp: any;
|
|
15
|
+
chain: "thor" | "cosmos" = "thor";
|
|
16
|
+
|
|
17
|
+
checkOrCreateTransportAndLedger = async (forceReconnect = false) => {
|
|
18
|
+
if (!forceReconnect && this.transport && this.ledgerApp) return;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
this.transport = forceReconnect || !this.transport ? await getLedgerTransport() : this.transport;
|
|
22
|
+
|
|
23
|
+
switch (this.chain) {
|
|
24
|
+
case "thor": {
|
|
25
|
+
this.ledgerApp = forceReconnect || !this.ledgerApp ? new THORChainApp(this.transport) : this.ledgerApp;
|
|
26
|
+
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
case "cosmos": {
|
|
31
|
+
const CosmosApp = (await import("@ledgerhq/hw-app-cosmos")).default;
|
|
32
|
+
this.ledgerApp = forceReconnect || !this.ledgerApp ? new CosmosApp(this.transport) : this.ledgerApp;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return this.ledgerApp;
|
|
37
|
+
} catch (error: unknown) {
|
|
38
|
+
throw new USwapError("wallet_ledger_connection_error", error);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
validateResponse = (errorCode: LedgerErrorCode, message?: string) => {
|
|
43
|
+
switch (errorCode) {
|
|
44
|
+
case LedgerErrorCode.NoError:
|
|
45
|
+
return;
|
|
46
|
+
|
|
47
|
+
case LedgerErrorCode.LockedDevice:
|
|
48
|
+
throw new USwapError("wallet_ledger_device_locked", { message: `Ledger is locked: ${message}` });
|
|
49
|
+
|
|
50
|
+
case LedgerErrorCode.TC_NotFound:
|
|
51
|
+
throw new USwapError("wallet_ledger_device_not_found");
|
|
52
|
+
|
|
53
|
+
default: {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CosmosLedger } from "./clients/cosmos";
|
|
2
|
+
import type {
|
|
3
|
+
ArbitrumLedger,
|
|
4
|
+
AuroraLedger,
|
|
5
|
+
AvalancheLedger,
|
|
6
|
+
BaseLedger,
|
|
7
|
+
BinanceSmartChainLedger,
|
|
8
|
+
EthereumLedger,
|
|
9
|
+
GnosisLedger,
|
|
10
|
+
OptimismLedger,
|
|
11
|
+
PolygonLedger,
|
|
12
|
+
} from "./clients/evm";
|
|
13
|
+
import type { THORChainLedger } from "./clients/thorchain";
|
|
14
|
+
import type { TronLedger } from "./clients/tron";
|
|
15
|
+
import type { BitcoinCashLedger, BitcoinLedger, DogecoinLedger, LitecoinLedger } from "./clients/utxo";
|
|
16
|
+
|
|
17
|
+
export type UTXOLedgerClients =
|
|
18
|
+
| ReturnType<typeof BitcoinLedger>
|
|
19
|
+
| ReturnType<typeof BitcoinCashLedger>
|
|
20
|
+
| ReturnType<typeof DogecoinLedger>
|
|
21
|
+
| ReturnType<typeof LitecoinLedger>;
|
|
22
|
+
export type CosmosLedgerClients = CosmosLedger | THORChainLedger;
|
|
23
|
+
export type EVMLedgerClients =
|
|
24
|
+
| ReturnType<typeof ArbitrumLedger>
|
|
25
|
+
| ReturnType<typeof AuroraLedger>
|
|
26
|
+
| ReturnType<typeof AvalancheLedger>
|
|
27
|
+
| ReturnType<typeof BaseLedger>
|
|
28
|
+
| ReturnType<typeof BinanceSmartChainLedger>
|
|
29
|
+
| ReturnType<typeof GnosisLedger>
|
|
30
|
+
| ReturnType<typeof EthereumLedger>
|
|
31
|
+
| ReturnType<typeof OptimismLedger>
|
|
32
|
+
| ReturnType<typeof PolygonLedger>;
|
|
33
|
+
export type TronLedgerClient = ReturnType<typeof TronLedger>;
|
|
34
|
+
|
|
35
|
+
export type GetAddressAndPubKeyResponse = {
|
|
36
|
+
bech32_address: string;
|
|
37
|
+
compressed_pk: any;
|
|
38
|
+
error_message: string;
|
|
39
|
+
return_code: number;
|
|
40
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modifications © 2025 Horizontal Systems.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
type Chain,
|
|
7
|
+
ChainToChainId,
|
|
8
|
+
type DerivationPathArray,
|
|
9
|
+
derivationPathToString,
|
|
10
|
+
USwapError,
|
|
11
|
+
USwapNumber,
|
|
12
|
+
WalletOption,
|
|
13
|
+
} from "@tcswap/helpers";
|
|
14
|
+
import type { JsonRpcProvider, Provider, TransactionRequest } from "ethers";
|
|
15
|
+
|
|
16
|
+
type TrezorEVMSignerParams = {
|
|
17
|
+
chain: Chain;
|
|
18
|
+
derivationPath: DerivationPathArray;
|
|
19
|
+
provider: Provider | JsonRpcProvider;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export async function getEVMSigner({ chain, derivationPath, provider }: TrezorEVMSignerParams) {
|
|
23
|
+
const { AbstractSigner, Signature } = await import("ethers");
|
|
24
|
+
|
|
25
|
+
class TrezorSigner extends AbstractSigner {
|
|
26
|
+
address: string;
|
|
27
|
+
chain: Chain;
|
|
28
|
+
derivationPath: DerivationPathArray;
|
|
29
|
+
readonly provider: Provider | JsonRpcProvider;
|
|
30
|
+
|
|
31
|
+
constructor({ chain, derivationPath, provider }: TrezorEVMSignerParams) {
|
|
32
|
+
super(provider);
|
|
33
|
+
|
|
34
|
+
this.address = "";
|
|
35
|
+
this.chain = chain;
|
|
36
|
+
this.derivationPath = derivationPath;
|
|
37
|
+
this.provider = provider;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getAddress = async () => {
|
|
41
|
+
if (!this.address) {
|
|
42
|
+
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
43
|
+
|
|
44
|
+
const result = await TrezorConnect.ethereumGetAddress({
|
|
45
|
+
path: derivationPathToString(this.derivationPath),
|
|
46
|
+
showOnTrezor: true,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (!result.success) {
|
|
50
|
+
throw new USwapError({
|
|
51
|
+
errorKey: "wallet_trezor_failed_to_get_address",
|
|
52
|
+
info: { ...result, chain: this.chain, derivationPath: this.derivationPath },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.address = result.payload.address;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return this.address;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
signMessage = async (message: string) => {
|
|
63
|
+
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
64
|
+
|
|
65
|
+
const result = await TrezorConnect.ethereumSignMessage({
|
|
66
|
+
message,
|
|
67
|
+
path: derivationPathToString(this.derivationPath),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (!result.success) {
|
|
71
|
+
throw new USwapError({
|
|
72
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
73
|
+
info: { ...result, chain: this.chain, derivationPath: this.derivationPath, message },
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return result.payload.signature;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
signTypedData(): Promise<string> {
|
|
81
|
+
throw new USwapError("wallet_trezor_method_not_supported", { method: "signTypedData" });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
signTransaction = async ({
|
|
85
|
+
to,
|
|
86
|
+
gasLimit,
|
|
87
|
+
value,
|
|
88
|
+
data,
|
|
89
|
+
nonce,
|
|
90
|
+
maxFeePerGas,
|
|
91
|
+
maxPriorityFeePerGas,
|
|
92
|
+
gasPrice,
|
|
93
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: any: refactor
|
|
94
|
+
}: TransactionRequest) => {
|
|
95
|
+
if (!to) throw new USwapError({ errorKey: "wallet_missing_params", info: { to } });
|
|
96
|
+
if (!gasLimit) throw new USwapError({ errorKey: "wallet_missing_params", info: { gasLimit } });
|
|
97
|
+
|
|
98
|
+
const isEIP1559 = maxFeePerGas && maxPriorityFeePerGas;
|
|
99
|
+
|
|
100
|
+
if (isEIP1559 && !maxFeePerGas) {
|
|
101
|
+
throw new USwapError({ errorKey: "wallet_missing_params", info: { maxFeePerGas } });
|
|
102
|
+
}
|
|
103
|
+
if (isEIP1559 && !maxPriorityFeePerGas) {
|
|
104
|
+
throw new USwapError({ errorKey: "wallet_missing_params", info: { maxPriorityFeePerGas } });
|
|
105
|
+
}
|
|
106
|
+
if (!(isEIP1559 || gasPrice)) {
|
|
107
|
+
throw new USwapError({ errorKey: "wallet_missing_params", info: { gasPrice } });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
111
|
+
const { toHexString } = await import("@tcswap/toolboxes/evm");
|
|
112
|
+
const { Transaction } = await import("ethers");
|
|
113
|
+
|
|
114
|
+
const additionalFields = isEIP1559
|
|
115
|
+
? {
|
|
116
|
+
maxFeePerGas: toHexString(BigInt(maxFeePerGas?.toString() || 0)),
|
|
117
|
+
maxPriorityFeePerGas: toHexString(BigInt(maxPriorityFeePerGas?.toString() || 0)),
|
|
118
|
+
}
|
|
119
|
+
: (gasPrice && { gasPrice: toHexString(BigInt(gasPrice?.toString() || 0)) }) || { gasPrice: "0x0" };
|
|
120
|
+
|
|
121
|
+
const hexifiedNonce = toHexString(
|
|
122
|
+
BigInt(nonce || (await this.provider.getTransactionCount(await this.getAddress(), "pending"))),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const formattedTx = {
|
|
126
|
+
chainId: Number.parseInt(ChainToChainId[this.chain], 10),
|
|
127
|
+
data: data?.toString() || "0x",
|
|
128
|
+
gasLimit: toHexString(BigInt(gasLimit?.toString() || 0)),
|
|
129
|
+
nonce: hexifiedNonce,
|
|
130
|
+
to: to.toString(),
|
|
131
|
+
value: toHexString(BigInt(value?.toString() || 0)),
|
|
132
|
+
...additionalFields,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const { success, payload } = await TrezorConnect.ethereumSignTransaction({
|
|
136
|
+
path: derivationPathToString(this.derivationPath),
|
|
137
|
+
transaction: formattedTx,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (!success) {
|
|
141
|
+
throw new USwapError({
|
|
142
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
143
|
+
info: { ...payload, chain: this.chain, derivationPath: this.derivationPath },
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const { r, s, v } = payload;
|
|
148
|
+
|
|
149
|
+
const signature = Signature.from({ r, s, v: new USwapNumber(BigInt(v)).getBaseValue("number") });
|
|
150
|
+
|
|
151
|
+
const serializedTx = Transaction.from({
|
|
152
|
+
...formattedTx,
|
|
153
|
+
nonce: Number.parseInt(formattedTx.nonce, 16),
|
|
154
|
+
signature,
|
|
155
|
+
type: isEIP1559 ? 2 : 0,
|
|
156
|
+
}).serialized;
|
|
157
|
+
|
|
158
|
+
if (!serializedTx) {
|
|
159
|
+
throw new USwapError({
|
|
160
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
161
|
+
info: { chain: this.chain, derivationPath: this.derivationPath },
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return serializedTx;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
connect = (provider: Provider | null) => {
|
|
169
|
+
if (!provider) {
|
|
170
|
+
throw new USwapError({
|
|
171
|
+
errorKey: "wallet_provider_not_found",
|
|
172
|
+
info: { chain: this.chain, derivationPath: this.derivationPath, wallet: WalletOption.TREZOR },
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return new TrezorSigner({ chain: this.chain, derivationPath: this.derivationPath, provider });
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return new TrezorSigner({ chain, derivationPath, provider });
|
|
181
|
+
}
|