@reef-knot/ledger-connector 5.1.0 → 5.2.0-alpha.1
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/hid/account.d.ts +5 -0
- package/dist/hid/account.d.ts.map +1 -0
- package/dist/hid/account.js +56 -0
- package/dist/hid/connector.d.ts.map +1 -1
- package/dist/hid/connector.js +25 -26
- package/dist/hid/helpers.d.ts +0 -10
- package/dist/hid/helpers.d.ts.map +1 -1
- package/dist/hid/helpers.js +1 -32
- package/dist/hid/provider.d.ts +34 -14
- package/dist/hid/provider.d.ts.map +1 -1
- package/dist/hid/provider.js +145 -47
- package/dist/iframe/connector.d.ts.map +1 -1
- package/dist/iframe/connector.js +3 -10
- package/package.json +5 -17
- package/dist/hid/signer.d.ts +0 -29
- package/dist/hid/signer.d.ts.map +0 -1
- package/dist/hid/signer.js +0 -146
- package/dist/hid/types.d.ts +0 -10
- package/dist/hid/types.d.ts.map +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type Eth from '@ledgerhq/hw-app-eth';
|
|
2
|
+
import { type Address, type LocalAccount } from 'viem';
|
|
3
|
+
export type WithEthApp = <T>(callback: (eth: Eth) => T | Promise<T>) => Promise<T>;
|
|
4
|
+
export declare const createLedgerAccount: (address: Address, path: string, withEthApp: WithEthApp) => LocalAccount;
|
|
5
|
+
//# sourceMappingURL=account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/hid/account.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,sBAAsB,CAAC;AAE5C,OAAO,EAOL,KAAK,OAAO,EACZ,KAAK,YAAY,EAGlB,MAAM,MAAM,CAAC;AAId,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,EACzB,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,KACnC,OAAO,CAAC,CAAC,CAAC,CAAC;AAiBhB,eAAO,MAAM,mBAAmB,YACrB,OAAO,QACV,MAAM,cACA,UAAU,KACrB,YAiFC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { bytesToHex, getTypesForEIP712Domain, hashStruct, serializeSignature, serializeTransaction, stringToHex } from "viem";
|
|
2
|
+
import { toAccount } from "viem/accounts";
|
|
3
|
+
|
|
4
|
+
//#region src/hid/account.ts
|
|
5
|
+
const RESOLUTION_CONFIG = {
|
|
6
|
+
erc20: true,
|
|
7
|
+
externalPlugins: true,
|
|
8
|
+
nft: true
|
|
9
|
+
};
|
|
10
|
+
const shouldFallbackToHashedSigning = (error) => error?.statusText === "INS_NOT_SUPPORTED";
|
|
11
|
+
const toSignatureHex = ({ r, s, v }) => serializeSignature({
|
|
12
|
+
r: `0x${r}`,
|
|
13
|
+
s: `0x${s}`,
|
|
14
|
+
v: BigInt(v)
|
|
15
|
+
});
|
|
16
|
+
const createLedgerAccount = (address, path, withEthApp) => toAccount({
|
|
17
|
+
address,
|
|
18
|
+
async signTransaction(transaction, { serializer = serializeTransaction } = {}) {
|
|
19
|
+
const unsignedRawTx = (await serializer(transaction)).slice(2);
|
|
20
|
+
const { r, s, v } = await withEthApp((eth) => eth.clearSignTransaction(path, unsignedRawTx, RESOLUTION_CONFIG, true));
|
|
21
|
+
return serializer(transaction, {
|
|
22
|
+
r: `0x${r}`,
|
|
23
|
+
s: `0x${s}`,
|
|
24
|
+
v: BigInt(`0x${v}`)
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
async signMessage({ message }) {
|
|
28
|
+
const messageHex = typeof message === "string" ? stringToHex(message) : typeof message.raw === "string" ? message.raw : bytesToHex(message.raw);
|
|
29
|
+
return toSignatureHex(await withEthApp((eth) => eth.signPersonalMessage(path, messageHex.slice(2))));
|
|
30
|
+
},
|
|
31
|
+
async signTypedData(parameters) {
|
|
32
|
+
const { domain = {}, types, primaryType, message } = parameters;
|
|
33
|
+
return toSignatureHex(await withEthApp(async (eth) => {
|
|
34
|
+
try {
|
|
35
|
+
return await eth.signEIP712Message(path, parameters);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (!shouldFallbackToHashedSigning(error)) throw error;
|
|
38
|
+
const typedDataDomain = domain;
|
|
39
|
+
const domainSeparator = hashStruct({
|
|
40
|
+
data: typedDataDomain,
|
|
41
|
+
primaryType: "EIP712Domain",
|
|
42
|
+
types: { EIP712Domain: getTypesForEIP712Domain({ domain: typedDataDomain }) }
|
|
43
|
+
});
|
|
44
|
+
const messageHash = hashStruct({
|
|
45
|
+
data: message,
|
|
46
|
+
primaryType,
|
|
47
|
+
types
|
|
48
|
+
});
|
|
49
|
+
return eth.signEIP712HashedMessage(path, domainSeparator.slice(2), messageHash.slice(2));
|
|
50
|
+
}
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { createLedgerAccount };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../src/hid/connector.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAGrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,eAAO,MAAM,WAAW,cAAc,CAAC;AACvC,eAAO,MAAM,IAAI,WAAW,CAAC;AAG7B,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,YAAY,GACb,EAAE;IACD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,YAAY,EAAE,KAAK,CAAC;CACrB,
|
|
1
|
+
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../src/hid/connector.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAGrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,eAAO,MAAM,WAAW,cAAc,CAAC;AACvC,eAAO,MAAM,IAAI,WAAW,CAAC;AAG7B,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,YAAY,GACb,EAAE;IACD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,YAAY,EAAE,KAAK,CAAC;CACrB,yGAuHA;yBA7He,kBAAkB"}
|
package/dist/hid/connector.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { checkError, clearLedgerDerivationPath } from "./helpers.js";
|
|
2
2
|
import { ChainNotConfiguredError, ConnectorNotFoundError, createConnector } from "wagmi";
|
|
3
|
+
import { SwitchChainError } from "viem";
|
|
3
4
|
|
|
4
5
|
//#region src/hid/connector.ts
|
|
5
6
|
const idLedgerHid = "ledgerHID";
|
|
@@ -7,46 +8,55 @@ const name = "Ledger";
|
|
|
7
8
|
ledgerHIDConnector.type = "ledgerHID";
|
|
8
9
|
function ledgerHIDConnector({ rpc, defaultChain }) {
|
|
9
10
|
const providers = {};
|
|
11
|
+
let currentChainId;
|
|
10
12
|
return createConnector(({ chains, emitter }) => ({
|
|
11
13
|
id: idLedgerHid,
|
|
12
14
|
name,
|
|
13
15
|
type: ledgerHIDConnector.type,
|
|
14
16
|
async getProvider({ chainId } = {}) {
|
|
15
|
-
const chain = chains.find((x) => x.id === chainId) ?? defaultChain;
|
|
17
|
+
const chain = chains.find((x) => x.id === (chainId ?? currentChainId)) ?? defaultChain;
|
|
16
18
|
if (!providers[chain.id]) {
|
|
17
19
|
const { LedgerHQProvider } = await import("./provider.js");
|
|
18
|
-
providers[chain.id] = new LedgerHQProvider({
|
|
20
|
+
providers[chain.id] = new LedgerHQProvider({
|
|
21
|
+
chain,
|
|
22
|
+
rpcUrl: rpc?.[chain.id]
|
|
23
|
+
});
|
|
19
24
|
}
|
|
20
25
|
return providers[chain.id];
|
|
21
26
|
},
|
|
22
|
-
async connect({ withCapabilities = false } = {}) {
|
|
27
|
+
async connect({ chainId, withCapabilities = false } = {}) {
|
|
23
28
|
try {
|
|
24
|
-
|
|
29
|
+
currentChainId = chainId;
|
|
30
|
+
const provider = await this.getProvider({ chainId });
|
|
25
31
|
provider.on("disconnect", this.onDisconnect);
|
|
26
32
|
const account = await provider.enable();
|
|
27
|
-
const
|
|
33
|
+
const connectedChainId = await this.getChainId();
|
|
34
|
+
currentChainId = connectedChainId;
|
|
28
35
|
return {
|
|
29
36
|
accounts: withCapabilities ? [{
|
|
30
37
|
address: account,
|
|
31
38
|
capabilities: {}
|
|
32
39
|
}] : [account],
|
|
33
|
-
chainId
|
|
40
|
+
chainId: connectedChainId
|
|
34
41
|
};
|
|
35
42
|
} catch (error) {
|
|
43
|
+
currentChainId = void 0;
|
|
36
44
|
return checkError(error);
|
|
37
45
|
}
|
|
38
46
|
},
|
|
39
47
|
async disconnect() {
|
|
40
|
-
|
|
48
|
+
Object.values(providers).forEach((provider) => {
|
|
49
|
+
provider.removeListener("disconnect", this.onDisconnect);
|
|
50
|
+
provider.resetAccount();
|
|
51
|
+
});
|
|
52
|
+
currentChainId = void 0;
|
|
41
53
|
clearLedgerDerivationPath();
|
|
42
54
|
},
|
|
43
55
|
async getAccounts() {
|
|
44
56
|
return [await (await this.getProvider()).getAddress()];
|
|
45
57
|
},
|
|
46
58
|
async getChainId() {
|
|
47
|
-
|
|
48
|
-
if (chainId) return chainId;
|
|
49
|
-
throw new ChainNotConfiguredError();
|
|
59
|
+
return (await this.getProvider()).chain.id;
|
|
50
60
|
},
|
|
51
61
|
async isAuthorized() {
|
|
52
62
|
try {
|
|
@@ -59,22 +69,11 @@ function ledgerHIDConnector({ rpc, defaultChain }) {
|
|
|
59
69
|
}
|
|
60
70
|
},
|
|
61
71
|
async switchChain({ chainId }) {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
network: `${id}`,
|
|
68
|
-
nativeCurrency: {
|
|
69
|
-
decimals: 18,
|
|
70
|
-
name: "Ether",
|
|
71
|
-
symbol: "ETH"
|
|
72
|
-
},
|
|
73
|
-
rpcUrls: {
|
|
74
|
-
default: { http: [""] },
|
|
75
|
-
public: { http: [""] }
|
|
76
|
-
}
|
|
77
|
-
});
|
|
72
|
+
const chain = chains.find((x) => x.id === chainId);
|
|
73
|
+
if (!chain) throw new SwitchChainError(new ChainNotConfiguredError());
|
|
74
|
+
currentChainId = chainId;
|
|
75
|
+
emitter.emit("change", { chainId });
|
|
76
|
+
return chain;
|
|
78
77
|
},
|
|
79
78
|
onDisconnect() {
|
|
80
79
|
emitter.emit("disconnect");
|
package/dist/hid/helpers.d.ts
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
import { BigNumberish } from '@ethersproject/bignumber';
|
|
2
|
-
import { TransactionRequestExtended, UnsignedTransactionStrict } from './types';
|
|
3
|
-
export declare const isHIDSupported: () => boolean;
|
|
4
|
-
export declare const hasEIP1559: (tx: {
|
|
5
|
-
type?: number;
|
|
6
|
-
maxFeePerGas?: BigNumberish;
|
|
7
|
-
maxPriorityFeePerGas?: BigNumberish;
|
|
8
|
-
}) => boolean;
|
|
9
|
-
export declare const toNumber: (value: BigNumberish | undefined | null) => number | undefined;
|
|
10
|
-
export declare const convertToUnsigned: (tx: TransactionRequestExtended) => Promise<UnsignedTransactionStrict>;
|
|
11
1
|
export declare const checkError: (error: any) => never;
|
|
12
2
|
export declare const clearLedgerDerivationPath: () => void;
|
|
13
3
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/hid/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/hid/helpers.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,UAAW,GAAG,KAAG,KAmBvC,CAAC;AAEF,eAAO,MAAM,yBAAyB,YAErC,CAAC"}
|
package/dist/hid/helpers.js
CHANGED
|
@@ -1,37 +1,6 @@
|
|
|
1
1
|
import { LS_KEY_DERIVATION_PATH } from "./constants.js";
|
|
2
|
-
import { BigNumber } from "@ethersproject/bignumber";
|
|
3
|
-
import { resolveProperties } from "@ethersproject/properties";
|
|
4
2
|
|
|
5
3
|
//#region src/hid/helpers.ts
|
|
6
|
-
const hasEIP1559 = (tx) => {
|
|
7
|
-
return tx.type === 2 || tx.maxFeePerGas != null || tx.maxPriorityFeePerGas != null;
|
|
8
|
-
};
|
|
9
|
-
const toNumber = (value) => {
|
|
10
|
-
return value == null ? void 0 : BigNumber.from(value).toNumber();
|
|
11
|
-
};
|
|
12
|
-
const convertToUnsigned = async (tx) => {
|
|
13
|
-
const resolvedTx = await resolveProperties(tx);
|
|
14
|
-
const { chainId, data, gasLimit, gas, gasPrice, value, to } = resolvedTx;
|
|
15
|
-
const nonce = toNumber(resolvedTx.nonce);
|
|
16
|
-
const type = toNumber(resolvedTx.type);
|
|
17
|
-
const baseTx = {
|
|
18
|
-
gasLimit: gasLimit || gas,
|
|
19
|
-
type: type ?? 2,
|
|
20
|
-
chainId,
|
|
21
|
-
gasPrice,
|
|
22
|
-
nonce,
|
|
23
|
-
value,
|
|
24
|
-
data,
|
|
25
|
-
to
|
|
26
|
-
};
|
|
27
|
-
if (tx.accessList != null) baseTx.accessList = tx.accessList;
|
|
28
|
-
if (hasEIP1559(tx)) {
|
|
29
|
-
baseTx.maxFeePerGas = tx.maxFeePerGas;
|
|
30
|
-
baseTx.maxPriorityFeePerGas = tx.maxPriorityFeePerGas;
|
|
31
|
-
baseTx.type = 2;
|
|
32
|
-
}
|
|
33
|
-
return baseTx;
|
|
34
|
-
};
|
|
35
4
|
const checkError = (error) => {
|
|
36
5
|
if (error.statusText === "INS_NOT_SUPPORTED") error.message = "Device is not supported. Make sure the Ethereum app is open on the device.";
|
|
37
6
|
if (error.statusText === "UNKNOWN_ERROR") error.message = "Unknown error. Make sure the device is connected and the Ethereum app is open on the device.";
|
|
@@ -43,4 +12,4 @@ const clearLedgerDerivationPath = () => {
|
|
|
43
12
|
};
|
|
44
13
|
|
|
45
14
|
//#endregion
|
|
46
|
-
export { checkError, clearLedgerDerivationPath
|
|
15
|
+
export { checkError, clearLedgerDerivationPath };
|
package/dist/hid/provider.d.ts
CHANGED
|
@@ -1,21 +1,41 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type Eth from '@ledgerhq/hw-app-eth';
|
|
2
2
|
import type TransportWebHID from '@ledgerhq/hw-transport-webhid';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import { type Address, type Chain, type LocalAccount } from 'viem';
|
|
4
|
+
type RequestArguments = {
|
|
5
|
+
method: string;
|
|
6
|
+
params?: unknown[];
|
|
7
|
+
};
|
|
8
|
+
type ProviderEvent = 'disconnect';
|
|
9
|
+
type Listener = () => void;
|
|
10
|
+
export declare class LedgerHQProvider {
|
|
11
|
+
readonly chain: Chain;
|
|
6
12
|
device?: HIDDevice;
|
|
7
13
|
transport?: typeof TransportWebHID;
|
|
8
|
-
|
|
14
|
+
private readonly rpcUrl?;
|
|
15
|
+
private account?;
|
|
16
|
+
private accountPath?;
|
|
17
|
+
private publicClient?;
|
|
18
|
+
private walletClient?;
|
|
19
|
+
private listeners;
|
|
20
|
+
constructor({ chain, rpcUrl }: {
|
|
21
|
+
chain: Chain;
|
|
22
|
+
rpcUrl?: string;
|
|
23
|
+
});
|
|
24
|
+
on(event: ProviderEvent, listener: Listener): void;
|
|
25
|
+
removeListener(event: ProviderEvent, listener: Listener): void;
|
|
26
|
+
emit(event: ProviderEvent): void;
|
|
27
|
+
get derivationPath(): string;
|
|
9
28
|
loadTransport(): Promise<void>;
|
|
10
|
-
getSigner(): LedgerHQSigner;
|
|
11
|
-
listAccounts(): Promise<Array<string>>;
|
|
12
|
-
detectNetwork(): Promise<Network>;
|
|
13
29
|
getTransport(): Promise<TransportWebHID>;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
withEthApp<T>(callback: (eth: Eth) => T | Promise<T>): Promise<T>;
|
|
31
|
+
enable(): Promise<Address>;
|
|
32
|
+
resetAccount(): void;
|
|
33
|
+
getAccount(): Promise<LocalAccount>;
|
|
34
|
+
getAddress(): Promise<Address>;
|
|
35
|
+
private getPublicClient;
|
|
36
|
+
private getWalletClient;
|
|
37
|
+
private sendTransaction;
|
|
38
|
+
request({ method, params }: RequestArguments): Promise<unknown>;
|
|
20
39
|
}
|
|
40
|
+
export {};
|
|
21
41
|
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/hid/provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/hid/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,sBAAsB,CAAC;AAC5C,OAAO,KAAK,eAAe,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAWL,KAAK,OAAO,EACZ,KAAK,KAAK,EAEV,KAAK,YAAY,EAIlB,MAAM,MAAM,CAAC;AA0Bd,KAAK,gBAAgB,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB,CAAC;AAEF,KAAK,aAAa,GAAG,YAAY,CAAC;AAClC,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAC;AAE3B,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAEf,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB,SAAS,CAAC,EAAE,OAAO,eAAe,CAAC;IAE1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IAEjC,OAAO,CAAC,OAAO,CAAC,CAAe;IAE/B,OAAO,CAAC,WAAW,CAAC,CAAS;IAE7B,OAAO,CAAC,YAAY,CAAC,CAAe;IAEpC,OAAO,CAAC,YAAY,CAAC,CAAe;IAEpC,OAAO,CAAC,SAAS,CAAqD;gBAE1D,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAehE,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ;IAI3C,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ;IAIvD,IAAI,CAAC,KAAK,EAAE,aAAa;IAMzB,IAAI,cAAc,WAQjB;IAEK,aAAa;IASb,YAAY,IAAI,OAAO,CAAC,eAAe,CAAC;IAc9C,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAoB3D,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAyBhC,YAAY;IAMN,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC;IAiBnC,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAOpC,OAAO,CAAC,eAAe;YAQT,eAAe;YAUf,eAAe;IAuEvB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAW,EAAE,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CA2C3E"}
|
package/dist/hid/provider.js
CHANGED
|
@@ -1,14 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import invariant from "tiny-invariant";
|
|
1
|
+
import { LS_KEY_DERIVATION_PATH } from "./constants.js";
|
|
2
|
+
import { checkError } from "./helpers.js";
|
|
3
|
+
import { createLedgerAccount } from "./account.js";
|
|
4
|
+
import { createPublicClient, createWalletClient, getAddress, hexToBigInt, hexToNumber, http, isAddress, isAddressEqual, isHex, numberToHex } from "viem";
|
|
6
5
|
|
|
7
6
|
//#region src/hid/provider.ts
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const NOOP = () => {};
|
|
8
|
+
const DEFAULT_DERIVATION_PATH = "m/44'/60'/0'/0/0";
|
|
9
|
+
const TX_TYPES = {
|
|
10
|
+
"0x0": "legacy",
|
|
11
|
+
"0x1": "eip2930",
|
|
12
|
+
"0x2": "eip1559"
|
|
13
|
+
};
|
|
14
|
+
let deviceSessionLock = Promise.resolve();
|
|
15
|
+
const withDeviceSession = (fn) => {
|
|
16
|
+
const result = deviceSessionLock.then(fn);
|
|
17
|
+
deviceSessionLock = result.then(NOOP, NOOP);
|
|
18
|
+
return result;
|
|
19
|
+
};
|
|
20
|
+
var LedgerHQProvider = class {
|
|
21
|
+
constructor({ chain, rpcUrl }) {
|
|
22
|
+
this.listeners = {};
|
|
23
|
+
this.chain = chain;
|
|
24
|
+
this.rpcUrl = rpcUrl;
|
|
25
|
+
if (!rpcUrl) console.warn(`[reef-knot] No RPC URL configured for chain ${chain.id} (${chain.name}), falling back to its default public RPC endpoint`);
|
|
26
|
+
}
|
|
27
|
+
on(event, listener) {
|
|
28
|
+
var _this$listeners;
|
|
29
|
+
((_this$listeners = this.listeners)[event] ?? (_this$listeners[event] = /* @__PURE__ */ new Set())).add(listener);
|
|
30
|
+
}
|
|
31
|
+
removeListener(event, listener) {
|
|
32
|
+
this.listeners[event]?.delete(listener);
|
|
33
|
+
}
|
|
34
|
+
emit(event) {
|
|
35
|
+
this.listeners[event]?.forEach((listener) => listener());
|
|
36
|
+
}
|
|
37
|
+
get derivationPath() {
|
|
38
|
+
if (typeof window !== "undefined") return window.localStorage.getItem(LS_KEY_DERIVATION_PATH) || DEFAULT_DERIVATION_PATH;
|
|
39
|
+
return DEFAULT_DERIVATION_PATH;
|
|
12
40
|
}
|
|
13
41
|
async loadTransport() {
|
|
14
42
|
if (!this.transport) {
|
|
@@ -16,15 +44,6 @@ var LedgerHQProvider = class extends JsonRpcBatchProvider {
|
|
|
16
44
|
this.transport = TransportWebHID;
|
|
17
45
|
}
|
|
18
46
|
}
|
|
19
|
-
getSigner() {
|
|
20
|
-
return new LedgerHQSigner(this);
|
|
21
|
-
}
|
|
22
|
-
listAccounts() {
|
|
23
|
-
throw new Error("method is not implemented");
|
|
24
|
-
}
|
|
25
|
-
detectNetwork() {
|
|
26
|
-
return Promise.resolve(this._network);
|
|
27
|
-
}
|
|
28
47
|
async getTransport() {
|
|
29
48
|
await this.loadTransport();
|
|
30
49
|
try {
|
|
@@ -35,6 +54,21 @@ var LedgerHQProvider = class extends JsonRpcBatchProvider {
|
|
|
35
54
|
return checkError(error);
|
|
36
55
|
}
|
|
37
56
|
}
|
|
57
|
+
withEthApp(callback) {
|
|
58
|
+
return withDeviceSession(async () => {
|
|
59
|
+
const transport = await this.getTransport();
|
|
60
|
+
try {
|
|
61
|
+
const { default: Eth } = await import("@ledgerhq/hw-app-eth");
|
|
62
|
+
const eth = new Eth(transport);
|
|
63
|
+
await eth.getAppConfiguration();
|
|
64
|
+
return await callback(eth);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return checkError(error);
|
|
67
|
+
} finally {
|
|
68
|
+
await transport.close();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
38
72
|
async enable() {
|
|
39
73
|
try {
|
|
40
74
|
await this.loadTransport();
|
|
@@ -46,49 +80,113 @@ var LedgerHQProvider = class extends JsonRpcBatchProvider {
|
|
|
46
80
|
}
|
|
47
81
|
};
|
|
48
82
|
hid.addEventListener("disconnect", onDisconnect);
|
|
49
|
-
|
|
83
|
+
this.resetAccount();
|
|
50
84
|
return await this.getAddress();
|
|
51
85
|
} catch (error) {
|
|
52
86
|
return checkError(error);
|
|
53
87
|
}
|
|
54
88
|
}
|
|
89
|
+
resetAccount() {
|
|
90
|
+
this.account = void 0;
|
|
91
|
+
this.accountPath = void 0;
|
|
92
|
+
this.walletClient = void 0;
|
|
93
|
+
}
|
|
94
|
+
async getAccount() {
|
|
95
|
+
const path = this.derivationPath;
|
|
96
|
+
if (!this.account || this.accountPath !== path) {
|
|
97
|
+
const { address } = await this.withEthApp((eth) => eth.getAddress(path));
|
|
98
|
+
this.account = createLedgerAccount(getAddress(address), path, (cb) => this.withEthApp(cb));
|
|
99
|
+
this.accountPath = path;
|
|
100
|
+
this.walletClient = void 0;
|
|
101
|
+
}
|
|
102
|
+
return this.account;
|
|
103
|
+
}
|
|
55
104
|
async getAddress() {
|
|
56
|
-
|
|
57
|
-
return
|
|
105
|
+
const { address } = await this.getAccount();
|
|
106
|
+
return address;
|
|
107
|
+
}
|
|
108
|
+
getPublicClient() {
|
|
109
|
+
this.publicClient ?? (this.publicClient = createPublicClient({
|
|
110
|
+
chain: this.chain,
|
|
111
|
+
transport: http(this.rpcUrl, { batch: true })
|
|
112
|
+
}));
|
|
113
|
+
return this.publicClient;
|
|
58
114
|
}
|
|
59
|
-
async
|
|
60
|
-
|
|
115
|
+
async getWalletClient() {
|
|
116
|
+
const account = await this.getAccount();
|
|
117
|
+
this.walletClient ?? (this.walletClient = createWalletClient({
|
|
118
|
+
account,
|
|
119
|
+
chain: this.chain,
|
|
120
|
+
transport: http(this.rpcUrl, { batch: true })
|
|
121
|
+
}));
|
|
122
|
+
return this.walletClient;
|
|
123
|
+
}
|
|
124
|
+
async sendTransaction(transaction) {
|
|
125
|
+
const walletClient = await this.getWalletClient();
|
|
126
|
+
const account = walletClient.account;
|
|
127
|
+
if (transaction.from && (!isAddress(transaction.from) || !isAddressEqual(transaction.from, account.address))) throw new Error("from address mismatch");
|
|
128
|
+
const type = transaction.type ? TX_TYPES[transaction.type] : void 0;
|
|
129
|
+
const request = {
|
|
130
|
+
account,
|
|
131
|
+
chain: this.chain,
|
|
132
|
+
to: transaction.to ?? void 0,
|
|
133
|
+
data: transaction.data,
|
|
134
|
+
value: transaction.value ? hexToBigInt(transaction.value) : void 0,
|
|
135
|
+
gas: transaction.gas ? hexToBigInt(transaction.gas) : void 0,
|
|
136
|
+
nonce: transaction.nonce != null ? hexToNumber(transaction.nonce) : void 0
|
|
137
|
+
};
|
|
138
|
+
const accessList = transaction.accessList;
|
|
139
|
+
const gasPrice = transaction.gasPrice ? hexToBigInt(transaction.gasPrice) : void 0;
|
|
140
|
+
if (type === "legacy") return walletClient.sendTransaction({
|
|
141
|
+
...request,
|
|
142
|
+
type: "legacy",
|
|
143
|
+
gasPrice
|
|
144
|
+
});
|
|
145
|
+
if (type === "eip2930") return walletClient.sendTransaction({
|
|
146
|
+
...request,
|
|
147
|
+
type: "eip2930",
|
|
148
|
+
gasPrice,
|
|
149
|
+
accessList
|
|
150
|
+
});
|
|
151
|
+
if (!type && gasPrice) return walletClient.sendTransaction({
|
|
152
|
+
...request,
|
|
153
|
+
gasPrice,
|
|
154
|
+
accessList
|
|
155
|
+
});
|
|
156
|
+
return walletClient.sendTransaction({
|
|
157
|
+
...request,
|
|
158
|
+
type,
|
|
159
|
+
accessList,
|
|
160
|
+
maxFeePerGas: transaction.maxFeePerGas ? hexToBigInt(transaction.maxFeePerGas) : void 0,
|
|
161
|
+
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? hexToBigInt(transaction.maxPriorityFeePerGas) : void 0
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async request({ method, params = [] }) {
|
|
61
165
|
switch (method) {
|
|
62
|
-
case "
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return this.send("eth_sendRawTransaction", [signedTx]);
|
|
67
|
-
}
|
|
68
|
-
case "eth_accounts": return [await this.getAddress()];
|
|
69
|
-
case "eth_signTypedData_v4": {
|
|
70
|
-
if (typeof params[1] !== "string") throw new Error("eth_signTypedData_v4 arg 1 is not a string");
|
|
71
|
-
const payload = JSON.parse(params[1]);
|
|
72
|
-
return await this.signer.__signEIP712Message({
|
|
73
|
-
domain: payload.domain,
|
|
74
|
-
types: payload.types,
|
|
75
|
-
primaryType: payload.primaryType,
|
|
76
|
-
message: payload.message
|
|
77
|
-
});
|
|
78
|
-
}
|
|
166
|
+
case "eth_chainId": return numberToHex(this.chain.id);
|
|
167
|
+
case "eth_accounts":
|
|
168
|
+
case "eth_requestAccounts": return [await this.getAddress()];
|
|
169
|
+
case "eth_sendTransaction": return this.sendTransaction(params[0]);
|
|
79
170
|
case "personal_sign": {
|
|
80
171
|
const messageHex = params[0];
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
return await this.signer.signMessage(messageBytes);
|
|
172
|
+
if (!isHex(messageHex)) throw new Error("personal_sign message must be a hex string");
|
|
173
|
+
return (await this.getAccount()).signMessage({ message: { raw: messageHex } });
|
|
84
174
|
}
|
|
85
175
|
case "eth_sign": {
|
|
86
176
|
const messageHex = params[1];
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
177
|
+
if (!isHex(messageHex)) throw new Error("eth_sign message must be a hex string");
|
|
178
|
+
return (await this.getAccount()).signMessage({ message: { raw: messageHex } });
|
|
179
|
+
}
|
|
180
|
+
case "eth_signTypedData_v4":
|
|
181
|
+
if (typeof params[1] !== "string") throw new Error("eth_signTypedData_v4 arg 1 is not a string");
|
|
182
|
+
return (await this.getAccount()).signTypedData(JSON.parse(params[1]));
|
|
183
|
+
default: {
|
|
184
|
+
const rpcRequest = this.getPublicClient().request;
|
|
185
|
+
return rpcRequest({
|
|
186
|
+
method,
|
|
187
|
+
params
|
|
188
|
+
});
|
|
90
189
|
}
|
|
91
|
-
default: return this.send(method, params);
|
|
92
190
|
}
|
|
93
191
|
}
|
|
94
192
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../src/iframe/connector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../src/iframe/connector.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,YAAY,eAAe,CAAC;AACzC,eAAO,MAAM,IAAI,gBAAgB,CAAC;AAElC,KAAK,uBAAuB,GAAG;IAC7B,OAAO,CAAC,EAAE,6BAA6B,CAAC;IACxC,YAAY,EAAE,KAAK,CAAC;CACrB,CAAC;AAGF,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,YAAY,GACb,EAAE,uBAAuB,6GA0IzB;yBA7Ie,mBAAmB"}
|
package/dist/iframe/connector.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { SwitchChainNotSupportedError, createConnector } from "wagmi";
|
|
2
|
-
import { ResourceUnavailableRpcError, UserRejectedRequestError } from "viem";
|
|
3
|
-
import { getAddress } from "@ethersproject/address";
|
|
4
|
-
import { hexValue } from "@ethersproject/bytes";
|
|
5
|
-
import { Web3Provider } from "@ethersproject/providers";
|
|
2
|
+
import { ResourceUnavailableRpcError, UserRejectedRequestError, getAddress, numberToHex } from "viem";
|
|
6
3
|
|
|
7
4
|
//#region src/iframe/connector.ts
|
|
8
5
|
const idLedgerLive = "ledgerLive";
|
|
@@ -48,7 +45,7 @@ function ledgerLiveConnector({ options, defaultChain }) {
|
|
|
48
45
|
},
|
|
49
46
|
async switchChain({ chainId }) {
|
|
50
47
|
const provider = await this.getProvider();
|
|
51
|
-
const id =
|
|
48
|
+
const id = numberToHex(chainId);
|
|
52
49
|
try {
|
|
53
50
|
await provider.send("wallet_switchEthereumChain", [{ chainId: id }]);
|
|
54
51
|
return chains.find((x) => x.id === chainId) ?? {
|
|
@@ -72,16 +69,12 @@ function ledgerLiveConnector({ options, defaultChain }) {
|
|
|
72
69
|
}
|
|
73
70
|
},
|
|
74
71
|
async getAccounts() {
|
|
75
|
-
return (await (await this.getProvider()).send("eth_requestAccounts")).map(getAddress);
|
|
72
|
+
return (await (await this.getProvider()).send("eth_requestAccounts")).map((account) => getAddress(account));
|
|
76
73
|
},
|
|
77
74
|
async getChainId() {
|
|
78
75
|
const chainId = await (await this.getProvider()).send("eth_chainId");
|
|
79
76
|
return Number(chainId);
|
|
80
77
|
},
|
|
81
|
-
async getSigner() {
|
|
82
|
-
const [provider, accounts] = await Promise.all([this.getProvider(), this.getAccounts()]);
|
|
83
|
-
return new Web3Provider(provider).getSigner(accounts[0]);
|
|
84
|
-
},
|
|
85
78
|
async isAuthorized() {
|
|
86
79
|
try {
|
|
87
80
|
return !!(await (await this.getProvider()).send("eth_accounts"))[0];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reef-knot/ledger-connector",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0-alpha.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -45,22 +45,10 @@
|
|
|
45
45
|
"wagmi": ">=3.6"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@
|
|
49
|
-
"@
|
|
50
|
-
"@
|
|
51
|
-
"@
|
|
52
|
-
"@ethersproject/hash": "^5.7.0",
|
|
53
|
-
"@ethersproject/properties": "^5.7.0",
|
|
54
|
-
"@ethersproject/providers": "^5.7.2",
|
|
55
|
-
"@ethersproject/strings": "^5.7.0",
|
|
56
|
-
"@ethersproject/transactions": "^5.7.0",
|
|
57
|
-
"@ledgerhq/hw-app-eth": "^6.37.1",
|
|
58
|
-
"@ledgerhq/hw-transport": "^6.31.0",
|
|
59
|
-
"@ledgerhq/hw-transport-webhid": "^6.29.0",
|
|
60
|
-
"@ledgerhq/iframe-provider": "^0.4.3",
|
|
61
|
-
"@web3-react/abstract-connector": "^6.0.7",
|
|
62
|
-
"@web3-react/types": "^6.0.7",
|
|
63
|
-
"tiny-invariant": "^1.2.0"
|
|
48
|
+
"@ledgerhq/hw-app-eth": "7.8.12",
|
|
49
|
+
"@ledgerhq/hw-transport": "6.35.7",
|
|
50
|
+
"@ledgerhq/hw-transport-webhid": "6.36.0",
|
|
51
|
+
"@ledgerhq/iframe-provider": "^0.4.3"
|
|
64
52
|
},
|
|
65
53
|
"peerDependencies": {
|
|
66
54
|
"@tanstack/react-query": "^5.29.0",
|
package/dist/hid/signer.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type Eth from '@ledgerhq/hw-app-eth';
|
|
2
|
-
import { LoadConfig, ResolutionConfig } from '@ledgerhq/hw-app-eth/lib/services/types';
|
|
3
|
-
import { EIP712Message } from '@ledgerhq/types-live';
|
|
4
|
-
import { JsonRpcSigner, TransactionRequest } from '@ethersproject/providers';
|
|
5
|
-
import { Signer, TypedDataDomain, TypedDataField, TypedDataSigner } from '@ethersproject/abstract-signer';
|
|
6
|
-
import { UnsignedTransaction } from '@ethersproject/transactions';
|
|
7
|
-
import { Bytes } from '@ethersproject/bytes';
|
|
8
|
-
import type { LedgerHQProvider } from './provider';
|
|
9
|
-
import type { UnsignedTransactionStrict } from './types';
|
|
10
|
-
export declare class LedgerHQSigner extends Signer implements TypedDataSigner {
|
|
11
|
-
readonly provider: LedgerHQProvider;
|
|
12
|
-
get path(): string;
|
|
13
|
-
_index: number;
|
|
14
|
-
_address: string;
|
|
15
|
-
constructor(provider: LedgerHQProvider);
|
|
16
|
-
withEthApp<T>(callback: (eth: Eth) => T): Promise<T>;
|
|
17
|
-
getAddress(): Promise<string>;
|
|
18
|
-
signMessage(message: Bytes | string): Promise<string>;
|
|
19
|
-
populateUnsigned(transaction: UnsignedTransactionStrict): Promise<UnsignedTransaction>;
|
|
20
|
-
signTransaction(transaction: TransactionRequest, loadConfig?: LoadConfig, resolutionConfig?: ResolutionConfig): Promise<string>;
|
|
21
|
-
connect(provider: LedgerHQProvider): JsonRpcSigner;
|
|
22
|
-
connectUnchecked(): JsonRpcSigner;
|
|
23
|
-
sendUncheckedTransaction(): Promise<string>;
|
|
24
|
-
unlock(): Promise<boolean>;
|
|
25
|
-
_legacySignMessage(_message: Bytes | string): Promise<string>;
|
|
26
|
-
_signTypedData(domain: TypedDataDomain, _types: Record<string, Array<TypedDataField>>, value: Record<string, any>): Promise<string>;
|
|
27
|
-
__signEIP712Message(data: EIP712Message): Promise<string>;
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=signer.d.ts.map
|
package/dist/hid/signer.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../../src/hid/signer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EACL,UAAU,EACV,gBAAgB,EACjB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAsB,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE7E,OAAO,EACL,MAAM,EACN,eAAe,EACf,cAAc,EACd,eAAe,EAChB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAa,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAE7E,OAAO,EAAE,KAAK,EAA0B,MAAM,sBAAsB,CAAC;AAMrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAIzD,qBAAa,cAAe,SAAQ,MAAO,YAAW,eAAe;IACnE,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAEpC,IAAI,IAAI,WAKP;IAGD,MAAM,SAAK;IACX,QAAQ,SAAM;gBAEF,QAAQ,EAAE,gBAAgB;IAKhC,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAiBpD,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAM7B,WAAW,CAAC,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiBrD,gBAAgB,CACpB,WAAW,EAAE,yBAAyB,GACrC,OAAO,CAAC,mBAAmB,CAAC;IAczB,eAAe,CACnB,WAAW,EAAE,kBAAkB,EAC/B,UAAU,GAAE,UAAe,EAC3B,gBAAgB,GAAE,gBAAqB,GACtC,OAAO,CAAC,MAAM,CAAC;IAuBlB,OAAO,CAAC,QAAQ,EAAE,gBAAgB,GAAG,aAAa;IAKlD,gBAAgB,IAAI,aAAa;IAKjC,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC;IAKrC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAK1B,kBAAkB,CAAC,QAAQ,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK7D,cAAc,CAClB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,EAC7C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,OAAO,CAAC,MAAM,CAAC;IA8BZ,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;CAOhE"}
|
package/dist/hid/signer.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { LS_KEY_DERIVATION_PATH } from "./constants.js";
|
|
2
|
-
import { checkError, convertToUnsigned, toNumber } from "./helpers.js";
|
|
3
|
-
import { hexlify, joinSignature } from "@ethersproject/bytes";
|
|
4
|
-
import { BigNumber } from "@ethersproject/bignumber";
|
|
5
|
-
import { Signer } from "@ethersproject/abstract-signer";
|
|
6
|
-
import { serialize } from "@ethersproject/transactions";
|
|
7
|
-
import { toUtf8Bytes } from "@ethersproject/strings";
|
|
8
|
-
import { _TypedDataEncoder } from "@ethersproject/hash";
|
|
9
|
-
|
|
10
|
-
//#region src/hid/signer.ts
|
|
11
|
-
const defaultPath = "m/44'/60'/0'/0/0";
|
|
12
|
-
var LedgerHQSigner = class LedgerHQSigner extends Signer {
|
|
13
|
-
get path() {
|
|
14
|
-
if (typeof window !== "undefined") return window.localStorage.getItem(LS_KEY_DERIVATION_PATH) || defaultPath;
|
|
15
|
-
return defaultPath;
|
|
16
|
-
}
|
|
17
|
-
constructor(provider) {
|
|
18
|
-
super();
|
|
19
|
-
this._index = 0;
|
|
20
|
-
this._address = "";
|
|
21
|
-
this.provider = provider;
|
|
22
|
-
}
|
|
23
|
-
async withEthApp(callback) {
|
|
24
|
-
const transport = await this.provider.getTransport();
|
|
25
|
-
try {
|
|
26
|
-
const { default: Eth } = await import("@ledgerhq/hw-app-eth");
|
|
27
|
-
const eth = new Eth(transport);
|
|
28
|
-
await eth.getAppConfiguration();
|
|
29
|
-
return await callback(eth);
|
|
30
|
-
} catch (error) {
|
|
31
|
-
return checkError(error);
|
|
32
|
-
} finally {
|
|
33
|
-
await transport.close();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
async getAddress() {
|
|
37
|
-
const account = await this.withEthApp((eth) => eth.getAddress(this.path));
|
|
38
|
-
this._address = this.provider.formatter.address(account.address);
|
|
39
|
-
return this._address;
|
|
40
|
-
}
|
|
41
|
-
async signMessage(message) {
|
|
42
|
-
if (typeof message === "string") message = toUtf8Bytes(message);
|
|
43
|
-
const messageHex = hexlify(message).substring(2);
|
|
44
|
-
const sig = await this.withEthApp((eth) => eth.signPersonalMessage(this.path, messageHex));
|
|
45
|
-
sig.r = `0x${sig.r}`;
|
|
46
|
-
sig.s = `0x${sig.s}`;
|
|
47
|
-
return joinSignature(sig);
|
|
48
|
-
}
|
|
49
|
-
async populateUnsigned(transaction) {
|
|
50
|
-
const populated = await this.populateTransaction(transaction);
|
|
51
|
-
const nonce = toNumber(populated.nonce);
|
|
52
|
-
if (populated.type === 0) {
|
|
53
|
-
const { gasLimit, type, chainId, gasPrice, value, data, to } = populated;
|
|
54
|
-
return {
|
|
55
|
-
gasLimit,
|
|
56
|
-
type,
|
|
57
|
-
chainId,
|
|
58
|
-
gasPrice,
|
|
59
|
-
nonce,
|
|
60
|
-
value,
|
|
61
|
-
data,
|
|
62
|
-
to
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
...populated,
|
|
67
|
-
nonce
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
async signTransaction(transaction, loadConfig = {}, resolutionConfig = {}) {
|
|
71
|
-
const unsignedTx = await convertToUnsigned(transaction);
|
|
72
|
-
const populatedTx = await this.populateUnsigned(unsignedTx);
|
|
73
|
-
const serializedTx = serialize(populatedTx).substring(2);
|
|
74
|
-
const { ledgerService } = await import("@ledgerhq/hw-app-eth");
|
|
75
|
-
const resolution = await ledgerService.resolveTransaction(serializedTx, loadConfig, resolutionConfig);
|
|
76
|
-
const sig = await this.withEthApp((eth) => eth.signTransaction(this.path, serializedTx, resolution));
|
|
77
|
-
return serialize(populatedTx, {
|
|
78
|
-
v: BigNumber.from(`0x${sig.v}`).toNumber(),
|
|
79
|
-
r: `0x${sig.r}`,
|
|
80
|
-
s: `0x${sig.s}`
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
connect(provider) {
|
|
84
|
-
return new LedgerHQSigner(provider);
|
|
85
|
-
}
|
|
86
|
-
connectUnchecked() {
|
|
87
|
-
throw new Error("method is not implemented");
|
|
88
|
-
}
|
|
89
|
-
sendUncheckedTransaction() {
|
|
90
|
-
throw new Error("method is not implemented");
|
|
91
|
-
}
|
|
92
|
-
async unlock() {
|
|
93
|
-
throw new Error("method is not implemented");
|
|
94
|
-
}
|
|
95
|
-
async _legacySignMessage(_message) {
|
|
96
|
-
throw new Error("method is not implemented");
|
|
97
|
-
}
|
|
98
|
-
async _signTypedData(domain, _types, value) {
|
|
99
|
-
const types = { ..._types };
|
|
100
|
-
delete types.EIP712Domain;
|
|
101
|
-
const encoder = new _TypedDataEncoder(types);
|
|
102
|
-
const data = {
|
|
103
|
-
domain: {
|
|
104
|
-
name: domain.name,
|
|
105
|
-
verifyingContract: domain.verifyingContract,
|
|
106
|
-
version: domain.version,
|
|
107
|
-
chainId: domain.chainId ? parseInt(domain.chainId.toString()) : void 0
|
|
108
|
-
},
|
|
109
|
-
types: {
|
|
110
|
-
...types,
|
|
111
|
-
EIP712Domain: [
|
|
112
|
-
{
|
|
113
|
-
name: "name",
|
|
114
|
-
type: "string"
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
name: "version",
|
|
118
|
-
type: "string"
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: "chainId",
|
|
122
|
-
type: "uint256"
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: "verifyingContract",
|
|
126
|
-
type: "address"
|
|
127
|
-
}
|
|
128
|
-
]
|
|
129
|
-
},
|
|
130
|
-
primaryType: encoder.primaryType,
|
|
131
|
-
message: value
|
|
132
|
-
};
|
|
133
|
-
return this.__signEIP712Message(data);
|
|
134
|
-
}
|
|
135
|
-
async __signEIP712Message(data) {
|
|
136
|
-
const { r, s, v } = await this.withEthApp((eth) => eth.signEIP712Message(this.path, data));
|
|
137
|
-
return joinSignature({
|
|
138
|
-
r: `0x${r}`,
|
|
139
|
-
s: `0x${s}`,
|
|
140
|
-
v
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
//#endregion
|
|
146
|
-
export { LedgerHQSigner };
|
package/dist/hid/types.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { BigNumberish } from '@ethersproject/bignumber';
|
|
2
|
-
import { TransactionRequest } from '@ethersproject/providers';
|
|
3
|
-
import { UnsignedTransaction } from '@ethersproject/transactions';
|
|
4
|
-
export type UnsignedTransactionStrict = Omit<UnsignedTransaction, 'type'> & {
|
|
5
|
-
type?: number;
|
|
6
|
-
};
|
|
7
|
-
export type TransactionRequestExtended = TransactionRequest & {
|
|
8
|
-
gas?: BigNumberish;
|
|
9
|
-
};
|
|
10
|
-
//# sourceMappingURL=types.d.ts.map
|
package/dist/hid/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hid/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,GAAG;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,kBAAkB,GAAG;IAC5D,GAAG,CAAC,EAAE,YAAY,CAAC;CACpB,CAAC"}
|