@swapkit/wallet-hardware 5.0.0 → 6.0.0
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/THIRD_PARTY_LICENSES.md +2344 -0
- package/dist/chunk-09e51wma.js +4 -0
- package/dist/chunk-09e51wma.js.map +167 -0
- package/dist/chunk-0arpsm5f.js +4 -0
- package/dist/chunk-0arpsm5f.js.map +10 -0
- package/dist/chunk-1amf58aq.js +4 -0
- package/dist/{chunk-vwv6z2mk.js.map → chunk-1amf58aq.js.map} +2 -2
- package/dist/chunk-3t17wpjg.js +17 -0
- package/dist/chunk-3t17wpjg.js.map +29 -0
- package/dist/chunk-5c7b7z2d.js +4 -0
- package/dist/{chunk-9gy0xve4.js.map → chunk-5c7b7z2d.js.map} +2 -2
- package/dist/chunk-5p3ttw6y.js +4 -0
- package/dist/{chunk-n05bv2n5.js.map → chunk-5p3ttw6y.js.map} +1 -1
- package/dist/chunk-dptbnkzm.js +64 -0
- package/dist/chunk-dptbnkzm.js.map +260 -0
- package/dist/chunk-ds2m83jp.js +5 -0
- package/dist/chunk-ds2m83jp.js.map +11 -0
- package/dist/chunk-eenx3cv6.js +4 -0
- package/dist/chunk-eenx3cv6.js.map +33 -0
- package/dist/chunk-gr3eswf1.js +4 -0
- package/dist/chunk-gr3eswf1.js.map +73 -0
- package/dist/{chunk-7fsaymh4.js → chunk-hg71hp4m.js} +3 -3
- package/dist/{chunk-7fsaymh4.js.map → chunk-hg71hp4m.js.map} +1 -1
- package/dist/chunk-jewm2ag3.js +5 -0
- package/dist/chunk-jewm2ag3.js.map +10 -0
- package/dist/chunk-jzrytcrf.js +4 -0
- package/dist/chunk-jzrytcrf.js.map +12 -0
- package/dist/chunk-k3thje6a.js +4 -0
- package/dist/chunk-k3thje6a.js.map +9 -0
- package/dist/chunk-nhva847d.js +5 -0
- package/dist/chunk-nhva847d.js.map +9 -0
- package/dist/chunk-tm47brht.js +4 -0
- package/dist/chunk-tm47brht.js.map +140 -0
- package/dist/chunk-xmvg4cds.js +4 -0
- package/dist/chunk-xmvg4cds.js.map +127 -0
- package/dist/chunk-xx7cwpzq.js +4 -0
- package/dist/chunk-xx7cwpzq.js.map +9 -0
- package/dist/chunk-yrxe491r.js +20 -0
- package/dist/chunk-yrxe491r.js.map +17 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/keepkey/index.cjs +2 -2
- package/dist/keepkey/index.cjs.map +2 -2
- package/dist/keepkey/index.js +2 -2
- package/dist/keepkey/index.js.map +2 -2
- package/dist/ledger/index.cjs +90 -2
- package/dist/ledger/index.cjs.map +830 -23
- package/dist/ledger/index.js +2 -2
- package/dist/ledger/index.js.map +21 -19
- package/dist/trezor/index.cjs +2 -2
- package/dist/trezor/index.cjs.map +5 -4
- package/dist/trezor/index.js +2 -2
- package/dist/trezor/index.js.map +3 -3
- package/dist/types/helpers/psbt.d.ts +9 -0
- package/dist/types/helpers/psbt.d.ts.map +1 -0
- package/dist/types/ledger/clients/bitcoin.d.ts +36 -0
- package/dist/types/ledger/clients/bitcoin.d.ts.map +1 -0
- package/dist/types/ledger/clients/cosmos.d.ts +38 -10
- package/dist/types/ledger/clients/cosmos.d.ts.map +1 -1
- package/dist/types/ledger/clients/evm.d.ts +37 -46
- package/dist/types/ledger/clients/evm.d.ts.map +1 -1
- package/dist/types/ledger/clients/near.d.ts +5 -2
- package/dist/types/ledger/clients/near.d.ts.map +1 -1
- package/dist/types/ledger/clients/sui.d.ts +8 -12
- package/dist/types/ledger/clients/sui.d.ts.map +1 -1
- package/dist/types/ledger/clients/thorchain/index.d.ts +34 -8
- package/dist/types/ledger/clients/thorchain/index.d.ts.map +1 -1
- package/dist/types/ledger/clients/thorchain/protocol.d.ts +58 -0
- package/dist/types/ledger/clients/thorchain/protocol.d.ts.map +1 -0
- package/dist/types/ledger/clients/tron.d.ts +11 -8
- package/dist/types/ledger/clients/tron.d.ts.map +1 -1
- package/dist/types/ledger/clients/utxo-legacy-adapter.d.ts +3 -2
- package/dist/types/ledger/clients/utxo-legacy-adapter.d.ts.map +1 -1
- package/dist/types/ledger/clients/utxo-legacy-outputs.d.ts +18 -0
- package/dist/types/ledger/clients/utxo-legacy-outputs.d.ts.map +1 -0
- package/dist/types/ledger/clients/utxo.d.ts +10 -13
- package/dist/types/ledger/clients/utxo.d.ts.map +1 -1
- package/dist/types/ledger/clients/xrp.d.ts +4 -1
- package/dist/types/ledger/clients/xrp.d.ts.map +1 -1
- package/dist/types/ledger/clients/zcash.d.ts +53 -0
- package/dist/types/ledger/clients/zcash.d.ts.map +1 -0
- package/dist/types/ledger/helpers/dmk.d.ts +24 -0
- package/dist/types/ledger/helpers/dmk.d.ts.map +1 -0
- package/dist/types/ledger/helpers/executeDeviceAction.d.ts +34 -0
- package/dist/types/ledger/helpers/executeDeviceAction.d.ts.map +1 -0
- package/dist/types/ledger/helpers/getLedgerAddress.d.ts +1 -1
- package/dist/types/ledger/helpers/getLedgerAddress.d.ts.map +1 -1
- package/dist/types/ledger/helpers/getLedgerClient.d.ts +10 -3
- package/dist/types/ledger/helpers/getLedgerClient.d.ts.map +1 -1
- package/dist/types/ledger/helpers/index.d.ts +2 -1
- package/dist/types/ledger/helpers/index.d.ts.map +1 -1
- package/dist/types/ledger/helpers/ledgerJsDmkBridge.d.ts +26 -0
- package/dist/types/ledger/helpers/ledgerJsDmkBridge.d.ts.map +1 -0
- package/dist/types/ledger/helpers/ledgerJsDmkTransport.d.ts +13 -0
- package/dist/types/ledger/helpers/ledgerJsDmkTransport.d.ts.map +1 -0
- package/dist/types/ledger/helpers/lowS.d.ts +6 -0
- package/dist/types/ledger/helpers/lowS.d.ts.map +1 -0
- package/dist/types/ledger/helpers/rawTx.d.ts +2 -0
- package/dist/types/ledger/helpers/rawTx.d.ts.map +1 -0
- package/dist/types/ledger/index.d.ts +19 -7
- package/dist/types/ledger/index.d.ts.map +1 -1
- package/dist/types/ledger/types.d.ts +6 -10
- package/dist/types/ledger/types.d.ts.map +1 -1
- package/dist/types/trezor/index.d.ts +2 -2
- package/dist/types/trezor/index.d.ts.map +1 -1
- package/package.json +36 -36
- package/src/helpers/psbt.ts +26 -0
- package/src/ledger/clients/bitcoin.ts +575 -0
- package/src/ledger/clients/cosmos.ts +180 -51
- package/src/ledger/clients/evm.ts +238 -195
- package/src/ledger/clients/near.ts +43 -13
- package/src/ledger/clients/sui.ts +55 -68
- package/src/ledger/clients/thorchain/index.ts +210 -86
- package/src/ledger/clients/thorchain/protocol.ts +166 -0
- package/src/ledger/clients/tron.ts +49 -37
- package/src/ledger/clients/utxo-legacy-adapter.ts +35 -32
- package/src/ledger/clients/utxo-legacy-outputs.ts +122 -0
- package/src/ledger/clients/utxo.ts +108 -206
- package/src/ledger/clients/xrp.ts +39 -23
- package/src/ledger/clients/zcash.ts +440 -0
- package/src/ledger/helpers/dmk.ts +231 -0
- package/src/ledger/helpers/executeDeviceAction.ts +201 -0
- package/src/ledger/helpers/getLedgerClient.ts +101 -72
- package/src/ledger/helpers/index.ts +6 -1
- package/src/ledger/helpers/ledgerJsDmkBridge.ts +109 -0
- package/src/ledger/helpers/ledgerJsDmkTransport.ts +88 -0
- package/src/ledger/helpers/lowS.ts +30 -0
- package/src/ledger/helpers/rawTx.ts +12 -0
- package/src/ledger/index.ts +564 -369
- package/src/ledger/types.ts +15 -10
- package/src/trezor/index.ts +117 -25
- package/dist/chunk-3yr76n9s.js +0 -5
- package/dist/chunk-3yr76n9s.js.map +0 -10
- package/dist/chunk-9gy0xve4.js +0 -4
- package/dist/chunk-bwf31zxr.js +0 -4
- package/dist/chunk-bwf31zxr.js.map +0 -10
- package/dist/chunk-egtwbe6q.js +0 -4
- package/dist/chunk-egtwbe6q.js.map +0 -10
- package/dist/chunk-n05bv2n5.js +0 -5
- package/dist/chunk-vwv6z2mk.js +0 -4
- package/dist/types/ledger/clients/thorchain/common.d.ts +0 -28
- package/dist/types/ledger/clients/thorchain/common.d.ts.map +0 -1
- package/dist/types/ledger/clients/thorchain/helpers.d.ts +0 -7
- package/dist/types/ledger/clients/thorchain/helpers.d.ts.map +0 -1
- package/dist/types/ledger/clients/thorchain/lib.d.ts +0 -22
- package/dist/types/ledger/clients/thorchain/lib.d.ts.map +0 -1
- package/dist/types/ledger/clients/thorchain/utils.d.ts +0 -2
- package/dist/types/ledger/clients/thorchain/utils.d.ts.map +0 -1
- package/dist/types/ledger/clients/utxo-psbt.d.ts +0 -18
- package/dist/types/ledger/clients/utxo-psbt.d.ts.map +0 -1
- package/dist/types/ledger/cosmosTypes.d.ts +0 -40
- package/dist/types/ledger/cosmosTypes.d.ts.map +0 -1
- package/dist/types/ledger/helpers/getLedgerTransport.d.ts +0 -3
- package/dist/types/ledger/helpers/getLedgerTransport.d.ts.map +0 -1
- package/dist/types/ledger/helpers/ledgerNetworkInfo.d.ts +0 -14
- package/dist/types/ledger/helpers/ledgerNetworkInfo.d.ts.map +0 -1
- package/dist/types/ledger/interfaces/CosmosLedgerInterface.d.ts +0 -14
- package/dist/types/ledger/interfaces/CosmosLedgerInterface.d.ts.map +0 -1
- package/src/ledger/clients/thorchain/common.ts +0 -93
- package/src/ledger/clients/thorchain/helpers.ts +0 -120
- package/src/ledger/clients/thorchain/lib.ts +0 -258
- package/src/ledger/clients/thorchain/utils.ts +0 -69
- package/src/ledger/clients/utxo-psbt.ts +0 -172
- package/src/ledger/cosmosTypes.ts +0 -98
- package/src/ledger/helpers/getLedgerTransport.ts +0 -102
- package/src/ledger/helpers/ledgerNetworkInfo.ts +0 -127
- package/src/ledger/interfaces/CosmosLedgerInterface.ts +0 -67
package/src/ledger/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type Transport from "@ledgerhq/hw-transport";
|
|
2
|
+
import { hex } from "@scure/base";
|
|
2
3
|
import {
|
|
3
4
|
type AssetValue,
|
|
4
5
|
Chain,
|
|
@@ -6,8 +7,7 @@ import {
|
|
|
6
7
|
derivationPathToString,
|
|
7
8
|
FeeOption,
|
|
8
9
|
filterSupportedChains,
|
|
9
|
-
|
|
10
|
-
getRPCUrl,
|
|
10
|
+
getUTXOScriptTypeForPath,
|
|
11
11
|
NetworkDerivationPath,
|
|
12
12
|
SwapKitError,
|
|
13
13
|
type UTXOChain,
|
|
@@ -27,34 +27,143 @@ import {
|
|
|
27
27
|
getUtxoApi,
|
|
28
28
|
type UTXOBuildTxParams,
|
|
29
29
|
type UTXOForMultiAddressTransfer,
|
|
30
|
+
type UTXOTransferParams,
|
|
31
|
+
type UTXOType,
|
|
30
32
|
} from "@swapkit/toolboxes/utxo";
|
|
31
|
-
import type { Transaction } from "@swapkit/utxo-signer";
|
|
33
|
+
import type { Transaction, ZcashTransaction } from "@swapkit/utxo-signer";
|
|
32
34
|
import { createWallet, getWalletSupportedChains, type HardwareExtendedPublicKeyInfo } from "@swapkit/wallet-core";
|
|
33
|
-
import {
|
|
35
|
+
import { match, P } from "ts-pattern";
|
|
36
|
+
import {
|
|
37
|
+
getLedgerAddress,
|
|
38
|
+
getLedgerClient,
|
|
39
|
+
type LedgerDeviceActionStateHandler,
|
|
40
|
+
type LedgerDMKSession,
|
|
41
|
+
} from "./helpers";
|
|
42
|
+
import { createCachedRawTxResolver } from "./helpers/rawTx";
|
|
43
|
+
|
|
44
|
+
type BitcoinLedgerClient = ReturnType<typeof import("./clients/bitcoin")["BitcoinLedger"]>;
|
|
45
|
+
type LegacyUTXOLedgerClient = ReturnType<typeof import("./clients/utxo")["BitcoinCashLedger"]>;
|
|
46
|
+
type ZcashLedgerClient = ReturnType<typeof import("./clients/zcash")["ZcashLedger"]>;
|
|
47
|
+
type UTXOLedgerClient = BitcoinLedgerClient | LegacyUTXOLedgerClient | ZcashLedgerClient;
|
|
34
48
|
|
|
35
49
|
/**
|
|
36
50
|
* Options passed to `connectLedger` at call time.
|
|
37
51
|
*
|
|
38
|
-
* When `
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* default browser flow (WebHID / WebUSB via `navigator.usb`) is used.
|
|
52
|
+
* When `dmkSession` is omitted, the default browser WebHID flow discovers a
|
|
53
|
+
* device and reuses one session across chains. Lazy-loaded apps can call
|
|
54
|
+
* `preloadLedgerDMK` before the user gesture that starts connection.
|
|
42
55
|
*/
|
|
43
|
-
export
|
|
56
|
+
export interface ConnectLedgerOptions {
|
|
57
|
+
address?: string;
|
|
58
|
+
/** Caller-owned DMK session used by every supported chain. */
|
|
59
|
+
dmkSession?: LedgerDMKSession;
|
|
60
|
+
/** Receives DMK progress and device-interaction states. */
|
|
61
|
+
onDeviceActionState?: LedgerDeviceActionStateHandler;
|
|
62
|
+
/** Ledger-provided token required for Transaction Checks. */
|
|
63
|
+
originToken?: string;
|
|
64
|
+
/** @deprecated Temporary non-EVM fallback. Cannot be combined with `dmkSession`. */
|
|
65
|
+
transport?: Transport;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface WalletMethodsParams<C extends Chain = Chain> extends ConnectLedgerOptions {
|
|
69
|
+
chain: C;
|
|
70
|
+
derivationPath?: DerivationPathArray;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface LedgerAccountXpubParams {
|
|
74
|
+
chain: UTXOChain;
|
|
75
|
+
path: string;
|
|
76
|
+
signer: UTXOLedgerClient;
|
|
77
|
+
xpubVersion: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface SignLedgerTransactionParams {
|
|
81
|
+
inputUtxos?: UTXOType[];
|
|
82
|
+
transaction: Transaction | ZcashTransaction;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const LEDGER_SUPPORTED_CHAINS_CONFIG = [
|
|
86
|
+
Chain.Arbitrum,
|
|
87
|
+
Chain.Arc,
|
|
88
|
+
Chain.Aurora,
|
|
89
|
+
Chain.Avalanche,
|
|
90
|
+
Chain.Base,
|
|
91
|
+
Chain.Berachain,
|
|
92
|
+
Chain.BinanceSmartChain,
|
|
93
|
+
Chain.Bitcoin,
|
|
94
|
+
Chain.BitcoinCash,
|
|
95
|
+
Chain.Cosmos,
|
|
96
|
+
Chain.Dash,
|
|
97
|
+
Chain.Dogecoin,
|
|
98
|
+
Chain.Ethereum,
|
|
99
|
+
Chain.Gnosis,
|
|
100
|
+
Chain.Litecoin,
|
|
101
|
+
Chain.Monad,
|
|
102
|
+
Chain.Near,
|
|
103
|
+
Chain.Optimism,
|
|
104
|
+
Chain.Polygon,
|
|
105
|
+
Chain.Ripple,
|
|
106
|
+
Chain.Sui,
|
|
107
|
+
Chain.THORChain,
|
|
108
|
+
Chain.XLayer,
|
|
109
|
+
Chain.Tron,
|
|
110
|
+
Chain.Zcash,
|
|
111
|
+
] as const;
|
|
112
|
+
|
|
113
|
+
type LedgerSupportedChain = (typeof LEDGER_SUPPORTED_CHAINS_CONFIG)[number];
|
|
114
|
+
|
|
115
|
+
const LEDGER_UTXO_CHAINS = [
|
|
116
|
+
Chain.BitcoinCash,
|
|
117
|
+
Chain.Bitcoin,
|
|
118
|
+
Chain.Dash,
|
|
119
|
+
Chain.Dogecoin,
|
|
120
|
+
Chain.Litecoin,
|
|
121
|
+
Chain.Zcash,
|
|
122
|
+
] as const satisfies readonly UTXOChain[];
|
|
123
|
+
|
|
124
|
+
const LEDGER_EVM_CHAINS = [
|
|
125
|
+
Chain.Ethereum,
|
|
126
|
+
Chain.Avalanche,
|
|
127
|
+
Chain.Arbitrum,
|
|
128
|
+
Chain.Arc,
|
|
129
|
+
Chain.Berachain,
|
|
130
|
+
Chain.Optimism,
|
|
131
|
+
Chain.Polygon,
|
|
132
|
+
Chain.BinanceSmartChain,
|
|
133
|
+
Chain.Base,
|
|
134
|
+
Chain.Aurora,
|
|
135
|
+
Chain.Gnosis,
|
|
136
|
+
Chain.Monad,
|
|
137
|
+
Chain.XLayer,
|
|
138
|
+
] as const satisfies readonly LedgerSupportedChain[];
|
|
139
|
+
|
|
140
|
+
type LedgerEVMChain = (typeof LEDGER_EVM_CHAINS)[number];
|
|
141
|
+
|
|
142
|
+
function isLedgerSupportedChain(chain: Chain): chain is LedgerSupportedChain {
|
|
143
|
+
return LEDGER_SUPPORTED_CHAINS_CONFIG.includes(chain as LedgerSupportedChain);
|
|
144
|
+
}
|
|
44
145
|
|
|
45
146
|
export const ledgerWallet = createWallet({
|
|
46
147
|
connect: ({ addChain, supportedChains, walletType }) =>
|
|
47
148
|
async function connectLedger(
|
|
48
149
|
chains: Chain[],
|
|
49
150
|
derivationPath?: DerivationPathArray,
|
|
50
|
-
{ address, transport }: ConnectLedgerOptions = {},
|
|
151
|
+
{ address, dmkSession, onDeviceActionState, originToken, transport }: ConnectLedgerOptions = {},
|
|
51
152
|
) {
|
|
52
153
|
const [chain] = filterSupportedChains({ chains, supportedChains, walletType });
|
|
53
154
|
|
|
54
155
|
if (!chain) return false;
|
|
55
156
|
|
|
56
157
|
const resolvedPath = derivationPath ?? (NetworkDerivationPath[chain] as DerivationPathArray | undefined);
|
|
57
|
-
const walletMethods = await getWalletMethods({
|
|
158
|
+
const walletMethods = await getWalletMethods({
|
|
159
|
+
address,
|
|
160
|
+
chain,
|
|
161
|
+
derivationPath: resolvedPath,
|
|
162
|
+
dmkSession,
|
|
163
|
+
onDeviceActionState,
|
|
164
|
+
originToken,
|
|
165
|
+
transport,
|
|
166
|
+
});
|
|
58
167
|
|
|
59
168
|
addChain({ ...walletMethods, chain, walletType: WalletOption.LEDGER });
|
|
60
169
|
|
|
@@ -85,436 +194,522 @@ export const ledgerWallet = createWallet({
|
|
|
85
194
|
[Chain.THORChain]: true,
|
|
86
195
|
[Chain.Tron]: true,
|
|
87
196
|
[Chain.XLayer]: true,
|
|
88
|
-
// ZEC
|
|
197
|
+
// ZEC transparent transfers use DSK, but route-level PCZT signing remains unsupported.
|
|
89
198
|
},
|
|
90
199
|
getExtendedPublicKey: getLedgerExtendedPublicKey,
|
|
91
200
|
name: "connectLedger",
|
|
92
|
-
supportedChains: [
|
|
93
|
-
Chain.Arbitrum,
|
|
94
|
-
Chain.Arc,
|
|
95
|
-
Chain.Aurora,
|
|
96
|
-
Chain.Avalanche,
|
|
97
|
-
Chain.Base,
|
|
98
|
-
Chain.Berachain,
|
|
99
|
-
Chain.BinanceSmartChain,
|
|
100
|
-
Chain.Bitcoin,
|
|
101
|
-
Chain.BitcoinCash,
|
|
102
|
-
Chain.Cosmos,
|
|
103
|
-
Chain.Dash,
|
|
104
|
-
Chain.Dogecoin,
|
|
105
|
-
Chain.Ethereum,
|
|
106
|
-
Chain.Gnosis,
|
|
107
|
-
Chain.Litecoin,
|
|
108
|
-
Chain.Monad,
|
|
109
|
-
Chain.Near,
|
|
110
|
-
Chain.Optimism,
|
|
111
|
-
Chain.Polygon,
|
|
112
|
-
Chain.Ripple,
|
|
113
|
-
Chain.Sui,
|
|
114
|
-
Chain.THORChain,
|
|
115
|
-
Chain.XLayer,
|
|
116
|
-
Chain.Tron,
|
|
117
|
-
Chain.Zcash,
|
|
118
|
-
],
|
|
201
|
+
supportedChains: [...LEDGER_SUPPORTED_CHAINS_CONFIG],
|
|
119
202
|
walletType: WalletOption.LEDGER,
|
|
120
203
|
});
|
|
121
204
|
|
|
122
205
|
export const LEDGER_SUPPORTED_CHAINS = getWalletSupportedChains(ledgerWallet);
|
|
123
206
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
207
|
+
function getLedgerAccountXpub({ chain, path, signer, xpubVersion }: LedgerAccountXpubParams) {
|
|
208
|
+
const ledgerPath = match(chain)
|
|
209
|
+
.with(Chain.Bitcoin, Chain.Litecoin, () => path)
|
|
210
|
+
.with(Chain.BitcoinCash, Chain.Dash, Chain.Dogecoin, Chain.Zcash, () => path.replace(/^m\//, ""))
|
|
211
|
+
.exhaustive();
|
|
212
|
+
|
|
213
|
+
return match(chain)
|
|
214
|
+
.with(Chain.Bitcoin, () => (signer as BitcoinLedgerClient).getExtendedPublicKey({ path: ledgerPath }))
|
|
215
|
+
.with(Chain.Zcash, () => (signer as ZcashLedgerClient).getExtendedPublicKey({ path: ledgerPath, xpubVersion }))
|
|
216
|
+
.with(Chain.BitcoinCash, Chain.Dash, Chain.Dogecoin, Chain.Litecoin, () =>
|
|
217
|
+
(signer as LegacyUTXOLedgerClient).getExtendedPublicKey(ledgerPath, xpubVersion),
|
|
218
|
+
)
|
|
219
|
+
.exhaustive();
|
|
220
|
+
}
|
|
127
221
|
|
|
128
|
-
|
|
222
|
+
// Toolbox-built transactions keep input txids in display order, the order the UTXO API looks transactions up by,
|
|
223
|
+
// while ZcashTransaction.fromBytes (raw API route transactions) keeps them in wire order, so try both. A txid and its
|
|
224
|
+
// byte reversal cannot both name real transactions, so the fallback cannot fetch an unrelated one.
|
|
225
|
+
function resolveZcashInputUtxos(transaction: ZcashTransaction): Promise<UTXOType[]> {
|
|
226
|
+
const zcashApi = getUtxoApi(Chain.Zcash);
|
|
227
|
+
const getRawTx = createCachedRawTxResolver((txid) => zcashApi.getRawTx(txid));
|
|
228
|
+
|
|
229
|
+
return Promise.all(
|
|
230
|
+
Array.from({ length: transaction.inputsLength }, async (_, inputIndex) => {
|
|
231
|
+
const input = transaction.getInput(inputIndex);
|
|
232
|
+
const txid = hex.encode(input.txid);
|
|
233
|
+
const reversedTxid = hex.encode(input.txid.slice().reverse());
|
|
234
|
+
const directTxHex = await getRawTx(txid);
|
|
235
|
+
const [hash, txHex] = directTxHex ? [txid, directTxHex] : [reversedTxid, await getRawTx(reversedTxid)];
|
|
236
|
+
if (!txHex) {
|
|
237
|
+
throw new SwapKitError("wallet_ledger_invalid_params", {
|
|
238
|
+
inputIndex,
|
|
239
|
+
outputIndex: input.index,
|
|
240
|
+
reason: "Unable to resolve previous transaction hex for Ledger signing in either txid byte order",
|
|
241
|
+
reversedTxid,
|
|
242
|
+
txid,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
129
245
|
|
|
130
|
-
|
|
246
|
+
// The Zcash client takes amounts from the device's trusted inputs; fromBytes leaves input values at zero.
|
|
247
|
+
return { hash, index: input.index, txHex, value: Number(input.value) };
|
|
248
|
+
}),
|
|
249
|
+
);
|
|
131
250
|
}
|
|
132
251
|
|
|
133
252
|
export async function getLedgerExtendedPublicKey(
|
|
134
253
|
chain: Chain,
|
|
135
254
|
derivationPath?: DerivationPathArray,
|
|
136
|
-
{
|
|
255
|
+
{
|
|
256
|
+
accountIndex,
|
|
257
|
+
dmkSession,
|
|
258
|
+
onDeviceActionState,
|
|
259
|
+
transport,
|
|
260
|
+
}: {
|
|
261
|
+
accountIndex?: number;
|
|
262
|
+
dmkSession?: LedgerDMKSession;
|
|
263
|
+
onDeviceActionState?: LedgerDeviceActionStateHandler;
|
|
264
|
+
transport?: Transport;
|
|
265
|
+
} = {},
|
|
137
266
|
): Promise<HardwareExtendedPublicKeyInfo | undefined> {
|
|
138
267
|
if (![Chain.BitcoinCash, Chain.Bitcoin, Chain.Dash, Chain.Dogecoin, Chain.Litecoin, Chain.Zcash].includes(chain)) {
|
|
139
268
|
throw new SwapKitError("wallet_chain_not_supported", { chain, wallet: WalletOption.LEDGER });
|
|
140
269
|
}
|
|
141
270
|
|
|
142
271
|
const utxoChain = chain as UTXOChain;
|
|
143
|
-
const signer = await getLedgerClient({
|
|
272
|
+
const signer = await getLedgerClient({
|
|
273
|
+
chain: utxoChain,
|
|
274
|
+
derivationPath,
|
|
275
|
+
dmkSession,
|
|
276
|
+
onDeviceActionState,
|
|
277
|
+
transport,
|
|
278
|
+
});
|
|
144
279
|
if (!signer.getExtendedPublicKey) return undefined;
|
|
145
280
|
|
|
146
281
|
const accountPath = getUTXOAccountPath({ accountIndex, chain: utxoChain, derivationPath });
|
|
147
282
|
const path = derivationPathToString(accountPath);
|
|
148
|
-
const ledgerPath = chain === Chain.Bitcoin || chain === Chain.Litecoin ? path : path.replace(/^m\//, "");
|
|
149
283
|
const xpubVersion = getNetworkForChain(utxoChain).bip32.public;
|
|
150
284
|
try {
|
|
151
|
-
const xpub = await
|
|
285
|
+
const xpub = await getLedgerAccountXpub({ chain: utxoChain, path, signer, xpubVersion });
|
|
152
286
|
return { accountIndex: getUTXOAccountIndexFromPath(accountPath), path, xpub };
|
|
153
287
|
} finally {
|
|
154
288
|
await (signer as { disconnect?: () => Promise<void> }).disconnect?.();
|
|
155
289
|
}
|
|
156
290
|
}
|
|
157
291
|
|
|
158
|
-
async function
|
|
292
|
+
async function getUTXOWalletMethods({
|
|
159
293
|
address: providedAddress,
|
|
160
294
|
chain,
|
|
295
|
+
dmkSession,
|
|
161
296
|
derivationPath,
|
|
297
|
+
onDeviceActionState,
|
|
162
298
|
transport,
|
|
163
|
-
}:
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
//
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
299
|
+
}: WalletMethodsParams<UTXOChain>) {
|
|
300
|
+
const { getUtxoToolbox } = await import("@swapkit/toolboxes/utxo");
|
|
301
|
+
const utxoChain = chain;
|
|
302
|
+
|
|
303
|
+
const signer = await getLedgerClient({ chain, derivationPath, dmkSession, onDeviceActionState, transport });
|
|
304
|
+
|
|
305
|
+
const address = providedAddress ?? (await getLedgerAddress({ chain, ledgerClient: signer }));
|
|
306
|
+
// On Bitcoin the account's path states its encoding (BIP44/49/84/86). The other apps sign for the address format
|
|
307
|
+
// the client derives (an 86' Litecoin account is ltc1q), so they, like a custom purpose, follow the address form.
|
|
308
|
+
const scriptType =
|
|
309
|
+
(chain === Chain.Bitcoin ? getUTXOScriptTypeForPath(derivationPath) : undefined) ??
|
|
310
|
+
getScriptTypeForAddress(address, utxoChain);
|
|
311
|
+
|
|
312
|
+
const { publicKey, signLedgerTransaction, toolboxSigner } = await match(chain)
|
|
313
|
+
.with(Chain.Bitcoin, async () => {
|
|
314
|
+
const bitcoinSigner = signer as BitcoinLedgerClient;
|
|
315
|
+
// Nested SegWit and taproot inputs need the key behind them (redeemScript, tapInternalKey).
|
|
316
|
+
const needsPublicKey = scriptType === UTXOScriptType.P2SH_P2WPKH || scriptType === UTXOScriptType.P2TR;
|
|
317
|
+
const publicKey = needsPublicKey ? await bitcoinSigner.getPublicKey() : undefined;
|
|
318
|
+
return {
|
|
319
|
+
publicKey,
|
|
320
|
+
signLedgerTransaction: ({ inputUtxos, transaction }: SignLedgerTransactionParams) =>
|
|
321
|
+
bitcoinSigner.signTransactionHex({ inputUtxos, tx: transaction as Transaction }),
|
|
322
|
+
toolboxSigner: {
|
|
323
|
+
getAddress: bitcoinSigner.getAddress,
|
|
324
|
+
publicKey,
|
|
325
|
+
signTransaction: bitcoinSigner.signTransaction,
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
})
|
|
329
|
+
.with(Chain.BitcoinCash, Chain.Dogecoin, Chain.Dash, Chain.Litecoin, async () => {
|
|
330
|
+
const { createLegacyPsbtSigner, signLegacyPsbtTransaction } = await import("./clients/utxo-legacy-adapter");
|
|
331
|
+
const legacySigner = signer as LegacyUTXOLedgerClient;
|
|
332
|
+
return {
|
|
333
|
+
publicKey: undefined,
|
|
334
|
+
signLedgerTransaction: ({ inputUtxos, transaction }: SignLedgerTransactionParams) =>
|
|
335
|
+
signLegacyPsbtTransaction({
|
|
336
|
+
chain: utxoChain,
|
|
337
|
+
inputUtxos,
|
|
338
|
+
legacyClient: legacySigner,
|
|
339
|
+
tx: transaction as Transaction,
|
|
340
|
+
}),
|
|
341
|
+
toolboxSigner: createLegacyPsbtSigner({ address, chain: utxoChain, legacyClient: legacySigner }),
|
|
342
|
+
};
|
|
343
|
+
})
|
|
344
|
+
.with(Chain.Zcash, () => {
|
|
345
|
+
const zcashSigner = signer as ZcashLedgerClient;
|
|
346
|
+
return {
|
|
347
|
+
publicKey: undefined,
|
|
348
|
+
signLedgerTransaction: async ({ inputUtxos, transaction }: SignLedgerTransactionParams) => {
|
|
349
|
+
if (!("consensusBranchId" in transaction)) {
|
|
350
|
+
throw new SwapKitError("wallet_ledger_method_not_supported", {
|
|
351
|
+
method: "signPCZT",
|
|
352
|
+
wallet: WalletOption.LEDGER,
|
|
353
|
+
});
|
|
191
354
|
}
|
|
192
|
-
| undefined;
|
|
193
|
-
let publicKey: Uint8Array | undefined;
|
|
194
|
-
let signAndBroadcastLegacyPsbtTransaction: ((tx: Transaction) => Promise<string>) | undefined;
|
|
195
|
-
if (chain === Chain.Bitcoin) {
|
|
196
|
-
const { BitcoinPsbtLedger } = await import("./clients/utxo-psbt");
|
|
197
|
-
const psbtClient = BitcoinPsbtLedger(derivationPath, transport);
|
|
198
|
-
publicKey = scriptType === UTXOScriptType.P2SH_P2WPKH ? await psbtClient.getPublicKey() : undefined;
|
|
199
|
-
toolboxSigner = { getAddress: psbtClient.getAddress, publicKey, signTransaction: psbtClient.signTransaction };
|
|
200
|
-
} else if (
|
|
201
|
-
chain === Chain.BitcoinCash ||
|
|
202
|
-
chain === Chain.Dogecoin ||
|
|
203
|
-
chain === Chain.Dash ||
|
|
204
|
-
chain === Chain.Litecoin
|
|
205
|
-
) {
|
|
206
|
-
const { createLegacyPsbtSigner, signLegacyPsbtTransaction } = await import("./clients/utxo-legacy-adapter");
|
|
207
|
-
toolboxSigner = createLegacyPsbtSigner({ address, chain: utxoChain, legacyClient: signer });
|
|
208
|
-
signAndBroadcastLegacyPsbtTransaction = async (tx) => {
|
|
209
|
-
const signedTxHex = await signLegacyPsbtTransaction({ chain: utxoChain, legacyClient: signer, tx });
|
|
210
|
-
return toolbox.broadcastTx(signedTxHex);
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
355
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const memo = [Chain.Bitcoin].includes(chain as typeof Chain.Bitcoin) ? params.memo : reduceMemo(params.memo);
|
|
222
|
-
|
|
223
|
-
const { tx, inputs } = await toolbox.createTransaction({
|
|
224
|
-
...params,
|
|
225
|
-
feeRate,
|
|
226
|
-
fetchTxHex: true,
|
|
227
|
-
memo,
|
|
228
|
-
publicKey: params.publicKey ?? publicKey,
|
|
229
|
-
sender: address,
|
|
230
|
-
});
|
|
356
|
+
const resolvedInputUtxos = inputUtxos ?? (await resolveZcashInputUtxos(transaction));
|
|
357
|
+
return zcashSigner.signTransaction({ inputUtxos: resolvedInputUtxos, tx: transaction });
|
|
358
|
+
},
|
|
359
|
+
toolboxSigner: undefined,
|
|
360
|
+
};
|
|
361
|
+
})
|
|
362
|
+
.exhaustive();
|
|
231
363
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
364
|
+
const toolbox = toolboxSigner
|
|
365
|
+
? await getUtxoToolbox(utxoChain, { scriptType, signer: toolboxSigner })
|
|
366
|
+
: getUtxoToolbox(utxoChain, { scriptType });
|
|
367
|
+
const signAndBroadcastTransaction = async (transaction: Transaction | ZcashTransaction) =>
|
|
368
|
+
toolbox.broadcastTx(await signLedgerTransaction({ transaction }));
|
|
236
369
|
|
|
237
|
-
|
|
238
|
-
|
|
370
|
+
// The toolbox's transfer parameters plus a public key override; the sender is always the Ledger account.
|
|
371
|
+
const transfer = async (params: UTXOTransferParams & Pick<UTXOBuildTxParams, "enableRBF" | "publicKey">) => {
|
|
372
|
+
const feeRate = params.feeRate || (await toolbox.getFeeRates())[params.feeOptionKey || FeeOption.Fast];
|
|
239
373
|
|
|
240
|
-
|
|
241
|
-
|
|
374
|
+
const { tx, inputs } = await toolbox.createTransaction({
|
|
375
|
+
...params,
|
|
376
|
+
feeRate,
|
|
377
|
+
fetchTxHex: true,
|
|
378
|
+
publicKey: params.publicKey ?? publicKey,
|
|
379
|
+
sender: address,
|
|
380
|
+
});
|
|
242
381
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
const ledgerPath = chain === Chain.Bitcoin || chain === Chain.Litecoin ? path : path.replace(/^m\//, "");
|
|
246
|
-
const xpubVersion = getNetworkForChain(utxoChain).bip32.public;
|
|
247
|
-
const xpub = await signer.getExtendedPublicKey(ledgerPath, xpubVersion);
|
|
382
|
+
const txHex = await signLedgerTransaction({ inputUtxos: inputs, transaction: tx });
|
|
383
|
+
const txHash = await toolbox.broadcastTx(txHex);
|
|
248
384
|
|
|
249
|
-
|
|
250
|
-
|
|
385
|
+
return txHash;
|
|
386
|
+
};
|
|
251
387
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
388
|
+
async function getExtendedPublicKeyInfo({ accountIndex }: { accountIndex?: number } = {}) {
|
|
389
|
+
if (!signer.getExtendedPublicKey) return undefined;
|
|
255
390
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}: {
|
|
261
|
-
accountIndex?: number;
|
|
262
|
-
index: number;
|
|
263
|
-
change?: boolean;
|
|
264
|
-
}) {
|
|
265
|
-
try {
|
|
266
|
-
const fullPath = getUTXOAddressPath({ accountIndex, chain: utxoChain, change, derivationPath, index });
|
|
267
|
-
|
|
268
|
-
const indexedSigner = await getLedgerClient({ chain: utxoChain, derivationPath: fullPath, transport });
|
|
269
|
-
const derivedAddress = await getLedgerAddress({ chain: utxoChain, ledgerClient: indexedSigner });
|
|
270
|
-
|
|
271
|
-
return {
|
|
272
|
-
accountIndex: getUTXOAccountIndexFromPath(fullPath),
|
|
273
|
-
address: derivedAddress,
|
|
274
|
-
change,
|
|
275
|
-
index,
|
|
276
|
-
path: derivationPathToString(fullPath),
|
|
277
|
-
pubkey: "",
|
|
278
|
-
};
|
|
279
|
-
} catch {
|
|
280
|
-
return undefined;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
391
|
+
const accountPath = getUTXOAccountPath({ accountIndex, chain: utxoChain, derivationPath });
|
|
392
|
+
const path = derivationPathToString(accountPath);
|
|
393
|
+
const xpubVersion = getNetworkForChain(utxoChain).bip32.public;
|
|
394
|
+
const xpub = await getLedgerAccountXpub({ chain, path, signer, xpubVersion });
|
|
283
395
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
count,
|
|
287
|
-
startIndex = 0,
|
|
288
|
-
change = false,
|
|
289
|
-
}: {
|
|
290
|
-
accountIndex?: number;
|
|
291
|
-
count: number;
|
|
292
|
-
startIndex?: number;
|
|
293
|
-
change?: boolean;
|
|
294
|
-
}) {
|
|
295
|
-
assertDerivationIndex("count", count);
|
|
296
|
-
assertDerivationIndex("startIndex", startIndex);
|
|
297
|
-
|
|
298
|
-
const addresses = await Promise.all(
|
|
299
|
-
Array.from({ length: count }, (_, i) =>
|
|
300
|
-
deriveAddressAtIndex({ accountIndex, change, index: startIndex + i }),
|
|
301
|
-
),
|
|
302
|
-
);
|
|
303
|
-
|
|
304
|
-
return addresses.filter((address) => !!address);
|
|
305
|
-
}
|
|
396
|
+
return { accountIndex: getUTXOAccountIndexFromPath(accountPath), path, xpub };
|
|
397
|
+
}
|
|
306
398
|
|
|
307
|
-
|
|
399
|
+
function getExtendedPublicKey(params: { accountIndex?: number } = {}) {
|
|
400
|
+
return getExtendedPublicKeyInfo(params);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async function deriveAddressAtIndex({
|
|
404
|
+
accountIndex,
|
|
405
|
+
index,
|
|
406
|
+
change = false,
|
|
407
|
+
}: {
|
|
408
|
+
accountIndex?: number;
|
|
409
|
+
index: number;
|
|
410
|
+
change?: boolean;
|
|
411
|
+
}) {
|
|
412
|
+
try {
|
|
413
|
+
const fullPath = getUTXOAddressPath({ accountIndex, chain: utxoChain, change, derivationPath, index });
|
|
414
|
+
|
|
415
|
+
const indexedSigner = await getLedgerClient({
|
|
308
416
|
chain: utxoChain,
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
417
|
+
derivationPath: fullPath,
|
|
418
|
+
dmkSession,
|
|
419
|
+
onDeviceActionState,
|
|
420
|
+
transport,
|
|
312
421
|
});
|
|
422
|
+
const derivedAddress = await getLedgerAddress({ chain: utxoChain, ledgerClient: indexedSigner });
|
|
313
423
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
memo?: string;
|
|
327
|
-
feeRate?: number;
|
|
328
|
-
feeOptionKey?: FeeOption;
|
|
329
|
-
changeAddress?: string;
|
|
330
|
-
}) {
|
|
331
|
-
if (!utxos.length) {
|
|
332
|
-
throw new SwapKitError("wallet_ledger_invalid_params", {
|
|
333
|
-
message: "No UTXOs provided for multi-address transfer",
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const txFeeRate = feeRate || (await toolbox.getFeeRates())[feeOptionKey || FeeOption.Fast];
|
|
338
|
-
const memoScript = memo ? compileMemo(memo) : null;
|
|
339
|
-
|
|
340
|
-
const targetOutputs: Array<{ address: string; value: number } | { script: Uint8Array; value: number }> = [
|
|
341
|
-
{ address: recipient, value: assetValue.getBaseValue("number") },
|
|
342
|
-
];
|
|
343
|
-
if (memoScript) {
|
|
344
|
-
targetOutputs.push({ script: memoScript, value: 0 });
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const basicUtxos = utxos.map(({ hash, index, value, txHex, witnessUtxo }) => ({
|
|
348
|
-
hash,
|
|
349
|
-
index,
|
|
350
|
-
txHex,
|
|
351
|
-
value,
|
|
352
|
-
witnessUtxo,
|
|
353
|
-
}));
|
|
354
|
-
|
|
355
|
-
const { inputs: selectedInputs, outputs } = toolbox.accumulative({
|
|
356
|
-
chain: utxoChain,
|
|
357
|
-
feeRate: txFeeRate,
|
|
358
|
-
inputs: basicUtxos,
|
|
359
|
-
outputs: targetOutputs,
|
|
360
|
-
});
|
|
424
|
+
return {
|
|
425
|
+
accountIndex: getUTXOAccountIndexFromPath(fullPath),
|
|
426
|
+
address: derivedAddress,
|
|
427
|
+
change,
|
|
428
|
+
index,
|
|
429
|
+
path: derivationPathToString(fullPath),
|
|
430
|
+
pubkey: "",
|
|
431
|
+
};
|
|
432
|
+
} catch {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
361
436
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
437
|
+
async function deriveAddresses({
|
|
438
|
+
accountIndex,
|
|
439
|
+
count,
|
|
440
|
+
startIndex = 0,
|
|
441
|
+
change = false,
|
|
442
|
+
}: {
|
|
443
|
+
accountIndex?: number;
|
|
444
|
+
count: number;
|
|
445
|
+
startIndex?: number;
|
|
446
|
+
change?: boolean;
|
|
447
|
+
}) {
|
|
448
|
+
assertDerivationIndex("count", count);
|
|
449
|
+
assertDerivationIndex("startIndex", startIndex);
|
|
450
|
+
|
|
451
|
+
const addresses = await Promise.all(
|
|
452
|
+
Array.from({ length: count }, (_, i) => deriveAddressAtIndex({ accountIndex, change, index: startIndex + i })),
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
return addresses.filter((address) => !!address);
|
|
456
|
+
}
|
|
380
457
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
458
|
+
const hdHelpers = createHDWalletHelpers({
|
|
459
|
+
chain: utxoChain,
|
|
460
|
+
deriveAddress: deriveAddressAtIndex,
|
|
461
|
+
getBalance: toolbox.getBalance,
|
|
462
|
+
getUtxos: (addr: string) => getUtxoApi(utxoChain).getUtxos({ address: addr, fetchTxHex: true }),
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
async function transferFromMultipleAddresses({
|
|
466
|
+
utxos,
|
|
467
|
+
recipient,
|
|
468
|
+
assetValue,
|
|
469
|
+
memo,
|
|
470
|
+
feeRate,
|
|
471
|
+
feeOptionKey,
|
|
472
|
+
changeAddress,
|
|
473
|
+
}: {
|
|
474
|
+
utxos: UTXOForMultiAddressTransfer[];
|
|
475
|
+
recipient: string;
|
|
476
|
+
assetValue: AssetValue;
|
|
477
|
+
memo?: string;
|
|
478
|
+
feeRate?: number;
|
|
479
|
+
feeOptionKey?: FeeOption;
|
|
480
|
+
changeAddress?: string;
|
|
481
|
+
}) {
|
|
482
|
+
if (chain === Chain.Zcash) {
|
|
483
|
+
throw new SwapKitError("wallet_ledger_method_not_supported", {
|
|
484
|
+
method: "transferFromMultipleAddresses",
|
|
485
|
+
wallet: WalletOption.LEDGER,
|
|
486
|
+
});
|
|
487
|
+
}
|
|
389
488
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
489
|
+
if (!utxos.length) {
|
|
490
|
+
throw new SwapKitError("wallet_ledger_invalid_params", {
|
|
491
|
+
message: "No UTXOs provided for multi-address transfer",
|
|
492
|
+
});
|
|
493
|
+
}
|
|
393
494
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
}
|
|
495
|
+
const txFeeRate = feeRate || (await toolbox.getFeeRates())[feeOptionKey || FeeOption.Fast];
|
|
496
|
+
const memoScript = memo ? compileMemo(memo) : null;
|
|
397
497
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
deriveAddresses,
|
|
404
|
-
getExtendedPublicKey,
|
|
405
|
-
getExtendedPublicKeyInfo,
|
|
406
|
-
signAndBroadcastTransaction,
|
|
407
|
-
transfer,
|
|
408
|
-
transferFromMultipleAddresses,
|
|
409
|
-
};
|
|
498
|
+
const targetOutputs: Array<{ address: string; value: number } | { script: Uint8Array; value: number }> = [
|
|
499
|
+
{ address: recipient, value: assetValue.getBaseValue("number") },
|
|
500
|
+
];
|
|
501
|
+
if (memoScript) {
|
|
502
|
+
targetOutputs.push({ script: memoScript, value: 0 });
|
|
410
503
|
}
|
|
411
504
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
505
|
+
const basicUtxos = utxos.map(({ hash, index, value, txHex, witnessUtxo }) => ({
|
|
506
|
+
hash,
|
|
507
|
+
index,
|
|
508
|
+
txHex,
|
|
509
|
+
value,
|
|
510
|
+
witnessUtxo,
|
|
511
|
+
}));
|
|
512
|
+
|
|
513
|
+
const { inputs: selectedInputs, outputs } = toolbox.accumulative({
|
|
514
|
+
chain: utxoChain,
|
|
515
|
+
feeRate: txFeeRate,
|
|
516
|
+
inputs: basicUtxos,
|
|
517
|
+
outputs: targetOutputs,
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
if (!(selectedInputs && outputs)) {
|
|
521
|
+
throw new SwapKitError("wallet_ledger_connection_error", {
|
|
522
|
+
message: "Insufficient balance for multi-address transfer",
|
|
523
|
+
});
|
|
431
524
|
}
|
|
432
525
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const signingClient = await createSigningStargateClient(rpcUrl, signer, "0.007uatom");
|
|
457
|
-
|
|
458
|
-
const { transactionHash } = await signingClient.signAndBroadcast(
|
|
459
|
-
address,
|
|
460
|
-
[{ typeUrl: "/cosmos.bank.v1beta1.MsgSend", value: sendCoinsMessage }],
|
|
461
|
-
getDefaultChainFee(Chain.Cosmos),
|
|
462
|
-
memo,
|
|
463
|
-
);
|
|
464
|
-
|
|
465
|
-
return transactionHash;
|
|
466
|
-
};
|
|
526
|
+
const { Transaction } = await import("@swapkit/utxo-signer");
|
|
527
|
+
const tx = new Transaction({ allowLegacyWitnessUtxo: true, allowUnknownOutputs: !!memoScript, version: 1 });
|
|
528
|
+
const senderAddress = changeAddress || utxos[0]?.address || recipient;
|
|
529
|
+
|
|
530
|
+
addInputsAndOutputs({
|
|
531
|
+
chain: utxoChain,
|
|
532
|
+
compiledMemo: memoScript,
|
|
533
|
+
inputs: selectedInputs,
|
|
534
|
+
outputs,
|
|
535
|
+
sender: senderAddress,
|
|
536
|
+
tx,
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
const inputDerivationPaths = selectedInputs.map((input: { hash: string; index: number }) => {
|
|
540
|
+
const utxoInfo = utxos.find((u) => u.hash === input.hash && u.index === input.index);
|
|
541
|
+
const fullPath = getUTXOAddressPath({
|
|
542
|
+
chain: utxoChain,
|
|
543
|
+
change: utxoInfo?.isChange ?? false,
|
|
544
|
+
derivationPath,
|
|
545
|
+
index: utxoInfo?.derivationIndex ?? 0,
|
|
546
|
+
});
|
|
547
|
+
return derivationPathToString(fullPath);
|
|
548
|
+
});
|
|
467
549
|
|
|
468
|
-
|
|
550
|
+
if (!signer.signTransactionWithMultiplePaths) {
|
|
551
|
+
throw new SwapKitError("wallet_ledger_method_not_supported", { method: "signTransactionWithMultiplePaths" });
|
|
469
552
|
}
|
|
470
553
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
554
|
+
const txHex = await match(chain)
|
|
555
|
+
.with(Chain.Bitcoin, () =>
|
|
556
|
+
(signer as BitcoinLedgerClient).signTransactionWithMultiplePaths({
|
|
557
|
+
derivationPaths: inputDerivationPaths,
|
|
558
|
+
inputUtxos: selectedInputs,
|
|
559
|
+
tx,
|
|
560
|
+
}),
|
|
561
|
+
)
|
|
562
|
+
.with(Chain.BitcoinCash, Chain.Dash, Chain.Dogecoin, Chain.Litecoin, () =>
|
|
563
|
+
(signer as LegacyUTXOLedgerClient).signTransactionWithMultiplePaths(tx, selectedInputs, inputDerivationPaths),
|
|
564
|
+
)
|
|
565
|
+
.exhaustive();
|
|
566
|
+
return toolbox.broadcastTx(txHex);
|
|
567
|
+
}
|
|
477
568
|
|
|
478
|
-
|
|
479
|
-
|
|
569
|
+
return {
|
|
570
|
+
...toolbox,
|
|
571
|
+
...hdHelpers,
|
|
572
|
+
address,
|
|
573
|
+
deriveAddressAtIndex,
|
|
574
|
+
deriveAddresses,
|
|
575
|
+
getExtendedPublicKey,
|
|
576
|
+
getExtendedPublicKeyInfo,
|
|
577
|
+
signAndBroadcastTransaction,
|
|
578
|
+
transfer,
|
|
579
|
+
transferFromMultipleAddresses,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
480
582
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
583
|
+
async function getEVMWalletMethods({
|
|
584
|
+
chain,
|
|
585
|
+
derivationPath,
|
|
586
|
+
dmkSession,
|
|
587
|
+
onDeviceActionState,
|
|
588
|
+
originToken,
|
|
589
|
+
transport,
|
|
590
|
+
}: WalletMethodsParams<LedgerEVMChain>) {
|
|
591
|
+
const signer = await getLedgerClient({
|
|
592
|
+
chain,
|
|
593
|
+
derivationPath,
|
|
594
|
+
dmkSession,
|
|
595
|
+
onDeviceActionState,
|
|
596
|
+
originToken,
|
|
597
|
+
transport,
|
|
598
|
+
});
|
|
599
|
+
const { getEvmToolboxAsync } = await import("@swapkit/toolboxes/evm");
|
|
600
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
601
|
+
const toolbox = await getEvmToolboxAsync(chain, { signer });
|
|
602
|
+
|
|
603
|
+
return { ...toolbox, address };
|
|
604
|
+
}
|
|
486
605
|
|
|
487
|
-
|
|
488
|
-
|
|
606
|
+
async function getCosmosWalletMethods({
|
|
607
|
+
chain,
|
|
608
|
+
derivationPath,
|
|
609
|
+
dmkSession,
|
|
610
|
+
onDeviceActionState,
|
|
611
|
+
transport,
|
|
612
|
+
}: WalletMethodsParams<Chain.Cosmos>) {
|
|
613
|
+
const signer = await getLedgerClient({ chain, derivationPath, dmkSession, onDeviceActionState, transport });
|
|
614
|
+
const { getCosmosToolbox } = await import("@swapkit/toolboxes/cosmos");
|
|
615
|
+
const toolbox = getCosmosToolbox(chain, { signer });
|
|
616
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
489
617
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
const signer = await getLedgerClient({ chain, derivationPath, transport });
|
|
493
|
-
const address = signer.getAddress();
|
|
494
|
-
const toolbox = getRippleToolbox({ signer });
|
|
618
|
+
return { ...toolbox, address };
|
|
619
|
+
}
|
|
495
620
|
|
|
496
|
-
|
|
497
|
-
|
|
621
|
+
async function getTHORChainWalletMethods({
|
|
622
|
+
chain,
|
|
623
|
+
derivationPath,
|
|
624
|
+
dmkSession,
|
|
625
|
+
onDeviceActionState,
|
|
626
|
+
transport,
|
|
627
|
+
}: WalletMethodsParams<Chain.THORChain>) {
|
|
628
|
+
const signer = await getLedgerClient({ chain, derivationPath, dmkSession, onDeviceActionState, transport });
|
|
629
|
+
const { getCosmosToolbox } = await import("@swapkit/toolboxes/cosmos");
|
|
630
|
+
const toolbox = getCosmosToolbox(chain, { signer });
|
|
631
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
632
|
+
const { sign: signMessage } = signer;
|
|
633
|
+
|
|
634
|
+
return { ...toolbox, address, signMessage };
|
|
635
|
+
}
|
|
498
636
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
637
|
+
async function getNearWalletMethods({
|
|
638
|
+
chain,
|
|
639
|
+
derivationPath,
|
|
640
|
+
dmkSession,
|
|
641
|
+
onDeviceActionState,
|
|
642
|
+
transport,
|
|
643
|
+
}: WalletMethodsParams<Chain.Near>) {
|
|
644
|
+
const { getNearToolbox } = await import("@swapkit/toolboxes/near");
|
|
645
|
+
const signer = await getLedgerClient({ chain, derivationPath, dmkSession, onDeviceActionState, transport });
|
|
646
|
+
const accountId = await signer.getAddress();
|
|
647
|
+
const toolbox = getNearToolbox({ signer });
|
|
504
648
|
|
|
505
|
-
|
|
506
|
-
|
|
649
|
+
return { ...toolbox, address: accountId };
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
async function getRippleWalletMethods({
|
|
653
|
+
chain,
|
|
654
|
+
derivationPath,
|
|
655
|
+
dmkSession,
|
|
656
|
+
onDeviceActionState,
|
|
657
|
+
transport,
|
|
658
|
+
}: WalletMethodsParams<Chain.Ripple>) {
|
|
659
|
+
const { getRippleToolbox } = await import("@swapkit/toolboxes/ripple");
|
|
660
|
+
const signer = await getLedgerClient({ chain, derivationPath, dmkSession, onDeviceActionState, transport });
|
|
661
|
+
const address = signer.getAddress();
|
|
662
|
+
const toolbox = getRippleToolbox({ signer });
|
|
507
663
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const signer = await getLedgerClient({ chain, derivationPath, transport });
|
|
511
|
-
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
512
|
-
const toolbox = getSuiToolbox({ signer });
|
|
664
|
+
return { ...toolbox, address };
|
|
665
|
+
}
|
|
513
666
|
|
|
514
|
-
|
|
515
|
-
|
|
667
|
+
async function getTronWalletMethods({
|
|
668
|
+
chain,
|
|
669
|
+
derivationPath,
|
|
670
|
+
dmkSession,
|
|
671
|
+
onDeviceActionState,
|
|
672
|
+
transport,
|
|
673
|
+
}: WalletMethodsParams<Chain.Tron>) {
|
|
674
|
+
const { getTronToolbox } = await import("@swapkit/toolboxes/tron");
|
|
675
|
+
const signer = await getLedgerClient({ chain, derivationPath, dmkSession, onDeviceActionState, transport });
|
|
676
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
677
|
+
const toolbox = getTronToolbox({ signer });
|
|
678
|
+
|
|
679
|
+
return { ...toolbox, address };
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
async function getSuiWalletMethods({
|
|
683
|
+
chain,
|
|
684
|
+
derivationPath,
|
|
685
|
+
dmkSession,
|
|
686
|
+
onDeviceActionState,
|
|
687
|
+
transport,
|
|
688
|
+
}: WalletMethodsParams<Chain.Sui>) {
|
|
689
|
+
const { getSuiToolbox } = await import("@swapkit/toolboxes/sui");
|
|
690
|
+
const signer = await getLedgerClient({ chain, derivationPath, dmkSession, onDeviceActionState, transport });
|
|
691
|
+
const address = await getLedgerAddress({ chain, ledgerClient: signer });
|
|
692
|
+
const toolbox = getSuiToolbox({ signer });
|
|
693
|
+
|
|
694
|
+
return { ...toolbox, address };
|
|
695
|
+
}
|
|
516
696
|
|
|
517
|
-
|
|
518
|
-
|
|
697
|
+
function getWalletMethods(params: WalletMethodsParams) {
|
|
698
|
+
if (!isLedgerSupportedChain(params.chain)) {
|
|
699
|
+
throw new SwapKitError("wallet_ledger_chain_not_supported", { chain: params.chain });
|
|
519
700
|
}
|
|
701
|
+
|
|
702
|
+
return match(params.chain)
|
|
703
|
+
.with(P.union(...LEDGER_UTXO_CHAINS), (chain) => getUTXOWalletMethods({ ...params, chain }))
|
|
704
|
+
.with(P.union(...LEDGER_EVM_CHAINS), (chain) => getEVMWalletMethods({ ...params, chain }))
|
|
705
|
+
.with(Chain.Cosmos, (chain) => getCosmosWalletMethods({ ...params, chain }))
|
|
706
|
+
.with(Chain.THORChain, (chain) => getTHORChainWalletMethods({ ...params, chain }))
|
|
707
|
+
.with(Chain.Near, (chain) => getNearWalletMethods({ ...params, chain }))
|
|
708
|
+
.with(Chain.Ripple, (chain) => getRippleWalletMethods({ ...params, chain }))
|
|
709
|
+
.with(Chain.Tron, (chain) => getTronWalletMethods({ ...params, chain }))
|
|
710
|
+
.with(Chain.Sui, (chain) => getSuiWalletMethods({ ...params, chain }))
|
|
711
|
+
.exhaustive();
|
|
520
712
|
}
|
|
713
|
+
|
|
714
|
+
export type { LedgerDeviceActionState, LedgerDeviceActionStateHandler, LedgerDMKSession } from "./helpers";
|
|
715
|
+
export { disconnectLedgerDMKSession, getLedgerDMKSession, preloadLedgerDMK } from "./helpers";
|