@swapkit/wallet-hardware 5.0.1 → 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-xkh15edk.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-20wx60bn.js.map → chunk-5c7b7z2d.js.map} +2 -2
- package/dist/chunk-5p3ttw6y.js +4 -0
- package/dist/{chunk-1jpcb30j.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-4tbtxdxa.js.map → chunk-jewm2ag3.js.map} +2 -2
- 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 -24
- 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 -5
- package/dist/trezor/index.js +2 -2
- package/dist/trezor/index.js.map +3 -3
- 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/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 +115 -27
- package/dist/chunk-1jpcb30j.js +0 -5
- package/dist/chunk-20wx60bn.js +0 -4
- package/dist/chunk-4tbtxdxa.js +0 -5
- package/dist/chunk-7v7cgm69.js +0 -4
- package/dist/chunk-7v7cgm69.js.map +0 -10
- package/dist/chunk-83g13ck6.js +0 -5
- package/dist/chunk-83g13ck6.js.map +0 -10
- package/dist/chunk-h2r568rz.js +0 -4
- package/dist/chunk-h2r568rz.js.map +0 -10
- package/dist/chunk-xkh15edk.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 -204
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
1
|
+
import type { BlindSigningReporter } from "@ledgerhq/context-module";
|
|
2
|
+
import type { TypedDataDomain as LedgerTypedDataDomain, SignerEth } from "@ledgerhq/device-signer-kit-ethereum";
|
|
3
3
|
import {
|
|
4
4
|
ChainId,
|
|
5
5
|
type DerivationPathArray,
|
|
@@ -10,66 +10,107 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
AbstractSigner,
|
|
12
12
|
type Provider,
|
|
13
|
+
type TransactionLike,
|
|
13
14
|
type TransactionRequest,
|
|
14
15
|
type TypedDataDomain,
|
|
15
16
|
type TypedDataField,
|
|
16
17
|
} from "ethers";
|
|
17
18
|
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
fetchLedgerNetworkCertificate,
|
|
21
|
-
fetchLedgerNetworkDescriptor,
|
|
22
|
-
provideLedgerCertificate,
|
|
23
|
-
provideLedgerNetworkInformation,
|
|
24
|
-
} from "../helpers/ledgerNetworkInfo";
|
|
25
|
-
|
|
26
|
-
const LEDGER_INCORRECT_DATA = 0x6a80;
|
|
27
|
-
|
|
28
|
-
const ARC_CHAIN_ID = Number(ChainId.Arc);
|
|
29
|
-
|
|
30
|
-
type LedgerTransactionResolution = Awaited<
|
|
31
|
-
ReturnType<typeof import("@ledgerhq/hw-app-eth")["ledgerService"]["resolveTransaction"]>
|
|
32
|
-
>;
|
|
33
|
-
|
|
34
|
-
function isLedgerIncorrectDataError(error: unknown) {
|
|
35
|
-
return (
|
|
36
|
-
error instanceof Error &&
|
|
37
|
-
"statusCode" in error &&
|
|
38
|
-
(error as { statusCode: number }).statusCode === LEDGER_INCORRECT_DATA
|
|
39
|
-
);
|
|
40
|
-
}
|
|
19
|
+
import { createLedgerSessionSigner, type LedgerDMKSession } from "../helpers/dmk";
|
|
20
|
+
import { executeLedgerDeviceAction, type LedgerDeviceActionStateHandler } from "../helpers/executeDeviceAction";
|
|
41
21
|
|
|
42
|
-
|
|
43
|
-
|
|
22
|
+
interface EVMLedgerParams {
|
|
23
|
+
dmkSession?: LedgerDMKSession;
|
|
24
|
+
provider: Provider;
|
|
25
|
+
derivationPath?: DerivationPathArray | string;
|
|
26
|
+
chainId?: ChainId;
|
|
27
|
+
onDeviceActionState?: LedgerDeviceActionStateHandler;
|
|
28
|
+
originToken?: string;
|
|
44
29
|
}
|
|
45
30
|
|
|
46
|
-
function
|
|
47
|
-
|
|
31
|
+
function selectTypedDataTypes({
|
|
32
|
+
primaryType,
|
|
33
|
+
types,
|
|
34
|
+
}: {
|
|
35
|
+
primaryType: string;
|
|
36
|
+
types: Record<string, TypedDataField[]>;
|
|
37
|
+
}) {
|
|
38
|
+
const selectedTypes: Record<string, TypedDataField[]> = {};
|
|
39
|
+
|
|
40
|
+
function addType(typeName: string) {
|
|
41
|
+
if (Object.hasOwn(selectedTypes, typeName) || !Object.hasOwn(types, typeName)) return;
|
|
42
|
+
const fields = types[typeName];
|
|
43
|
+
if (!fields) return;
|
|
44
|
+
|
|
45
|
+
selectedTypes[typeName] = fields;
|
|
46
|
+
for (const field of fields) addType(field.type.replace(/\[[0-9]*\]/g, ""));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
addType(primaryType);
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
if (!Object.hasOwn(selectedTypes, primaryType)) {
|
|
52
|
+
throw new SwapKitError("wallet_ledger_invalid_params", {
|
|
53
|
+
primaryType,
|
|
54
|
+
reason: "The EIP-712 primary type is not defined",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return selectedTypes;
|
|
51
59
|
}
|
|
52
60
|
|
|
61
|
+
const disabledBlindSigningReporter: BlindSigningReporter = {
|
|
62
|
+
// The context module ignores the result; the cast avoids depending on purify-ts for an unused Either.
|
|
63
|
+
report: () => Promise.resolve(undefined as unknown as Awaited<ReturnType<BlindSigningReporter["report"]>>),
|
|
64
|
+
};
|
|
65
|
+
|
|
53
66
|
class EVMLedgerInterface extends AbstractSigner {
|
|
54
67
|
chainId: ChainId = ChainId.Ethereum;
|
|
55
68
|
derivationPath = "";
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
private
|
|
59
|
-
private readonly
|
|
60
|
-
private arcNetworkRegistered = false;
|
|
69
|
+
private readonly dmkSession?: LedgerDMKSession;
|
|
70
|
+
private readonly getLedgerSigner: () => Promise<SignerEth>;
|
|
71
|
+
private readonly onDeviceActionState?: LedgerDeviceActionStateHandler;
|
|
72
|
+
private readonly originToken?: string;
|
|
61
73
|
|
|
62
74
|
constructor({
|
|
63
75
|
provider,
|
|
76
|
+
dmkSession,
|
|
64
77
|
derivationPath = NetworkDerivationPath.OP,
|
|
65
78
|
chainId = ChainId.Optimism,
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
onDeviceActionState,
|
|
80
|
+
originToken,
|
|
81
|
+
}: EVMLedgerParams) {
|
|
68
82
|
super(provider);
|
|
69
83
|
|
|
70
84
|
this.chainId = chainId || ChainId.Ethereum;
|
|
71
|
-
this.derivationPath =
|
|
72
|
-
|
|
85
|
+
this.derivationPath = (
|
|
86
|
+
typeof derivationPath === "string" ? derivationPath : derivationPathToString(derivationPath)
|
|
87
|
+
).replace(/^m\//, "");
|
|
88
|
+
this.dmkSession = dmkSession;
|
|
89
|
+
this.onDeviceActionState = onDeviceActionState;
|
|
90
|
+
this.originToken = originToken;
|
|
91
|
+
this.getLedgerSigner = createLedgerSessionSigner({
|
|
92
|
+
build: async (session) => {
|
|
93
|
+
const [{ ContextModuleBuilder, ContextModuleChainID }, { SignerEthBuilder }] = await Promise.all([
|
|
94
|
+
import("@ledgerhq/context-module"),
|
|
95
|
+
import("@ledgerhq/device-signer-kit-ethereum"),
|
|
96
|
+
]);
|
|
97
|
+
// Same context module the signer kit builds by default, minus the blind-signing reporter that
|
|
98
|
+
// would post chain, target address and device model to Ledger on every signature.
|
|
99
|
+
const contextModule = new ContextModuleBuilder({
|
|
100
|
+
loggerFactory: (tag) => session.dmk.getLoggerFactory()(["ContextModule", tag]),
|
|
101
|
+
originToken,
|
|
102
|
+
})
|
|
103
|
+
.setChain(ContextModuleChainID.Ethereum)
|
|
104
|
+
.setBlindSigningReporter(disabledBlindSigningReporter)
|
|
105
|
+
.build();
|
|
106
|
+
// The signer kit also calls the optional sign reporter after every signature. 2.6.0 leaves it unset
|
|
107
|
+
// and offers no builder setter, so keep it inert in case a later 2.x release wires it up.
|
|
108
|
+
contextModule.signReport = () => Promise.resolve();
|
|
109
|
+
|
|
110
|
+
return new SignerEthBuilder({ ...session, originToken }).withContextModule(contextModule).build();
|
|
111
|
+
},
|
|
112
|
+
dmkSession,
|
|
113
|
+
});
|
|
73
114
|
|
|
74
115
|
Object.defineProperty(this, "provider", { enumerable: true, value: provider || null, writable: false });
|
|
75
116
|
}
|
|
@@ -78,58 +119,47 @@ class EVMLedgerInterface extends AbstractSigner {
|
|
|
78
119
|
new EVMLedgerInterface({
|
|
79
120
|
chainId: this.chainId,
|
|
80
121
|
derivationPath: this.derivationPath,
|
|
122
|
+
dmkSession: this.dmkSession,
|
|
123
|
+
onDeviceActionState: this.onDeviceActionState,
|
|
124
|
+
originToken: this.originToken,
|
|
81
125
|
provider,
|
|
82
|
-
transport: this.transport ?? this.injectedTransport,
|
|
83
126
|
});
|
|
84
127
|
|
|
85
|
-
checkOrCreateTransportAndLedger = async () => {
|
|
86
|
-
await this.createTransportAndLedger();
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
createTransportAndLedger = async () => {
|
|
90
|
-
if (this.ledgerApp) return;
|
|
91
|
-
|
|
92
|
-
this.transport ||= this.injectedTransport ?? (await getLedgerTransport());
|
|
93
|
-
const EthereumApp = (await import("@ledgerhq/hw-app-eth")).default;
|
|
94
|
-
|
|
95
|
-
this.ledgerApp = new EthereumApp(this.transport);
|
|
96
|
-
};
|
|
97
|
-
|
|
98
128
|
getAddress = async () => {
|
|
99
|
-
const
|
|
100
|
-
if (!
|
|
101
|
-
return
|
|
129
|
+
const { address } = await this.getAddressAndPubKey();
|
|
130
|
+
if (!address) throw new SwapKitError("wallet_ledger_failed_to_get_address");
|
|
131
|
+
return address;
|
|
102
132
|
};
|
|
103
133
|
|
|
104
134
|
getAddressAndPubKey = async () => {
|
|
105
|
-
await this.
|
|
106
|
-
return this.ledgerApp?.getAddress(this.derivationPath);
|
|
107
|
-
};
|
|
135
|
+
const ledgerSigner = await this.getLedgerSigner();
|
|
108
136
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
137
|
+
return executeLedgerDeviceAction({
|
|
138
|
+
action: () => ledgerSigner.getAddress(this.derivationPath, { chainId: Number(this.chainId) }),
|
|
139
|
+
onDeviceActionState: this.onDeviceActionState,
|
|
140
|
+
});
|
|
112
141
|
};
|
|
113
142
|
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
await this.createTransportAndLedger();
|
|
117
|
-
|
|
118
|
-
const sig = await this.ledgerApp?.signPersonalMessage(this.derivationPath, messageHex);
|
|
119
|
-
|
|
120
|
-
if (!sig) throw new SwapKitError("wallet_ledger_signing_error");
|
|
143
|
+
showAddressAndPubKey = async () => {
|
|
144
|
+
const ledgerSigner = await this.getLedgerSigner();
|
|
121
145
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
146
|
+
return executeLedgerDeviceAction({
|
|
147
|
+
action: () =>
|
|
148
|
+
ledgerSigner.getAddress(this.derivationPath, { chainId: Number(this.chainId), checkOnDevice: true }),
|
|
149
|
+
onDeviceActionState: this.onDeviceActionState,
|
|
150
|
+
});
|
|
125
151
|
};
|
|
126
152
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
153
|
+
signMessage = async (message: string | Uint8Array) => {
|
|
154
|
+
const { Signature, toUtf8Bytes } = await import("ethers");
|
|
155
|
+
const messageBytes = typeof message === "string" ? toUtf8Bytes(message) : message;
|
|
156
|
+
const ledgerSigner = await this.getLedgerSigner();
|
|
157
|
+
const signature = await executeLedgerDeviceAction({
|
|
158
|
+
action: () => ledgerSigner.signMessage(this.derivationPath, messageBytes),
|
|
159
|
+
onDeviceActionState: this.onDeviceActionState,
|
|
160
|
+
});
|
|
131
161
|
|
|
132
|
-
return
|
|
162
|
+
return Signature.from(signature).serialized;
|
|
133
163
|
};
|
|
134
164
|
|
|
135
165
|
signTypedData = async (
|
|
@@ -139,152 +169,165 @@ class EVMLedgerInterface extends AbstractSigner {
|
|
|
139
169
|
explicitPrimaryType?: string,
|
|
140
170
|
) => {
|
|
141
171
|
const { buildEIP712DomainType } = await import("@swapkit/toolboxes/evm");
|
|
142
|
-
const { Signature, TypedDataEncoder } = await import("ethers");
|
|
143
|
-
await this.createTransportAndLedger();
|
|
144
|
-
|
|
172
|
+
const { hexlify, Signature, TypedDataEncoder } = await import("ethers");
|
|
145
173
|
const { EIP712Domain: _, ...filteredTypes } = types;
|
|
146
174
|
const primaryType = explicitPrimaryType ?? TypedDataEncoder.from(filteredTypes).primaryType;
|
|
175
|
+
const resolutionTypes = selectTypedDataTypes({ primaryType, types: filteredTypes });
|
|
176
|
+
const populated = await TypedDataEncoder.resolveNames(domain, resolutionTypes, value, async (name) => {
|
|
177
|
+
const resolvedAddress = await this.resolveName(name);
|
|
178
|
+
if (!resolvedAddress) throw new SwapKitError("wallet_ledger_invalid_params", { name });
|
|
179
|
+
return resolvedAddress;
|
|
180
|
+
});
|
|
181
|
+
const chainId = populated.domain.chainId == null ? undefined : Number(populated.domain.chainId);
|
|
147
182
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
try {
|
|
151
|
-
sig = await this.ledgerApp?.signEIP712Message(this.derivationPath, {
|
|
152
|
-
domain: domain as Record<string, unknown>,
|
|
153
|
-
message: value,
|
|
154
|
-
primaryType,
|
|
155
|
-
types: { EIP712Domain: buildEIP712DomainType(domain), ...filteredTypes },
|
|
156
|
-
});
|
|
157
|
-
} catch (error) {
|
|
158
|
-
const isLedgerDeviceError = error instanceof Error && "statusCode" in error;
|
|
159
|
-
if (!isLedgerDeviceError || (isLedgerDeviceError && (error as { statusCode: number }).statusCode === 0x6985)) {
|
|
160
|
-
throw error;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const domainSeparator = TypedDataEncoder.hashDomain(domain).slice(2);
|
|
164
|
-
const messageHash = TypedDataEncoder.from(filteredTypes).hash(value).slice(2);
|
|
165
|
-
|
|
166
|
-
sig = await this.ledgerApp?.signEIP712HashedMessage(this.derivationPath, domainSeparator, messageHash);
|
|
183
|
+
if (chainId !== undefined && !Number.isSafeInteger(chainId)) {
|
|
184
|
+
throw new SwapKitError("wallet_ledger_invalid_params", { chainId: populated.domain.chainId });
|
|
167
185
|
}
|
|
168
186
|
|
|
169
|
-
|
|
187
|
+
const ledgerDomain = {
|
|
188
|
+
...(populated.domain.chainId != null && { chainId }),
|
|
189
|
+
...(populated.domain.name != null && { name: populated.domain.name }),
|
|
190
|
+
...(populated.domain.salt != null && { salt: hexlify(populated.domain.salt) }),
|
|
191
|
+
...(populated.domain.verifyingContract != null && { verifyingContract: populated.domain.verifyingContract }),
|
|
192
|
+
...(populated.domain.version != null && { version: populated.domain.version }),
|
|
193
|
+
} satisfies LedgerTypedDataDomain;
|
|
194
|
+
|
|
195
|
+
const typedData = {
|
|
196
|
+
domain: ledgerDomain,
|
|
197
|
+
message: populated.value,
|
|
198
|
+
primaryType,
|
|
199
|
+
// Only the primary type and its dependencies: the signer kit's legacy fallback hashes with ethers,
|
|
200
|
+
// which rejects unused types.
|
|
201
|
+
types: { EIP712Domain: buildEIP712DomainType(populated.domain), ...resolutionTypes },
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const ledgerSigner = await this.getLedgerSigner();
|
|
205
|
+
const signature = await executeLedgerDeviceAction({
|
|
206
|
+
action: () => ledgerSigner.signTypedData(this.derivationPath, typedData),
|
|
207
|
+
onDeviceActionState: this.onDeviceActionState,
|
|
208
|
+
});
|
|
170
209
|
|
|
171
|
-
|
|
172
|
-
sig.s = `0x${sig.s}`;
|
|
173
|
-
return Signature.from(sig).serialized;
|
|
210
|
+
return Signature.from(signature).serialized;
|
|
174
211
|
};
|
|
175
212
|
|
|
176
213
|
signTransaction = async (tx: TransactionRequest) => {
|
|
177
|
-
const { Transaction } = await import(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
gasLimit: tx.gasLimit,
|
|
188
|
-
...(tx.gasPrice && { gasPrice: tx.gasPrice }),
|
|
189
|
-
...(!tx.gasPrice &&
|
|
190
|
-
tx.maxFeePerGas && { maxFeePerGas: tx.maxFeePerGas, maxPriorityFeePerGas: tx.maxPriorityFeePerGas }),
|
|
191
|
-
nonce: nonce !== undefined ? Number(nonce.toString()) : transactionCount,
|
|
192
|
-
to: tx.to?.toString(),
|
|
193
|
-
type: tx.type && !Number.isNaN(tx.type) ? tx.type : tx.maxFeePerGas ? 2 : 0,
|
|
194
|
-
value: tx.value,
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
// ledger expects the tx to be serialized without the 0x prefix
|
|
198
|
-
const unsignedTx = Transaction.from(baseTx).unsignedSerialized.slice(2);
|
|
199
|
-
|
|
200
|
-
const { ledgerService } = await import("@ledgerhq/hw-app-eth");
|
|
214
|
+
const { copyRequest, getAddress, getBytes, resolveAddress, resolveProperties, Transaction } = await import(
|
|
215
|
+
"ethers"
|
|
216
|
+
);
|
|
217
|
+
const request = copyRequest(tx);
|
|
218
|
+
|
|
219
|
+
if (request.type === 4 || request.authorizationList?.length) {
|
|
220
|
+
throw new SwapKitError("wallet_ledger_invalid_params", {
|
|
221
|
+
message: "Ledger Ethereum DSK does not support EIP-7702 transactions",
|
|
222
|
+
});
|
|
223
|
+
}
|
|
201
224
|
|
|
202
|
-
const
|
|
203
|
-
const isArc = chainId === ARC_CHAIN_ID;
|
|
225
|
+
const expectedChainId = BigInt(this.chainId);
|
|
204
226
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
227
|
+
if (request.chainId != null && request.chainId !== expectedChainId) {
|
|
228
|
+
throw new SwapKitError("wallet_ledger_invalid_params", {
|
|
229
|
+
chainId: request.chainId,
|
|
230
|
+
expectedChainId,
|
|
231
|
+
message: "Transaction chainId does not match the Ledger client chain",
|
|
232
|
+
});
|
|
233
|
+
}
|
|
209
234
|
|
|
210
|
-
|
|
235
|
+
const { from, to } = await resolveProperties({
|
|
236
|
+
from: request.from ? resolveAddress(request.from, this) : undefined,
|
|
237
|
+
to: request.to ? resolveAddress(request.to, this) : undefined,
|
|
238
|
+
});
|
|
239
|
+
const signerAddress = from || request.nonce == null ? await this.getAddress() : undefined;
|
|
211
240
|
|
|
212
|
-
|
|
241
|
+
if (from && signerAddress && getAddress(from) !== getAddress(signerAddress)) {
|
|
242
|
+
throw new SwapKitError("wallet_ledger_invalid_params", {
|
|
243
|
+
message: "Transaction from address does not match the Ledger account",
|
|
213
244
|
});
|
|
245
|
+
}
|
|
214
246
|
|
|
215
|
-
if (
|
|
247
|
+
if (to) request.to = to;
|
|
248
|
+
delete request.from;
|
|
249
|
+
delete request.authorizationList;
|
|
250
|
+
request.chainId = expectedChainId;
|
|
251
|
+
// ethers infers EIP-2930 for an untyped gasPrice-only request; sign it as legacy, as before the signer kit.
|
|
252
|
+
const isUntypedLegacyRequest =
|
|
253
|
+
request.type == null &&
|
|
254
|
+
request.gasPrice != null &&
|
|
255
|
+
request.accessList == null &&
|
|
256
|
+
request.maxFeePerGas == null &&
|
|
257
|
+
request.maxPriorityFeePerGas == null;
|
|
258
|
+
if (isUntypedLegacyRequest) request.type = 0;
|
|
259
|
+
request.nonce ??= await this.provider?.getTransactionCount(signerAddress ?? (await this.getAddress()));
|
|
260
|
+
|
|
261
|
+
const baseTx = Transaction.from(request as TransactionLike<string>);
|
|
262
|
+
const unsignedTransaction = getBytes(baseTx.unsignedSerialized);
|
|
263
|
+
const ledgerSigner = await this.getLedgerSigner();
|
|
264
|
+
const signature = await executeLedgerDeviceAction({
|
|
265
|
+
action: () => ledgerSigner.signTransaction(this.derivationPath, unsignedTransaction),
|
|
266
|
+
onDeviceActionState: this.onDeviceActionState,
|
|
267
|
+
});
|
|
216
268
|
|
|
217
|
-
|
|
269
|
+
baseTx.signature = signature;
|
|
218
270
|
|
|
219
|
-
|
|
271
|
+
return baseTx.serialized;
|
|
272
|
+
};
|
|
273
|
+
}
|
|
220
274
|
|
|
221
|
-
|
|
275
|
+
interface LedgerParams {
|
|
276
|
+
dmkSession?: LedgerDMKSession;
|
|
277
|
+
provider: Provider;
|
|
278
|
+
derivationPath?: DerivationPathArray;
|
|
279
|
+
onDeviceActionState?: LedgerDeviceActionStateHandler;
|
|
280
|
+
originToken?: string;
|
|
281
|
+
}
|
|
222
282
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
283
|
+
export function ArbitrumLedger(params: LedgerParams) {
|
|
284
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Arbitrum });
|
|
285
|
+
}
|
|
226
286
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
chainId: number,
|
|
231
|
-
) => {
|
|
232
|
-
try {
|
|
233
|
-
return await this.ledgerApp?.signTransaction(this.derivationPath, unsignedTx, resolution);
|
|
234
|
-
} catch (error) {
|
|
235
|
-
const canSignBlind =
|
|
236
|
-
chainId === ARC_CHAIN_ID && isLedgerIncorrectDataError(error) && hasClearSigningPayload(resolution);
|
|
287
|
+
export function ArcLedger(params: LedgerParams) {
|
|
288
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Arc });
|
|
289
|
+
}
|
|
237
290
|
|
|
238
|
-
|
|
291
|
+
export function AuroraLedger(params: LedgerParams) {
|
|
292
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Aurora });
|
|
293
|
+
}
|
|
239
294
|
|
|
240
|
-
|
|
295
|
+
export function AvalancheLedger(params: LedgerParams) {
|
|
296
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Avalanche });
|
|
297
|
+
}
|
|
241
298
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
299
|
+
export function BaseLedger(params: LedgerParams) {
|
|
300
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Base });
|
|
301
|
+
}
|
|
245
302
|
|
|
246
|
-
|
|
247
|
-
|
|
303
|
+
export function EthereumLedger(params: LedgerParams) {
|
|
304
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Ethereum });
|
|
305
|
+
}
|
|
248
306
|
|
|
249
|
-
|
|
307
|
+
export function GnosisLedger(params: LedgerParams) {
|
|
308
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Gnosis });
|
|
309
|
+
}
|
|
250
310
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
fetchLedgerNetworkCertificate(deviceModelId),
|
|
255
|
-
]);
|
|
311
|
+
export function OptimismLedger(params: LedgerParams) {
|
|
312
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Optimism });
|
|
313
|
+
}
|
|
256
314
|
|
|
257
|
-
|
|
315
|
+
export function PolygonLedger(params: LedgerParams) {
|
|
316
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Polygon });
|
|
317
|
+
}
|
|
258
318
|
|
|
259
|
-
|
|
319
|
+
export function BinanceSmartChainLedger(params: LedgerParams) {
|
|
320
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.BinanceSmartChain });
|
|
321
|
+
}
|
|
260
322
|
|
|
261
|
-
|
|
323
|
+
export function MonadLedger(params: LedgerParams) {
|
|
324
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Monad });
|
|
325
|
+
}
|
|
262
326
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// the app will reject the metadata and signWithLedgerApp falls back to blind signing
|
|
266
|
-
}
|
|
267
|
-
};
|
|
327
|
+
export function XLayerLedger(params: LedgerParams) {
|
|
328
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.XLayer });
|
|
268
329
|
}
|
|
269
330
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
new EVMLedgerInterface({ ...params, chainId: ChainId.Arbitrum });
|
|
274
|
-
export const ArcLedger = (params: LedgerParams) => new EVMLedgerInterface({ ...params, chainId: ChainId.Arc });
|
|
275
|
-
export const AuroraLedger = (params: LedgerParams) => new EVMLedgerInterface({ ...params, chainId: ChainId.Aurora });
|
|
276
|
-
export const AvalancheLedger = (params: LedgerParams) =>
|
|
277
|
-
new EVMLedgerInterface({ ...params, chainId: ChainId.Avalanche });
|
|
278
|
-
export const BaseLedger = (params: LedgerParams) => new EVMLedgerInterface({ ...params, chainId: ChainId.Base });
|
|
279
|
-
export const EthereumLedger = (params: LedgerParams) =>
|
|
280
|
-
new EVMLedgerInterface({ ...params, chainId: ChainId.Ethereum });
|
|
281
|
-
export const GnosisLedger = (params: LedgerParams) => new EVMLedgerInterface({ ...params, chainId: ChainId.Gnosis });
|
|
282
|
-
export const OptimismLedger = (params: LedgerParams) =>
|
|
283
|
-
new EVMLedgerInterface({ ...params, chainId: ChainId.Optimism });
|
|
284
|
-
export const PolygonLedger = (params: LedgerParams) => new EVMLedgerInterface({ ...params, chainId: ChainId.Polygon });
|
|
285
|
-
export const BinanceSmartChainLedger = (params: LedgerParams) =>
|
|
286
|
-
new EVMLedgerInterface({ ...params, chainId: ChainId.BinanceSmartChain });
|
|
287
|
-
export const MonadLedger = (params: LedgerParams) => new EVMLedgerInterface({ ...params, chainId: ChainId.Monad });
|
|
288
|
-
export const XLayerLedger = (params: LedgerParams) => new EVMLedgerInterface({ ...params, chainId: ChainId.XLayer });
|
|
289
|
-
export const BerachainLedger = (params: LedgerParams) =>
|
|
290
|
-
new EVMLedgerInterface({ ...params, chainId: ChainId.Berachain });
|
|
331
|
+
export function BerachainLedger(params: LedgerParams) {
|
|
332
|
+
return new EVMLedgerInterface({ ...params, chainId: ChainId.Berachain });
|
|
333
|
+
}
|
|
@@ -1,18 +1,44 @@
|
|
|
1
|
+
import type { UserInteractionRequired } from "@ledgerhq/device-management-kit";
|
|
2
|
+
import type Near from "@ledgerhq/hw-app-near";
|
|
1
3
|
import type Transport from "@ledgerhq/hw-transport";
|
|
2
4
|
import type { SignedTransaction, Transaction } from "@near-js/transactions";
|
|
3
|
-
import type
|
|
5
|
+
import { Chain, type DerivationPathArray, NetworkDerivationPath, SwapKitError } from "@swapkit/helpers";
|
|
4
6
|
import type { NearSigner } from "@swapkit/toolboxes/near";
|
|
5
|
-
import { getLedgerTransport } from "../helpers/getLedgerTransport";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
import {
|
|
9
|
+
LEDGER_USER_INTERACTION_REQUIRED,
|
|
10
|
+
type LedgerJsClientParams,
|
|
11
|
+
normalizeLedgerJsClientParams,
|
|
12
|
+
runLedgerJsOperation,
|
|
13
|
+
} from "../helpers/ledgerJsDmkBridge";
|
|
12
14
|
|
|
15
|
+
type NearLedgerParams = LedgerJsClientParams<DerivationPathArray>;
|
|
16
|
+
|
|
17
|
+
export async function getNearLedgerClient(
|
|
18
|
+
paramsOrPath?: NearLedgerParams | DerivationPathArray,
|
|
19
|
+
transport?: Transport,
|
|
20
|
+
) {
|
|
21
|
+
const { derivationPath, ...connection } = normalizeLedgerJsClientParams({ paramsOrPath, transport });
|
|
13
22
|
const path = (derivationPath || NetworkDerivationPath[Chain.Near]).join("'/").concat("'");
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
async function runNearOperation<Output>({
|
|
25
|
+
operation,
|
|
26
|
+
requiredUserInteraction,
|
|
27
|
+
}: {
|
|
28
|
+
operation: (app: Near) => Promise<Output>;
|
|
29
|
+
requiredUserInteraction?: UserInteractionRequired;
|
|
30
|
+
}) {
|
|
31
|
+
const NearApp = (await import("@ledgerhq/hw-app-near")).default;
|
|
32
|
+
return runLedgerJsOperation({
|
|
33
|
+
appName: "NEAR",
|
|
34
|
+
connection,
|
|
35
|
+
createApp: (ledgerTransport) => new NearApp(ledgerTransport),
|
|
36
|
+
operation,
|
|
37
|
+
requiredUserInteraction,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { address, publicKey } = await runNearOperation({ operation: (app) => app.getAddress(path) });
|
|
16
42
|
|
|
17
43
|
const signer = {
|
|
18
44
|
getAddress() {
|
|
@@ -20,10 +46,11 @@ export async function getNearLedgerClient(derivationPath?: DerivationPathArray,
|
|
|
20
46
|
},
|
|
21
47
|
async getPublicKey() {
|
|
22
48
|
const { PublicKey } = await import("@near-js/crypto");
|
|
23
|
-
|
|
49
|
+
const encodedPublicKey = publicKey.startsWith("ed25519:") ? publicKey : `ed25519:${publicKey}`;
|
|
50
|
+
return PublicKey.fromString(encodedPublicKey);
|
|
24
51
|
},
|
|
25
52
|
|
|
26
|
-
signDelegateAction(_delegateAction:
|
|
53
|
+
signDelegateAction(_delegateAction: unknown) {
|
|
27
54
|
return Promise.reject(
|
|
28
55
|
new SwapKitError("wallet_ledger_method_not_supported", { method: "signDelegateAction", wallet: "Ledger" }),
|
|
29
56
|
);
|
|
@@ -44,17 +71,20 @@ export async function getNearLedgerClient(derivationPath?: DerivationPathArray,
|
|
|
44
71
|
async signTransaction(transaction: Transaction) {
|
|
45
72
|
const { Signature, SignedTransaction } = await import("@near-js/transactions");
|
|
46
73
|
try {
|
|
47
|
-
const signatureArray = await
|
|
74
|
+
const signatureArray = await runNearOperation({
|
|
75
|
+
operation: (app) => app.signTransaction(transaction.encode(), path),
|
|
76
|
+
requiredUserInteraction: LEDGER_USER_INTERACTION_REQUIRED.SignTransaction,
|
|
77
|
+
});
|
|
48
78
|
if (!signatureArray) {
|
|
49
|
-
throw new
|
|
79
|
+
throw new SwapKitError("wallet_ledger_signing_error", { reason: "Ledger returned no NEAR signature" });
|
|
50
80
|
}
|
|
51
81
|
|
|
52
82
|
const signature = new Signature({ data: signatureArray, keyType: 0 });
|
|
53
|
-
|
|
54
83
|
const signedTransaction = new SignedTransaction({ signature, transaction });
|
|
55
84
|
|
|
56
85
|
return [signatureArray, signedTransaction] as [Uint8Array<ArrayBufferLike>, SignedTransaction];
|
|
57
86
|
} catch (error) {
|
|
87
|
+
if (error instanceof SwapKitError) throw error;
|
|
58
88
|
throw new SwapKitError("wallet_ledger_signing_error", { error });
|
|
59
89
|
}
|
|
60
90
|
},
|