@reef-knot/ledger-connector 4.4.0-alpha.3 → 4.4.0-alpha.4
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/connector.d.ts +1 -2
- package/dist/hid/connector.d.ts.map +1 -1
- package/dist/hid/connector.js +76 -93
- package/dist/hid/helpers.js +5 -6
- package/dist/hid/provider.js +80 -92
- package/dist/hid/signer.js +119 -134
- package/dist/iframe/connector.d.ts +1 -2
- package/dist/iframe/connector.d.ts.map +1 -1
- package/dist/iframe/connector.js +99 -118
- package/package.json +5 -5
- package/dist/_virtual/_tslib.js +0 -33
package/dist/hid/connector.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { Chain } from 'wagmi/chains';
|
|
2
|
-
import type { LedgerHQProvider } from './provider';
|
|
3
2
|
export declare const idLedgerHid = "ledgerHID";
|
|
4
3
|
export declare const name = "Ledger";
|
|
5
4
|
export declare function ledgerHIDConnector({ rpc, defaultChain, }: {
|
|
6
5
|
rpc: Record<number, string>;
|
|
7
6
|
defaultChain: Chain;
|
|
8
|
-
}): import("wagmi").CreateConnectorFn<
|
|
7
|
+
}): import("wagmi").CreateConnectorFn<provider, properties, storageItem>;
|
|
9
8
|
export declare namespace ledgerHIDConnector {
|
|
10
9
|
var type: "ledgerHID";
|
|
11
10
|
}
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../src/hid/connector.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAGrC,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,wEAwGA;yBA9Ge,kBAAkB"}
|
package/dist/hid/connector.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { __awaiter } from '../_virtual/_tslib.js';
|
|
2
1
|
import { createConnector, ChainNotConfiguredError, ConnectorNotFoundError } from 'wagmi';
|
|
3
2
|
import { checkError, clearLedgerDerivationPath } from './helpers.js';
|
|
4
3
|
|
|
@@ -17,106 +16,90 @@ function ledgerHIDConnector({
|
|
|
17
16
|
id: idLedgerHid,
|
|
18
17
|
name,
|
|
19
18
|
type: ledgerHIDConnector.type,
|
|
20
|
-
getProvider(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
return providers[chain.id];
|
|
35
|
-
});
|
|
19
|
+
async getProvider({
|
|
20
|
+
chainId
|
|
21
|
+
} = {}) {
|
|
22
|
+
const chain = chains.find(x => x.id === chainId) ?? defaultChain;
|
|
23
|
+
if (!providers[chain.id]) {
|
|
24
|
+
const {
|
|
25
|
+
LedgerHQProvider
|
|
26
|
+
} = await import('./provider.js');
|
|
27
|
+
providers[chain.id] = new LedgerHQProvider({
|
|
28
|
+
url: rpc?.[chain.id]
|
|
29
|
+
}, chain.id);
|
|
30
|
+
}
|
|
31
|
+
return providers[chain.id];
|
|
36
32
|
},
|
|
37
|
-
connect() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
});
|
|
33
|
+
async connect() {
|
|
34
|
+
try {
|
|
35
|
+
const provider = await this.getProvider();
|
|
36
|
+
provider.on('disconnect', this.onDisconnect);
|
|
37
|
+
const account = await provider.enable();
|
|
38
|
+
const chainId = await this.getChainId();
|
|
39
|
+
return {
|
|
40
|
+
accounts: [account],
|
|
41
|
+
chainId
|
|
42
|
+
};
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return checkError(error);
|
|
45
|
+
}
|
|
52
46
|
},
|
|
53
|
-
disconnect() {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
clearLedgerDerivationPath();
|
|
59
|
-
});
|
|
47
|
+
async disconnect() {
|
|
48
|
+
// Handles programmatic disconnect.
|
|
49
|
+
const provider = await this.getProvider();
|
|
50
|
+
provider.removeListener('disconnect', this.onDisconnect);
|
|
51
|
+
clearLedgerDerivationPath();
|
|
60
52
|
},
|
|
61
|
-
getAccounts() {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return [address];
|
|
66
|
-
});
|
|
53
|
+
async getAccounts() {
|
|
54
|
+
const provider = await this.getProvider();
|
|
55
|
+
const address = await provider.getAddress();
|
|
56
|
+
return [address];
|
|
67
57
|
},
|
|
68
|
-
getChainId() {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
throw new ChainNotConfiguredError();
|
|
76
|
-
});
|
|
58
|
+
async getChainId() {
|
|
59
|
+
const provider = await this.getProvider();
|
|
60
|
+
const {
|
|
61
|
+
chainId
|
|
62
|
+
} = await provider.getNetwork();
|
|
63
|
+
if (chainId) return chainId;
|
|
64
|
+
throw new ChainNotConfiguredError();
|
|
77
65
|
},
|
|
78
|
-
isAuthorized() {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
});
|
|
66
|
+
async isAuthorized() {
|
|
67
|
+
try {
|
|
68
|
+
const provider = await this.getProvider();
|
|
69
|
+
if (!provider) throw new ConnectorNotFoundError();
|
|
70
|
+
const [account] = await this.getAccounts();
|
|
71
|
+
return !!account;
|
|
72
|
+
} catch (e) {
|
|
73
|
+
// The errors caught here are generally expected in most use cases.
|
|
74
|
+
// However, unexpected errors may still occur, so they should at least be logged to the console.
|
|
75
|
+
console.error(e);
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
92
78
|
},
|
|
93
|
-
switchChain(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
79
|
+
async switchChain({
|
|
80
|
+
chainId
|
|
81
|
+
}) {
|
|
82
|
+
const id = chainId.toString(16);
|
|
83
|
+
emitter.emit('change', {
|
|
84
|
+
chainId: Number(chainId)
|
|
85
|
+
});
|
|
86
|
+
return Promise.resolve(chains.find(x => x.id === chainId) ?? {
|
|
87
|
+
id: chainId,
|
|
88
|
+
name: `Chain ${id}`,
|
|
89
|
+
network: `${id}`,
|
|
90
|
+
nativeCurrency: {
|
|
91
|
+
decimals: 18,
|
|
92
|
+
name: 'Ether',
|
|
93
|
+
symbol: 'ETH'
|
|
94
|
+
},
|
|
95
|
+
rpcUrls: {
|
|
96
|
+
default: {
|
|
97
|
+
http: ['']
|
|
110
98
|
},
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
http: ['']
|
|
114
|
-
},
|
|
115
|
-
public: {
|
|
116
|
-
http: ['']
|
|
117
|
-
}
|
|
99
|
+
public: {
|
|
100
|
+
http: ['']
|
|
118
101
|
}
|
|
119
|
-
}
|
|
102
|
+
}
|
|
120
103
|
});
|
|
121
104
|
},
|
|
122
105
|
onDisconnect() {
|
package/dist/hid/helpers.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { __awaiter } from '../_virtual/_tslib.js';
|
|
2
1
|
import { BigNumber } from '@ethersproject/bignumber';
|
|
3
2
|
import { resolveProperties } from '@ethersproject/properties';
|
|
4
3
|
import { LS_KEY_DERIVATION_PATH } from './constants.js';
|
|
@@ -9,8 +8,8 @@ const hasEIP1559 = tx => {
|
|
|
9
8
|
const toNumber = value => {
|
|
10
9
|
return value == null ? undefined : BigNumber.from(value).toNumber();
|
|
11
10
|
};
|
|
12
|
-
const convertToUnsigned = tx =>
|
|
13
|
-
const resolvedTx =
|
|
11
|
+
const convertToUnsigned = async tx => {
|
|
12
|
+
const resolvedTx = await resolveProperties(tx);
|
|
14
13
|
const {
|
|
15
14
|
chainId,
|
|
16
15
|
data,
|
|
@@ -25,7 +24,7 @@ const convertToUnsigned = tx => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
25
24
|
// Allowed transaction keys for Legacy and EIP-155 Transactions
|
|
26
25
|
const baseTx = {
|
|
27
26
|
gasLimit: gasLimit || gas,
|
|
28
|
-
type: type
|
|
27
|
+
type: type ?? 2,
|
|
29
28
|
chainId,
|
|
30
29
|
gasPrice,
|
|
31
30
|
nonce,
|
|
@@ -44,7 +43,7 @@ const convertToUnsigned = tx => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
44
43
|
baseTx.type = 2;
|
|
45
44
|
}
|
|
46
45
|
return baseTx;
|
|
47
|
-
}
|
|
46
|
+
};
|
|
48
47
|
const checkError = error => {
|
|
49
48
|
if (error.statusText === 'INS_NOT_SUPPORTED') {
|
|
50
49
|
// eslint-disable-next-line no-param-reassign
|
|
@@ -61,7 +60,7 @@ const checkError = error => {
|
|
|
61
60
|
throw error;
|
|
62
61
|
};
|
|
63
62
|
const clearLedgerDerivationPath = () => {
|
|
64
|
-
window
|
|
63
|
+
window?.localStorage.removeItem(LS_KEY_DERIVATION_PATH);
|
|
65
64
|
};
|
|
66
65
|
|
|
67
66
|
export { checkError, clearLedgerDerivationPath, convertToUnsigned, hasEIP1559, toNumber };
|
package/dist/hid/provider.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { __awaiter } from '../_virtual/_tslib.js';
|
|
2
1
|
import invariant from 'tiny-invariant';
|
|
3
2
|
import { JsonRpcBatchProvider } from '@ethersproject/providers';
|
|
4
3
|
import { arrayify } from '@ethersproject/bytes';
|
|
@@ -10,15 +9,13 @@ class LedgerHQProvider extends JsonRpcBatchProvider {
|
|
|
10
9
|
super(...args);
|
|
11
10
|
this.signer = this.getSigner();
|
|
12
11
|
}
|
|
13
|
-
loadTransport() {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
});
|
|
12
|
+
async loadTransport() {
|
|
13
|
+
if (!this.transport) {
|
|
14
|
+
const {
|
|
15
|
+
default: TransportWebHID
|
|
16
|
+
} = await import('@ledgerhq/hw-transport-webhid');
|
|
17
|
+
this.transport = TransportWebHID;
|
|
18
|
+
}
|
|
22
19
|
}
|
|
23
20
|
getSigner() {
|
|
24
21
|
return new LedgerHQSigner(this);
|
|
@@ -29,93 +26,84 @@ class LedgerHQProvider extends JsonRpcBatchProvider {
|
|
|
29
26
|
detectNetwork() {
|
|
30
27
|
return Promise.resolve(this._network);
|
|
31
28
|
}
|
|
32
|
-
getTransport() {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return checkError(error);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
29
|
+
async getTransport() {
|
|
30
|
+
await this.loadTransport();
|
|
31
|
+
try {
|
|
32
|
+
const transportInstance = await this.transport?.create();
|
|
33
|
+
this.device = transportInstance.device;
|
|
34
|
+
return transportInstance;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return checkError(error);
|
|
37
|
+
}
|
|
44
38
|
}
|
|
45
|
-
enable() {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.emit('disconnect');
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
hid.addEventListener('disconnect', onDisconnect);
|
|
59
|
-
if (!this.signer) {
|
|
60
|
-
this.signer = this.getSigner();
|
|
39
|
+
async enable() {
|
|
40
|
+
try {
|
|
41
|
+
await this.loadTransport();
|
|
42
|
+
const {
|
|
43
|
+
hid
|
|
44
|
+
} = window.navigator;
|
|
45
|
+
const onDisconnect = event => {
|
|
46
|
+
if (this.device === event.device) {
|
|
47
|
+
hid.removeEventListener('disconnect', onDisconnect);
|
|
48
|
+
this.emit('disconnect');
|
|
61
49
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
50
|
+
};
|
|
51
|
+
hid.addEventListener('disconnect', onDisconnect);
|
|
52
|
+
if (!this.signer) {
|
|
53
|
+
this.signer = this.getSigner();
|
|
65
54
|
}
|
|
66
|
-
|
|
55
|
+
return await this.getAddress();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return checkError(error);
|
|
58
|
+
}
|
|
67
59
|
}
|
|
68
|
-
getAddress() {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return yield this.signer.getAddress();
|
|
72
|
-
});
|
|
60
|
+
async getAddress() {
|
|
61
|
+
invariant(this.signer, 'Signer is not defined');
|
|
62
|
+
return await this.signer.getAddress();
|
|
73
63
|
}
|
|
74
|
-
request(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
});
|
|
64
|
+
async request({
|
|
65
|
+
method,
|
|
66
|
+
params
|
|
67
|
+
}) {
|
|
68
|
+
invariant(this.signer, 'Signer is not defined');
|
|
69
|
+
switch (method) {
|
|
70
|
+
case 'eth_sendTransaction':
|
|
71
|
+
{
|
|
72
|
+
const sourceTx = params[0];
|
|
73
|
+
const unsignedTx = await convertToUnsigned(sourceTx);
|
|
74
|
+
const signedTx = await this.signer.signTransaction(unsignedTx);
|
|
75
|
+
return this.send('eth_sendRawTransaction', [signedTx]);
|
|
76
|
+
}
|
|
77
|
+
case 'eth_accounts':
|
|
78
|
+
return [await this.getAddress()];
|
|
79
|
+
case 'eth_signTypedData_v4':
|
|
80
|
+
{
|
|
81
|
+
if (typeof params[1] !== 'string') throw new Error('eth_signTypedData_v4 arg 1 is not a string');
|
|
82
|
+
const payload = JSON.parse(params[1]);
|
|
83
|
+
return await this.signer.__signEIP712Message({
|
|
84
|
+
domain: payload.domain,
|
|
85
|
+
types: payload.types,
|
|
86
|
+
primaryType: payload.primaryType,
|
|
87
|
+
message: payload.message
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
case 'personal_sign':
|
|
91
|
+
{
|
|
92
|
+
const messageHex = params[0];
|
|
93
|
+
if (typeof messageHex !== 'string') throw new Error('personal_sign message must be a string');
|
|
94
|
+
const messageBytes = arrayify(messageHex);
|
|
95
|
+
return await this.signer.signMessage(messageBytes);
|
|
96
|
+
}
|
|
97
|
+
case 'eth_sign':
|
|
98
|
+
{
|
|
99
|
+
const messageHex = params[1];
|
|
100
|
+
if (typeof messageHex !== 'string') throw new Error('eth_sign message must be a string');
|
|
101
|
+
const messageBytes = arrayify(messageHex);
|
|
102
|
+
return await this.signer.signMessage(messageBytes);
|
|
103
|
+
}
|
|
104
|
+
default:
|
|
105
|
+
return this.send(method, params);
|
|
106
|
+
}
|
|
119
107
|
}
|
|
120
108
|
}
|
|
121
109
|
|
package/dist/hid/signer.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { __awaiter } from '../_virtual/_tslib.js';
|
|
2
1
|
import { BigNumber } from '@ethersproject/bignumber';
|
|
3
2
|
import { Signer } from '@ethersproject/abstract-signer';
|
|
4
3
|
import { serialize } from '@ethersproject/transactions';
|
|
@@ -23,90 +22,81 @@ class LedgerHQSigner extends Signer {
|
|
|
23
22
|
this._address = '';
|
|
24
23
|
this.provider = provider;
|
|
25
24
|
}
|
|
26
|
-
withEthApp(callback) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
});
|
|
25
|
+
async withEthApp(callback) {
|
|
26
|
+
const transport = await this.provider.getTransport();
|
|
27
|
+
try {
|
|
28
|
+
const {
|
|
29
|
+
default: Eth
|
|
30
|
+
} = await import('@ledgerhq/hw-app-eth');
|
|
31
|
+
const eth = new Eth(transport);
|
|
32
|
+
await eth.getAppConfiguration();
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
34
|
+
return await callback(eth);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return checkError(error);
|
|
37
|
+
} finally {
|
|
38
|
+
await transport.close();
|
|
39
|
+
}
|
|
43
40
|
}
|
|
44
|
-
getAddress() {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return this._address;
|
|
49
|
-
});
|
|
41
|
+
async getAddress() {
|
|
42
|
+
const account = await this.withEthApp(eth => eth.getAddress(this.path));
|
|
43
|
+
this._address = this.provider.formatter.address(account.address);
|
|
44
|
+
return this._address;
|
|
50
45
|
}
|
|
51
|
-
signMessage(message) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return joinSignature(sig);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
populateUnsigned(transaction) {
|
|
65
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
-
const populated = yield this.populateTransaction(transaction);
|
|
67
|
-
const nonce = toNumber(populated.nonce);
|
|
68
|
-
if (populated.type === 0) {
|
|
69
|
-
const {
|
|
70
|
-
gasLimit,
|
|
71
|
-
type,
|
|
72
|
-
chainId,
|
|
73
|
-
gasPrice,
|
|
74
|
-
value,
|
|
75
|
-
data,
|
|
76
|
-
to
|
|
77
|
-
} = populated;
|
|
78
|
-
// Allowed transaction keys for Legacy and EIP-155 Transactions
|
|
79
|
-
return {
|
|
80
|
-
gasLimit,
|
|
81
|
-
type,
|
|
82
|
-
chainId,
|
|
83
|
-
gasPrice,
|
|
84
|
-
nonce,
|
|
85
|
-
value,
|
|
86
|
-
data,
|
|
87
|
-
to
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
return Object.assign(Object.assign({}, populated), {
|
|
91
|
-
nonce
|
|
92
|
-
});
|
|
93
|
-
});
|
|
46
|
+
async signMessage(message) {
|
|
47
|
+
if (typeof message === 'string') {
|
|
48
|
+
// eslint-disable-next-line no-param-reassign
|
|
49
|
+
message = toUtf8Bytes(message);
|
|
50
|
+
}
|
|
51
|
+
const messageHex = hexlify(message).substring(2);
|
|
52
|
+
const sig = await this.withEthApp(eth => eth.signPersonalMessage(this.path, messageHex));
|
|
53
|
+
sig.r = `0x${sig.r}`;
|
|
54
|
+
sig.s = `0x${sig.s}`;
|
|
55
|
+
return joinSignature(sig);
|
|
94
56
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const serializedTx = serialize(populatedTx).substring(2);
|
|
57
|
+
async populateUnsigned(transaction) {
|
|
58
|
+
const populated = await this.populateTransaction(transaction);
|
|
59
|
+
const nonce = toNumber(populated.nonce);
|
|
60
|
+
if (populated.type === 0) {
|
|
100
61
|
const {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
62
|
+
gasLimit,
|
|
63
|
+
type,
|
|
64
|
+
chainId,
|
|
65
|
+
gasPrice,
|
|
66
|
+
value,
|
|
67
|
+
data,
|
|
68
|
+
to
|
|
69
|
+
} = populated;
|
|
70
|
+
// Allowed transaction keys for Legacy and EIP-155 Transactions
|
|
71
|
+
return {
|
|
72
|
+
gasLimit,
|
|
73
|
+
type,
|
|
74
|
+
chainId,
|
|
75
|
+
gasPrice,
|
|
76
|
+
nonce,
|
|
77
|
+
value,
|
|
78
|
+
data,
|
|
79
|
+
to
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
...populated,
|
|
84
|
+
nonce
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async signTransaction(transaction, loadConfig = {}, resolutionConfig = {}) {
|
|
88
|
+
const unsignedTx = await convertToUnsigned(transaction);
|
|
89
|
+
const populatedTx = await this.populateUnsigned(unsignedTx);
|
|
90
|
+
const serializedTx = serialize(populatedTx).substring(2);
|
|
91
|
+
const {
|
|
92
|
+
ledgerService
|
|
93
|
+
} = await import('@ledgerhq/hw-app-eth');
|
|
94
|
+
const resolution = await ledgerService.resolveTransaction(serializedTx, loadConfig, resolutionConfig);
|
|
95
|
+
const sig = await this.withEthApp(eth => eth.signTransaction(this.path, serializedTx, resolution));
|
|
96
|
+
return serialize(populatedTx, {
|
|
97
|
+
v: BigNumber.from(`0x${sig.v}`).toNumber(),
|
|
98
|
+
r: `0x${sig.r}`,
|
|
99
|
+
s: `0x${sig.s}`
|
|
110
100
|
});
|
|
111
101
|
}
|
|
112
102
|
connect(provider) {
|
|
@@ -121,65 +111,60 @@ class LedgerHQSigner extends Signer {
|
|
|
121
111
|
throw new Error('method is not implemented');
|
|
122
112
|
}
|
|
123
113
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/require-await
|
|
124
|
-
unlock() {
|
|
125
|
-
|
|
126
|
-
throw new Error('method is not implemented');
|
|
127
|
-
});
|
|
114
|
+
async unlock() {
|
|
115
|
+
throw new Error('method is not implemented');
|
|
128
116
|
}
|
|
129
117
|
// eslint-disable-next-line class-methods-use-this, @typescript-eslint/require-await
|
|
130
|
-
_legacySignMessage(_message) {
|
|
131
|
-
|
|
132
|
-
throw new Error('method is not implemented');
|
|
133
|
-
});
|
|
118
|
+
async _legacySignMessage(_message) {
|
|
119
|
+
throw new Error('method is not implemented');
|
|
134
120
|
}
|
|
135
121
|
// _signTypedData as per ethers Signer, cleans up types, replaces domain, calculates primaryType
|
|
136
|
-
_signTypedData(domain, _types, value) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
122
|
+
async _signTypedData(domain, _types, value) {
|
|
123
|
+
const types = {
|
|
124
|
+
..._types
|
|
125
|
+
};
|
|
126
|
+
delete types.EIP712Domain;
|
|
127
|
+
const encoder = new _TypedDataEncoder(types);
|
|
128
|
+
const data = {
|
|
129
|
+
domain: {
|
|
130
|
+
name: domain.name,
|
|
131
|
+
verifyingContract: domain.verifyingContract,
|
|
132
|
+
version: domain.version,
|
|
133
|
+
chainId: domain.chainId // eslint-disable-next-line radix
|
|
134
|
+
? parseInt(domain.chainId.toString()) : undefined
|
|
135
|
+
},
|
|
136
|
+
types: {
|
|
137
|
+
...types,
|
|
138
|
+
EIP712Domain: [{
|
|
139
|
+
name: 'name',
|
|
140
|
+
type: 'string'
|
|
141
|
+
}, {
|
|
142
|
+
name: 'version',
|
|
143
|
+
type: 'string'
|
|
144
|
+
}, {
|
|
145
|
+
name: 'chainId',
|
|
146
|
+
type: 'uint256'
|
|
147
|
+
}, {
|
|
148
|
+
name: 'verifyingContract',
|
|
149
|
+
type: 'address'
|
|
150
|
+
}]
|
|
151
|
+
},
|
|
152
|
+
primaryType: encoder.primaryType,
|
|
153
|
+
message: value
|
|
154
|
+
};
|
|
155
|
+
return this.__signEIP712Message(data);
|
|
169
156
|
}
|
|
170
157
|
// custom method, also called directly on eth_signTypedData_v4 RPC request
|
|
171
|
-
__signEIP712Message(data) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
v
|
|
182
|
-
});
|
|
158
|
+
async __signEIP712Message(data) {
|
|
159
|
+
const {
|
|
160
|
+
r,
|
|
161
|
+
s,
|
|
162
|
+
v
|
|
163
|
+
} = await this.withEthApp(eth => eth.signEIP712Message(this.path, data));
|
|
164
|
+
return joinSignature({
|
|
165
|
+
r: `0x${r}`,
|
|
166
|
+
s: `0x${s}`,
|
|
167
|
+
v
|
|
183
168
|
});
|
|
184
169
|
}
|
|
185
170
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { Chain } from 'wagmi/chains';
|
|
2
2
|
import type { IFrameEthereumProviderOptions } from '@ledgerhq/iframe-provider';
|
|
3
|
-
import type { LedgerIFrameProvider } from './provider';
|
|
4
3
|
export declare const idLedgerLive = "ledgerLive";
|
|
5
4
|
export declare const name = "Ledger Live";
|
|
6
5
|
type LedgerLiveConnectorArgs = {
|
|
7
6
|
options?: IFrameEthereumProviderOptions;
|
|
8
7
|
defaultChain: Chain;
|
|
9
8
|
};
|
|
10
|
-
export declare function ledgerLiveConnector({ options, defaultChain, }: LedgerLiveConnectorArgs): import("wagmi").CreateConnectorFn<
|
|
9
|
+
export declare function ledgerLiveConnector({ options, defaultChain, }: LedgerLiveConnectorArgs): import("wagmi").CreateConnectorFn<provider, properties, storageItem>;
|
|
11
10
|
export declare namespace ledgerLiveConnector {
|
|
12
11
|
var type: string;
|
|
13
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../src/iframe/connector.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAIrC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../src/iframe/connector.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAIrC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAG/E,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,wEA0IzB;yBA7Ie,mBAAmB"}
|
package/dist/iframe/connector.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { __awaiter } from '../_virtual/_tslib.js';
|
|
2
1
|
import { createConnector, SwitchChainNotSupportedError } from 'wagmi';
|
|
3
2
|
import { UserRejectedRequestError, ResourceUnavailableRpcError } from 'viem';
|
|
4
3
|
import { getAddress } from '@ethersproject/address';
|
|
@@ -20,130 +19,114 @@ function ledgerLiveConnector({
|
|
|
20
19
|
id: idLedgerLive,
|
|
21
20
|
name,
|
|
22
21
|
type: ledgerLiveConnector.type,
|
|
23
|
-
getProvider(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
return providers[chain.id];
|
|
36
|
-
});
|
|
22
|
+
async getProvider({
|
|
23
|
+
chainId
|
|
24
|
+
} = {}) {
|
|
25
|
+
const chain = chains.find(x => x.id === chainId) ?? defaultChain;
|
|
26
|
+
if (!providers[chain.id]) {
|
|
27
|
+
const {
|
|
28
|
+
LedgerIFrameProvider
|
|
29
|
+
} = await import('./provider.js');
|
|
30
|
+
providers[chain.id] = new LedgerIFrameProvider(options);
|
|
31
|
+
}
|
|
32
|
+
return providers[chain.id];
|
|
37
33
|
},
|
|
38
|
-
connect(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
async connect({
|
|
35
|
+
chainId
|
|
36
|
+
} = {}) {
|
|
37
|
+
try {
|
|
38
|
+
const provider = await this.getProvider();
|
|
39
|
+
// works without bind because it's an obj created(scoped) in a function
|
|
40
|
+
provider.on('accountsChanged', this.onAccountsChanged);
|
|
41
|
+
provider.on('chainChanged', this.onChainChanged);
|
|
42
|
+
emitter.emit('message', {
|
|
43
|
+
type: 'connecting'
|
|
44
|
+
});
|
|
45
|
+
const accounts = await this.getAccounts();
|
|
46
|
+
let currentChainId = await this.getChainId();
|
|
47
|
+
if (chainId && currentChainId !== chainId && this.switchChain) {
|
|
48
|
+
const chain = await this.switchChain({
|
|
49
|
+
chainId
|
|
49
50
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
chainId: currentChainId
|
|
61
|
-
};
|
|
62
|
-
} catch (error) {
|
|
63
|
-
if (error instanceof Error) {
|
|
64
|
-
if (error.code === 4001) {
|
|
65
|
-
throw new UserRejectedRequestError(error);
|
|
66
|
-
}
|
|
67
|
-
throw new ResourceUnavailableRpcError(error);
|
|
51
|
+
currentChainId = chain.id;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
accounts,
|
|
55
|
+
chainId: currentChainId
|
|
56
|
+
};
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
if (error.code === 4001) {
|
|
60
|
+
throw new UserRejectedRequestError(error);
|
|
68
61
|
}
|
|
69
|
-
throw error;
|
|
62
|
+
throw new ResourceUnavailableRpcError(error);
|
|
70
63
|
}
|
|
71
|
-
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
72
66
|
},
|
|
73
|
-
switchChain(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
67
|
+
async switchChain({
|
|
68
|
+
chainId
|
|
69
|
+
}) {
|
|
70
|
+
const provider = await this.getProvider();
|
|
71
|
+
const id = hexValue(chainId);
|
|
72
|
+
try {
|
|
73
|
+
await provider.send('wallet_switchEthereumChain', [{
|
|
74
|
+
chainId: id
|
|
75
|
+
}]);
|
|
76
|
+
return chains.find(x => x.id === chainId) ?? {
|
|
77
|
+
id: chainId,
|
|
78
|
+
name: `Chain ${id}`,
|
|
79
|
+
network: `${id}`,
|
|
80
|
+
nativeCurrency: {
|
|
81
|
+
decimals: 18,
|
|
82
|
+
name: 'Ether',
|
|
83
|
+
symbol: 'ETH'
|
|
84
|
+
},
|
|
85
|
+
rpcUrls: {
|
|
86
|
+
default: {
|
|
87
|
+
http: ['']
|
|
92
88
|
},
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
http: ['']
|
|
96
|
-
},
|
|
97
|
-
public: {
|
|
98
|
-
http: ['']
|
|
99
|
-
}
|
|
89
|
+
public: {
|
|
90
|
+
http: ['']
|
|
100
91
|
}
|
|
101
|
-
};
|
|
102
|
-
} catch (error) {
|
|
103
|
-
const message = typeof error === 'string' ? error : error === null || error === void 0 ? void 0 : error.message;
|
|
104
|
-
if (/user rejected request/i.test(message)) {
|
|
105
|
-
throw new UserRejectedRequestError(error);
|
|
106
92
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
93
|
+
};
|
|
94
|
+
} catch (error) {
|
|
95
|
+
const message = typeof error === 'string' ? error : error?.message;
|
|
96
|
+
if (/user rejected request/i.test(message)) {
|
|
97
|
+
throw new UserRejectedRequestError(error);
|
|
112
98
|
}
|
|
113
|
-
|
|
99
|
+
throw new SwitchChainNotSupportedError({
|
|
100
|
+
connector: {
|
|
101
|
+
name
|
|
102
|
+
} // only name is needed to generate an error message
|
|
103
|
+
});
|
|
104
|
+
}
|
|
114
105
|
},
|
|
115
|
-
getAccounts() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return accounts.map(getAddress);
|
|
121
|
-
});
|
|
106
|
+
async getAccounts() {
|
|
107
|
+
const provider = await this.getProvider();
|
|
108
|
+
const accounts = await provider.send('eth_requestAccounts');
|
|
109
|
+
// return checksum address
|
|
110
|
+
return accounts.map(getAddress);
|
|
122
111
|
},
|
|
123
|
-
getChainId() {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return Number(chainId);
|
|
128
|
-
});
|
|
112
|
+
async getChainId() {
|
|
113
|
+
const provider = await this.getProvider();
|
|
114
|
+
const chainId = await provider.send('eth_chainId');
|
|
115
|
+
return Number(chainId);
|
|
129
116
|
},
|
|
130
|
-
getSigner() {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return new Web3Provider(provider).getSigner(accounts[0]);
|
|
134
|
-
});
|
|
117
|
+
async getSigner() {
|
|
118
|
+
const [provider, accounts] = await Promise.all([this.getProvider(), this.getAccounts()]);
|
|
119
|
+
return new Web3Provider(provider).getSigner(accounts[0]);
|
|
135
120
|
},
|
|
136
|
-
isAuthorized() {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
});
|
|
121
|
+
async isAuthorized() {
|
|
122
|
+
try {
|
|
123
|
+
const provider = await this.getProvider();
|
|
124
|
+
const accounts = await provider.send('eth_accounts');
|
|
125
|
+
const account = accounts[0];
|
|
126
|
+
return !!account;
|
|
127
|
+
} catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
147
130
|
},
|
|
148
131
|
onAccountsChanged(accounts) {
|
|
149
132
|
if (accounts.length === 0 || !accounts[0]) {
|
|
@@ -160,12 +143,10 @@ function ledgerLiveConnector({
|
|
|
160
143
|
chainId: Number(chainId)
|
|
161
144
|
});
|
|
162
145
|
},
|
|
163
|
-
disconnect() {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
provider.removeListener('chainChanged', this.onChainChanged);
|
|
168
|
-
});
|
|
146
|
+
async disconnect() {
|
|
147
|
+
const provider = await this.getProvider();
|
|
148
|
+
provider.removeListener('accountsChanged', this.onAccountsChanged);
|
|
149
|
+
provider.removeListener('chainChanged', this.onChainChanged);
|
|
169
150
|
},
|
|
170
151
|
onDisconnect() {
|
|
171
152
|
emitter.emit('disconnect');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reef-knot/ledger-connector",
|
|
3
|
-
"version": "4.4.0-alpha.
|
|
3
|
+
"version": "4.4.0-alpha.4",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/w3c-web-hid": "^1.0.2",
|
|
41
41
|
"eslint-config-custom": "*",
|
|
42
|
-
"viem": ">=2.
|
|
43
|
-
"wagmi": ">=
|
|
42
|
+
"viem": ">=2.44",
|
|
43
|
+
"wagmi": ">=3.3"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@ethersproject/abstract-signer": "^5.7.0",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"@tanstack/react-query": "^5.29.0",
|
|
65
|
-
"viem": ">=2.
|
|
66
|
-
"wagmi": ">=
|
|
65
|
+
"viem": ">=2.44",
|
|
66
|
+
"wagmi": ">=3.3"
|
|
67
67
|
}
|
|
68
68
|
}
|
package/dist/_virtual/_tslib.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/******************************************************************************
|
|
2
|
-
Copyright (c) Microsoft Corporation.
|
|
3
|
-
|
|
4
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
5
|
-
purpose with or without fee is hereby granted.
|
|
6
|
-
|
|
7
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
8
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
9
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
10
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
11
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
12
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
13
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
14
|
-
***************************************************************************** */
|
|
15
|
-
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
19
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
20
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
21
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
22
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
23
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
24
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
29
|
-
var e = new Error(message);
|
|
30
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export { __awaiter };
|