@faremeter/wallet-ledger 0.1.2 → 0.5.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/src/evm.d.ts +2 -2
- package/dist/src/evm.d.ts.map +1 -1
- package/dist/src/evm.js +6 -6
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/interface.d.ts +10 -0
- package/dist/src/interface.d.ts.map +1 -0
- package/dist/src/interface.js +14 -0
- package/dist/src/logger.d.ts +2 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +2 -0
- package/dist/src/transport.d.ts.map +1 -1
- package/dist/src/transport.js +2 -1
- package/dist/src/types.d.ts +5 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils.d.ts +2 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +6 -14
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/src/evm.ts +7 -8
- package/src/index.ts +1 -0
- package/src/interface.ts +25 -0
- package/src/logger.ts +3 -0
- package/src/transport.ts +2 -1
- package/src/types.ts +6 -0
- package/src/utils.ts +7 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faremeter/wallet-ledger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -8,14 +8,15 @@
|
|
|
8
8
|
"@ledgerhq/hw-app-eth": "^6.36.0",
|
|
9
9
|
"@ledgerhq/hw-app-solana": "^7.2.0",
|
|
10
10
|
"@ledgerhq/hw-transport": "^6.31.0",
|
|
11
|
-
"@ledgerhq/hw-transport-webusb": "^6.29.0",
|
|
12
11
|
"@ledgerhq/hw-transport-node-hid": "^6.29.0",
|
|
13
|
-
"@
|
|
14
|
-
"
|
|
15
|
-
"
|
|
12
|
+
"@ledgerhq/hw-transport-webusb": "^6.29.0",
|
|
13
|
+
"@logtape/logtape": "1.0.4",
|
|
14
|
+
"@solana/web3.js": "1.98.4",
|
|
15
|
+
"arktype": "2.1.21",
|
|
16
|
+
"viem": "2.37.2"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
|
-
"
|
|
19
|
-
"
|
|
19
|
+
"tsc-esm-fix": "3.1.2",
|
|
20
|
+
"typescript": "5.9.2"
|
|
20
21
|
}
|
|
21
22
|
}
|
package/src/evm.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { baseSepolia, mainnet, sepolia } from "viem/chains";
|
|
|
13
13
|
import Eth from "@ledgerhq/hw-app-eth/lib-es/Eth";
|
|
14
14
|
import { type } from "arktype";
|
|
15
15
|
import { createTransport } from "./transport";
|
|
16
|
-
import type { LedgerEvmWallet } from "./types";
|
|
16
|
+
import type { LedgerEvmWallet, UserInterface } from "./types";
|
|
17
17
|
|
|
18
18
|
interface NetworkConfig {
|
|
19
19
|
chain: Chain;
|
|
@@ -45,6 +45,7 @@ const NETWORK_CONFIGS = new Map<string, NetworkConfig>([
|
|
|
45
45
|
]);
|
|
46
46
|
|
|
47
47
|
export async function createLedgerEvmWallet(
|
|
48
|
+
ui: UserInterface,
|
|
48
49
|
network: string,
|
|
49
50
|
derivationPath: string,
|
|
50
51
|
): Promise<LedgerEvmWallet> {
|
|
@@ -169,12 +170,10 @@ export async function createLedgerEvmWallet(
|
|
|
169
170
|
types,
|
|
170
171
|
});
|
|
171
172
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
"\nPlease approve the transaction on your Ledger device...",
|
|
177
|
-
);
|
|
173
|
+
ui.message("\nEIP-712 hashes calculated:");
|
|
174
|
+
ui.message(` Domain separator: ${domainSeparator}`);
|
|
175
|
+
ui.message(` Message hash: ${messageHash}`);
|
|
176
|
+
ui.message(`\nPlease approve the transaction on your Ledger device...`);
|
|
178
177
|
|
|
179
178
|
const result = await eth.signEIP712HashedMessage(
|
|
180
179
|
derivationPath,
|
|
@@ -186,7 +185,7 @@ export async function createLedgerEvmWallet(
|
|
|
186
185
|
`0x${result.r}${result.s}${result.v.toString(16).padStart(2, "0")}` as Hex;
|
|
187
186
|
return signature;
|
|
188
187
|
} catch (error) {
|
|
189
|
-
|
|
188
|
+
ui.message(`EIP-712 signing failed: ${error}`);
|
|
190
189
|
throw error;
|
|
191
190
|
}
|
|
192
191
|
},
|
package/src/index.ts
CHANGED
package/src/interface.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { UserInterface } from "./types";
|
|
2
|
+
|
|
3
|
+
export type createReadlineInterfaceArgs = {
|
|
4
|
+
stdin: NodeJS.ReadableStream;
|
|
5
|
+
stdout: NodeJS.WritableStream;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export async function createReadlineInterface(
|
|
9
|
+
args: createReadlineInterfaceArgs,
|
|
10
|
+
) {
|
|
11
|
+
const readline = await import("readline");
|
|
12
|
+
const rl = readline.createInterface({
|
|
13
|
+
input: args.stdin,
|
|
14
|
+
output: args.stdout,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
message: (msg: string) => void args.stdout.write(msg + "\n"),
|
|
19
|
+
question: async (q: string) =>
|
|
20
|
+
new Promise<string>((resolve) => {
|
|
21
|
+
rl.question(q, resolve);
|
|
22
|
+
}),
|
|
23
|
+
close: async () => rl.close(),
|
|
24
|
+
} satisfies UserInterface;
|
|
25
|
+
}
|
package/src/logger.ts
ADDED
package/src/transport.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logger } from "./logger";
|
|
1
2
|
import type Transport from "@ledgerhq/hw-transport";
|
|
2
3
|
|
|
3
4
|
const LEDGER_ERRORS: Record<string, string> = {
|
|
@@ -67,7 +68,7 @@ export async function createTransport(maxRetries = 3): Promise<Transport> {
|
|
|
67
68
|
i < maxRetries - 1 &&
|
|
68
69
|
(errorMessage.includes("USB") || errorMessage.includes("device"))
|
|
69
70
|
) {
|
|
70
|
-
|
|
71
|
+
logger.warning(`USB connection attempt ${i + 1} failed, retrying...`);
|
|
71
72
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
72
73
|
continue;
|
|
73
74
|
}
|
package/src/types.ts
CHANGED
|
@@ -29,3 +29,9 @@ export interface LedgerTransportWrapper {
|
|
|
29
29
|
transport: Transport;
|
|
30
30
|
close: () => Promise<void>;
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
export interface UserInterface {
|
|
34
|
+
message: (msg: string) => void;
|
|
35
|
+
question: (prompt: string) => Promise<string>;
|
|
36
|
+
close: () => Promise<void>;
|
|
37
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -2,6 +2,7 @@ import Eth from "@ledgerhq/hw-app-eth/lib-es/Eth";
|
|
|
2
2
|
import Solana from "@ledgerhq/hw-app-solana/lib-es/Solana";
|
|
3
3
|
import { PublicKey } from "@solana/web3.js";
|
|
4
4
|
import { createTransport, translateLedgerError } from "./transport";
|
|
5
|
+
import type { UserInterface } from "./types";
|
|
5
6
|
|
|
6
7
|
function evmDerivationPath(index: number) {
|
|
7
8
|
return `m/44'/60'/${index}'/0/0`;
|
|
@@ -12,11 +13,12 @@ function solanaDerivationPath(index: number) {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export async function selectLedgerAccount(
|
|
16
|
+
ui: UserInterface,
|
|
15
17
|
type: "evm" | "solana",
|
|
16
18
|
numAccounts = 5,
|
|
17
19
|
): Promise<{ path: string; address: string } | null> {
|
|
18
20
|
const isEvm = type === "evm";
|
|
19
|
-
|
|
21
|
+
ui.message(
|
|
20
22
|
`\nScanning first ${numAccounts} ${isEvm ? "Ethereum" : "Solana"} accounts...`,
|
|
21
23
|
);
|
|
22
24
|
|
|
@@ -39,7 +41,7 @@ export async function selectLedgerAccount(
|
|
|
39
41
|
? address
|
|
40
42
|
: `0x${address}`;
|
|
41
43
|
accounts.push({ path, address: normalizedAddress });
|
|
42
|
-
|
|
44
|
+
ui.message(`${i + 1}. ${normalizedAddress}`);
|
|
43
45
|
}
|
|
44
46
|
} else {
|
|
45
47
|
const solana = new Solana(transport);
|
|
@@ -54,28 +56,19 @@ export async function selectLedgerAccount(
|
|
|
54
56
|
const publicKey = new PublicKey(result.address);
|
|
55
57
|
const address = publicKey.toBase58();
|
|
56
58
|
accounts.push({ path, address });
|
|
57
|
-
|
|
59
|
+
ui.message(`${i + 1}. ${address}`);
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
} finally {
|
|
61
63
|
await transport.close();
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
const
|
|
65
|
-
const rl = readline.createInterface({
|
|
66
|
-
input: process.stdin,
|
|
67
|
-
output: process.stdout,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const selection = await new Promise<string>((resolve) => {
|
|
71
|
-
rl.question(`\nSelect account (1-${numAccounts}): `, resolve);
|
|
72
|
-
});
|
|
73
|
-
rl.close();
|
|
66
|
+
const selection = await ui.question(`\nSelect account (1-${numAccounts}): `);
|
|
74
67
|
|
|
75
68
|
const index = parseInt(selection) - 1;
|
|
76
69
|
|
|
77
70
|
if (index < 0 || index >= accounts.length) {
|
|
78
|
-
|
|
71
|
+
ui.message("Invalid selection");
|
|
79
72
|
return null;
|
|
80
73
|
}
|
|
81
74
|
|