@injectivelabs/wallet-trezor 1.15.0 → 1.15.2
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/cjs/index.d.ts +3 -0
- package/dist/cjs/index.js +22 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/strategy/Base.d.ts +42 -0
- package/dist/cjs/strategy/Base.js +280 -0
- package/dist/cjs/strategy/TrezorBip32.d.ts +5 -0
- package/dist/cjs/strategy/TrezorBip32.js +17 -0
- package/dist/cjs/strategy/TrezorBip44.d.ts +5 -0
- package/dist/cjs/strategy/TrezorBip44.js +17 -0
- package/dist/cjs/strategy/hw/AccountManager.d.ts +19 -0
- package/dist/cjs/strategy/hw/AccountManager.js +106 -0
- package/dist/cjs/strategy/hw/index.d.ts +4 -0
- package/dist/cjs/strategy/hw/index.js +12 -0
- package/dist/cjs/strategy/hw/transport/base.d.ts +6 -0
- package/dist/cjs/strategy/hw/transport/base.js +19 -0
- package/dist/cjs/strategy/hw/transport/transport-init.d.ts +4 -0
- package/dist/cjs/strategy/hw/transport/transport-init.js +27 -0
- package/dist/cjs/strategy/hw/transport/transport-no-init.d.ts +4 -0
- package/dist/cjs/strategy/hw/transport/transport-no-init.js +12 -0
- package/dist/cjs/types.d.ts +11 -0
- package/dist/cjs/types.js +9 -0
- package/dist/cjs/utils.d.ts +16 -0
- package/dist/cjs/utils.js +34 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/strategy/Base.d.ts +42 -0
- package/dist/esm/strategy/Base.js +277 -0
- package/dist/esm/strategy/TrezorBip32.d.ts +5 -0
- package/dist/esm/strategy/TrezorBip32.js +10 -0
- package/dist/esm/strategy/TrezorBip44.d.ts +5 -0
- package/dist/esm/strategy/TrezorBip44.js +10 -0
- package/dist/esm/strategy/hw/AccountManager.d.ts +19 -0
- package/dist/esm/strategy/hw/AccountManager.js +100 -0
- package/dist/esm/strategy/hw/index.d.ts +4 -0
- package/dist/esm/strategy/hw/index.js +4 -0
- package/dist/esm/strategy/hw/transport/base.d.ts +6 -0
- package/dist/esm/strategy/hw/transport/base.js +13 -0
- package/dist/esm/strategy/hw/transport/transport-init.d.ts +4 -0
- package/dist/esm/strategy/hw/transport/transport-init.js +21 -0
- package/dist/esm/strategy/hw/transport/transport-no-init.d.ts +4 -0
- package/dist/esm/strategy/hw/transport/transport-no-init.js +6 -0
- package/dist/esm/types.d.ts +11 -0
- package/dist/esm/types.js +6 -0
- package/dist/esm/utils.d.ts +16 -0
- package/dist/esm/utils.js +30 -0
- package/package.json +6 -6
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type TypedMessageV4 } from '@injectivelabs/sdk-ts';
|
|
2
|
+
/**
|
|
3
|
+
* Calculates the domain_separator_hash and message_hash from an EIP-712 Typed Data object.
|
|
4
|
+
*
|
|
5
|
+
* The Trezor Model 1 does not currently support constructing the hash on the device,
|
|
6
|
+
* so this function pre-computes them.
|
|
7
|
+
*
|
|
8
|
+
* @template {TypedMessage} T
|
|
9
|
+
* @param {T} data - The EIP-712 Typed Data object.
|
|
10
|
+
* @param {boolean} metamask_v4_compat - Set to `true` for compatibility with Metamask's signTypedData_v4 function.
|
|
11
|
+
* @returns {{domain_separator_hash: string, message_hash?: string} & T} The hashes.
|
|
12
|
+
*/
|
|
13
|
+
export declare const transformTypedData: <T extends TypedMessageV4>(data: T, metamask_v4_compat?: boolean) => {
|
|
14
|
+
domain_separator_hash: string;
|
|
15
|
+
message_hash?: string;
|
|
16
|
+
} & T;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.transformTypedData = void 0;
|
|
4
|
+
const exceptions_1 = require("@injectivelabs/exceptions");
|
|
5
|
+
const sdk_ts_1 = require("@injectivelabs/sdk-ts");
|
|
6
|
+
/**
|
|
7
|
+
* Calculates the domain_separator_hash and message_hash from an EIP-712 Typed Data object.
|
|
8
|
+
*
|
|
9
|
+
* The Trezor Model 1 does not currently support constructing the hash on the device,
|
|
10
|
+
* so this function pre-computes them.
|
|
11
|
+
*
|
|
12
|
+
* @template {TypedMessage} T
|
|
13
|
+
* @param {T} data - The EIP-712 Typed Data object.
|
|
14
|
+
* @param {boolean} metamask_v4_compat - Set to `true` for compatibility with Metamask's signTypedData_v4 function.
|
|
15
|
+
* @returns {{domain_separator_hash: string, message_hash?: string} & T} The hashes.
|
|
16
|
+
*/
|
|
17
|
+
const transformTypedData = (data, metamask_v4_compat = true) => {
|
|
18
|
+
if (!metamask_v4_compat) {
|
|
19
|
+
throw new exceptions_1.TrezorException(new Error('Trezor: Only version 4 of typed data signing is supported'));
|
|
20
|
+
}
|
|
21
|
+
const version = sdk_ts_1.SignTypedDataVersionV4;
|
|
22
|
+
const { types, primaryType, domain, message } = (0, sdk_ts_1.TypedDataUtilsSanitizeData)(data);
|
|
23
|
+
const domainSeparatorHash = (0, sdk_ts_1.TypedDataUtilsHashStruct)('EIP712Domain', (0, sdk_ts_1.sanitizeTypedData)(domain), types, version).toString('hex');
|
|
24
|
+
let messageHash = null;
|
|
25
|
+
if (primaryType !== 'EIP712Domain') {
|
|
26
|
+
messageHash = (0, sdk_ts_1.TypedDataUtilsHashStruct)(primaryType, (0, sdk_ts_1.sanitizeTypedData)(message), types, version).toString('hex');
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
domain_separator_hash: domainSeparatorHash,
|
|
30
|
+
message_hash: messageHash,
|
|
31
|
+
...data,
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
exports.transformTypedData = transformTypedData;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AccountAddress, EthereumChainId } from '@injectivelabs/ts-types';
|
|
2
|
+
import { TxRaw, TxResponse, DirectSignResponse, AminoSignResponse } from '@injectivelabs/sdk-ts';
|
|
3
|
+
import { StdSignDoc, WalletDeviceType, BaseConcreteStrategy, ConcreteWalletStrategy, SendTransactionOptions, ConcreteEthereumWalletStrategyArgs } from '@injectivelabs/wallet-base';
|
|
4
|
+
import { TrezorDerivationPathType } from '../types.js';
|
|
5
|
+
export default class TrezorBase extends BaseConcreteStrategy implements ConcreteWalletStrategy {
|
|
6
|
+
private baseDerivationPath;
|
|
7
|
+
private trezor;
|
|
8
|
+
private ethereumOptions;
|
|
9
|
+
private alchemy;
|
|
10
|
+
private derivationPathType;
|
|
11
|
+
constructor(args: ConcreteEthereumWalletStrategyArgs & {
|
|
12
|
+
derivationPathType: TrezorDerivationPathType;
|
|
13
|
+
});
|
|
14
|
+
getWalletDeviceType(): Promise<WalletDeviceType>;
|
|
15
|
+
enable(): Promise<boolean>;
|
|
16
|
+
disconnect(): Promise<void>;
|
|
17
|
+
getAddresses(): Promise<string[]>;
|
|
18
|
+
getSessionOrConfirm(address: AccountAddress): Promise<string>;
|
|
19
|
+
sendEthereumTransaction(txData: any, options: {
|
|
20
|
+
address: string;
|
|
21
|
+
ethereumChainId: EthereumChainId;
|
|
22
|
+
}): Promise<string>;
|
|
23
|
+
sendTransaction(transaction: TxRaw, options: SendTransactionOptions): Promise<TxResponse>;
|
|
24
|
+
signEip712TypedData(eip712json: string, address: AccountAddress): Promise<string>;
|
|
25
|
+
signAminoCosmosTransaction(_transaction: {
|
|
26
|
+
address: string;
|
|
27
|
+
signDoc: StdSignDoc;
|
|
28
|
+
}): Promise<AminoSignResponse>;
|
|
29
|
+
signCosmosTransaction(_transaction: {
|
|
30
|
+
txRaw: TxRaw;
|
|
31
|
+
accountNumber: number;
|
|
32
|
+
chainId: string;
|
|
33
|
+
address: string;
|
|
34
|
+
}): Promise<DirectSignResponse>;
|
|
35
|
+
signArbitrary(signer: AccountAddress, data: string | Uint8Array): Promise<string>;
|
|
36
|
+
getEthereumChainId(): Promise<string>;
|
|
37
|
+
getEthereumTransactionReceipt(txHash: string): Promise<string>;
|
|
38
|
+
getPubKey(): Promise<string>;
|
|
39
|
+
private signEthereumTransaction;
|
|
40
|
+
private getWalletForAddress;
|
|
41
|
+
private getAlchemy;
|
|
42
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
/* eslint-disable class-methods-use-this */
|
|
3
|
+
import { EthereumChainId } from '@injectivelabs/ts-types';
|
|
4
|
+
import { Alchemy, Network as AlchemyNetwork } from 'alchemy-sdk';
|
|
5
|
+
import { addHexPrefix } from 'ethereumjs-util';
|
|
6
|
+
import { FeeMarketEIP1559Transaction } from '@ethereumjs/tx';
|
|
7
|
+
import { Common, Chain, Hardfork } from '@ethereumjs/common';
|
|
8
|
+
import { TrezorConnect } from '@bangjelkoski/trezor-connect-web';
|
|
9
|
+
import { ErrorType, WalletException, TrezorException, GeneralException, TransactionException, UnspecifiedErrorCode, } from '@injectivelabs/exceptions';
|
|
10
|
+
import { toUtf8, TxGrpcApi, } from '@injectivelabs/sdk-ts';
|
|
11
|
+
import { TIP_IN_GWEI, WalletAction, getKeyFromRpcUrl, WalletDeviceType, BaseConcreteStrategy, DEFAULT_BASE_DERIVATION_PATH, DEFAULT_ADDRESS_SEARCH_LIMIT, DEFAULT_NUM_ADDRESSES_TO_FETCH, } from '@injectivelabs/wallet-base';
|
|
12
|
+
import { TrezorTransportInit } from './hw/index.js';
|
|
13
|
+
import { transformTypedData } from '../utils.js';
|
|
14
|
+
const getNetworkFromChainId = (chainId) => {
|
|
15
|
+
if (chainId === EthereumChainId.Goerli) {
|
|
16
|
+
return Chain.Goerli;
|
|
17
|
+
}
|
|
18
|
+
if (chainId === EthereumChainId.Sepolia) {
|
|
19
|
+
return Chain.Sepolia;
|
|
20
|
+
}
|
|
21
|
+
if (chainId === EthereumChainId.Kovan) {
|
|
22
|
+
return Chain.Goerli;
|
|
23
|
+
}
|
|
24
|
+
return Chain.Mainnet;
|
|
25
|
+
};
|
|
26
|
+
export default class TrezorBase extends BaseConcreteStrategy {
|
|
27
|
+
baseDerivationPath;
|
|
28
|
+
trezor;
|
|
29
|
+
ethereumOptions;
|
|
30
|
+
alchemy;
|
|
31
|
+
derivationPathType;
|
|
32
|
+
constructor(args) {
|
|
33
|
+
super(args);
|
|
34
|
+
this.baseDerivationPath = DEFAULT_BASE_DERIVATION_PATH;
|
|
35
|
+
this.derivationPathType = args.derivationPathType;
|
|
36
|
+
this.trezor = new TrezorTransportInit();
|
|
37
|
+
this.ethereumOptions = args.ethereumOptions;
|
|
38
|
+
}
|
|
39
|
+
async getWalletDeviceType() {
|
|
40
|
+
return Promise.resolve(WalletDeviceType.Hardware);
|
|
41
|
+
}
|
|
42
|
+
async enable() {
|
|
43
|
+
return Promise.resolve(true);
|
|
44
|
+
}
|
|
45
|
+
async disconnect() {
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
}
|
|
48
|
+
async getAddresses() {
|
|
49
|
+
const { baseDerivationPath, derivationPathType } = this;
|
|
50
|
+
try {
|
|
51
|
+
await this.trezor.connect();
|
|
52
|
+
const accountManager = await this.trezor.getAccountManager();
|
|
53
|
+
const wallets = await accountManager.getWallets(baseDerivationPath, derivationPathType);
|
|
54
|
+
return wallets.map((k) => k.address);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
throw new TrezorException(new Error(e.message), {
|
|
58
|
+
code: UnspecifiedErrorCode,
|
|
59
|
+
type: ErrorType.WalletError,
|
|
60
|
+
contextModule: WalletAction.GetAccounts,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async getSessionOrConfirm(address) {
|
|
65
|
+
return Promise.resolve(`0x${Buffer.from(`Confirmation for ${address} at time: ${Date.now()}`).toString('hex')}`);
|
|
66
|
+
}
|
|
67
|
+
async sendEthereumTransaction(txData, options) {
|
|
68
|
+
const signedTransaction = await this.signEthereumTransaction(txData, options);
|
|
69
|
+
try {
|
|
70
|
+
const alchemy = await this.getAlchemy();
|
|
71
|
+
const txReceipt = await alchemy.core.sendTransaction(addHexPrefix(signedTransaction.serialize().toString('hex')));
|
|
72
|
+
return txReceipt.hash;
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
throw new TrezorException(new Error(e.message), {
|
|
76
|
+
code: UnspecifiedErrorCode,
|
|
77
|
+
type: ErrorType.WalletError,
|
|
78
|
+
contextModule: WalletAction.SendEthereumTransaction,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async sendTransaction(transaction, options) {
|
|
83
|
+
const { endpoints, txTimeout } = options;
|
|
84
|
+
if (!endpoints) {
|
|
85
|
+
throw new WalletException(new Error('You have to pass endpoints.grpc within the options for using Ethereum native wallets'));
|
|
86
|
+
}
|
|
87
|
+
const txApi = new TxGrpcApi(endpoints.grpc);
|
|
88
|
+
const response = await txApi.broadcast(transaction, { txTimeout });
|
|
89
|
+
if (response.code !== 0) {
|
|
90
|
+
throw new TransactionException(new Error(response.rawLog), {
|
|
91
|
+
code: UnspecifiedErrorCode,
|
|
92
|
+
contextCode: response.code,
|
|
93
|
+
contextModule: response.codespace,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return response;
|
|
97
|
+
}
|
|
98
|
+
async signEip712TypedData(eip712json, address) {
|
|
99
|
+
const object = JSON.parse(eip712json);
|
|
100
|
+
const compatibleObject = {
|
|
101
|
+
...object,
|
|
102
|
+
domain: {
|
|
103
|
+
...object.domain,
|
|
104
|
+
chainId: object.domain.chainId,
|
|
105
|
+
salt: '0',
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
const dataWithHashes = transformTypedData(compatibleObject);
|
|
109
|
+
const { types: { EIP712Domain = [], ...otherTypes } = {}, message = {}, domain = {}, primaryType, domain_separator_hash, message_hash, } = dataWithHashes;
|
|
110
|
+
try {
|
|
111
|
+
await this.trezor.connect();
|
|
112
|
+
const { derivationPath } = await this.getWalletForAddress(address);
|
|
113
|
+
const response = await TrezorConnect.ethereumSignTypedData({
|
|
114
|
+
path: derivationPath,
|
|
115
|
+
data: {
|
|
116
|
+
types: { EIP712Domain, ...otherTypes },
|
|
117
|
+
message,
|
|
118
|
+
domain,
|
|
119
|
+
primaryType,
|
|
120
|
+
},
|
|
121
|
+
message_hash,
|
|
122
|
+
domain_separator_hash,
|
|
123
|
+
metamask_v4_compat: true,
|
|
124
|
+
});
|
|
125
|
+
if (!response.success) {
|
|
126
|
+
// noinspection ExceptionCaughtLocallyJS
|
|
127
|
+
throw new Error((response.payload && response.payload.error) || 'Unknown error');
|
|
128
|
+
}
|
|
129
|
+
return response.payload.signature;
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
throw new TrezorException(new Error(e.message), {
|
|
133
|
+
code: UnspecifiedErrorCode,
|
|
134
|
+
type: ErrorType.WalletError,
|
|
135
|
+
contextModule: WalletAction.SignTransaction,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async signAminoCosmosTransaction(_transaction) {
|
|
140
|
+
throw new WalletException(new Error('This wallet does not support signing Cosmos transactions'), {
|
|
141
|
+
code: UnspecifiedErrorCode,
|
|
142
|
+
type: ErrorType.WalletError,
|
|
143
|
+
contextModule: WalletAction.SendTransaction,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// eslint-disable-next-line class-methods-use-this
|
|
147
|
+
async signCosmosTransaction(_transaction) {
|
|
148
|
+
throw new WalletException(new Error('This wallet does not support signing Cosmos transactions'), {
|
|
149
|
+
code: UnspecifiedErrorCode,
|
|
150
|
+
type: ErrorType.WalletError,
|
|
151
|
+
contextModule: WalletAction.SendTransaction,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
async signArbitrary(signer, data) {
|
|
155
|
+
try {
|
|
156
|
+
await this.trezor.connect();
|
|
157
|
+
const { derivationPath } = await this.getWalletForAddress(signer);
|
|
158
|
+
const response = await TrezorConnect.ethereumSignMessage({
|
|
159
|
+
path: derivationPath,
|
|
160
|
+
message: toUtf8(data),
|
|
161
|
+
});
|
|
162
|
+
if (!response.success) {
|
|
163
|
+
throw new Error((response.payload && response.payload.error) || 'Unknown error');
|
|
164
|
+
}
|
|
165
|
+
return response.payload.signature;
|
|
166
|
+
}
|
|
167
|
+
catch (e) {
|
|
168
|
+
throw new TrezorException(new Error(e.message), {
|
|
169
|
+
code: UnspecifiedErrorCode,
|
|
170
|
+
type: ErrorType.WalletError,
|
|
171
|
+
contextModule: WalletAction.SignTransaction,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async getEthereumChainId() {
|
|
176
|
+
const alchemy = await this.getAlchemy();
|
|
177
|
+
const alchemyProvider = await alchemy.config.getProvider();
|
|
178
|
+
return alchemyProvider.network.chainId.toString();
|
|
179
|
+
}
|
|
180
|
+
async getEthereumTransactionReceipt(txHash) {
|
|
181
|
+
return Promise.resolve(txHash);
|
|
182
|
+
}
|
|
183
|
+
// eslint-disable-next-line class-methods-use-this
|
|
184
|
+
async getPubKey() {
|
|
185
|
+
throw new WalletException(new Error('You can only fetch PubKey from Cosmos native wallets'));
|
|
186
|
+
}
|
|
187
|
+
async signEthereumTransaction(txData, options) {
|
|
188
|
+
const chainId = parseInt(options.ethereumChainId.toString(), 10);
|
|
189
|
+
const alchemy = await this.getAlchemy();
|
|
190
|
+
const nonce = await alchemy.core.getTransactionCount(options.address);
|
|
191
|
+
const common = new Common({
|
|
192
|
+
chain: getNetworkFromChainId(chainId),
|
|
193
|
+
hardfork: Hardfork.London,
|
|
194
|
+
});
|
|
195
|
+
const eip1559TxData = {
|
|
196
|
+
from: txData.from,
|
|
197
|
+
data: txData.data,
|
|
198
|
+
to: txData.to,
|
|
199
|
+
nonce: addHexPrefix(nonce.toString(16)),
|
|
200
|
+
gas: addHexPrefix(txData.gas),
|
|
201
|
+
gasLimit: addHexPrefix(txData.gas),
|
|
202
|
+
maxFeePerGas: addHexPrefix(txData.gasPrice || txData.maxFeePerGas),
|
|
203
|
+
maxPriorityFeePerGas: addHexPrefix(txData.maxPriorityFeePerGas || TIP_IN_GWEI.toString(16)),
|
|
204
|
+
};
|
|
205
|
+
const tx = FeeMarketEIP1559Transaction.fromTxData(eip1559TxData, {
|
|
206
|
+
common,
|
|
207
|
+
});
|
|
208
|
+
const transaction = {
|
|
209
|
+
...tx.toJSON(),
|
|
210
|
+
chainId,
|
|
211
|
+
};
|
|
212
|
+
try {
|
|
213
|
+
await this.trezor.connect();
|
|
214
|
+
const { derivationPath } = await this.getWalletForAddress(options.address);
|
|
215
|
+
const response = await TrezorConnect.ethereumSignTransaction({
|
|
216
|
+
path: derivationPath,
|
|
217
|
+
transaction,
|
|
218
|
+
});
|
|
219
|
+
if (!response.success) {
|
|
220
|
+
throw new TrezorException(new Error((response.payload && response.payload.error) ||
|
|
221
|
+
'Something happened while signing with Trezor'), {
|
|
222
|
+
code: UnspecifiedErrorCode,
|
|
223
|
+
type: ErrorType.WalletError,
|
|
224
|
+
contextModule: WalletAction.SignEthereumTransaction,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
const signedTxData = {
|
|
228
|
+
...eip1559TxData,
|
|
229
|
+
v: `${response.payload.v}`,
|
|
230
|
+
r: `${response.payload.r}`,
|
|
231
|
+
s: `${response.payload.s}`,
|
|
232
|
+
};
|
|
233
|
+
return FeeMarketEIP1559Transaction.fromTxData(signedTxData, {
|
|
234
|
+
common,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
if (e instanceof TrezorException) {
|
|
239
|
+
throw e;
|
|
240
|
+
}
|
|
241
|
+
throw new TrezorException(new Error(e.message), {
|
|
242
|
+
code: UnspecifiedErrorCode,
|
|
243
|
+
type: ErrorType.WalletError,
|
|
244
|
+
contextModule: WalletAction.SignEthereumTransaction,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async getWalletForAddress(address) {
|
|
249
|
+
const { baseDerivationPath, derivationPathType } = this;
|
|
250
|
+
const accountManager = await this.trezor.getAccountManager();
|
|
251
|
+
if (!accountManager.hasWalletForAddress(address)) {
|
|
252
|
+
for (let i = 0; i < DEFAULT_ADDRESS_SEARCH_LIMIT / DEFAULT_NUM_ADDRESSES_TO_FETCH; i += 1) {
|
|
253
|
+
await accountManager.getWallets(baseDerivationPath, derivationPathType);
|
|
254
|
+
if (accountManager.hasWalletForAddress(address)) {
|
|
255
|
+
return (await accountManager.getWalletForAddress(address));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return (await accountManager.getWalletForAddress(address));
|
|
260
|
+
}
|
|
261
|
+
async getAlchemy() {
|
|
262
|
+
if (this.alchemy) {
|
|
263
|
+
return this.alchemy;
|
|
264
|
+
}
|
|
265
|
+
const { rpcUrl, ethereumChainId } = this.ethereumOptions;
|
|
266
|
+
if (!rpcUrl) {
|
|
267
|
+
throw new GeneralException(new Error('Please pass rpcUrl within the ethereumOptions'));
|
|
268
|
+
}
|
|
269
|
+
this.alchemy = new Alchemy({
|
|
270
|
+
apiKey: getKeyFromRpcUrl(rpcUrl),
|
|
271
|
+
network: ethereumChainId === EthereumChainId.Mainnet
|
|
272
|
+
? AlchemyNetwork.ETH_MAINNET
|
|
273
|
+
: AlchemyNetwork.ETH_SEPOLIA,
|
|
274
|
+
});
|
|
275
|
+
return this.alchemy;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AccountAddress } from '@injectivelabs/ts-types';
|
|
2
|
+
import { TrezorWalletInfo, TrezorDerivationPathType } from '../../types.js';
|
|
3
|
+
export default class AccountManager {
|
|
4
|
+
private wallets;
|
|
5
|
+
constructor();
|
|
6
|
+
getWallets(baseDerivationPath: string, derivationPathType: TrezorDerivationPathType): Promise<TrezorWalletInfo[]>;
|
|
7
|
+
getTrezorDerivationPathBasedOnType: ({ fullBaseDerivationPath, derivationPathType, index, }: {
|
|
8
|
+
fullBaseDerivationPath: string;
|
|
9
|
+
derivationPathType: TrezorDerivationPathType;
|
|
10
|
+
index: number;
|
|
11
|
+
}) => string;
|
|
12
|
+
private getWalletsBasedOnIndex;
|
|
13
|
+
private hasWallets;
|
|
14
|
+
private hasWalletsInOffset;
|
|
15
|
+
private getOffset;
|
|
16
|
+
hasWalletForAddress(address: AccountAddress): boolean;
|
|
17
|
+
getWalletForAddress(address: AccountAddress): Promise<TrezorWalletInfo | undefined>;
|
|
18
|
+
reset(): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import HDNode from 'hdkey';
|
|
2
|
+
import { TrezorException } from '@injectivelabs/exceptions';
|
|
3
|
+
import { TrezorDerivationPathType } from '../../types.js';
|
|
4
|
+
import { addHexPrefix, publicKeyToAddress } from '@injectivelabs/sdk-ts';
|
|
5
|
+
import { DEFAULT_NUM_ADDRESSES_TO_FETCH } from '@injectivelabs/wallet-base';
|
|
6
|
+
import { TrezorConnect } from '@bangjelkoski/trezor-connect-web';
|
|
7
|
+
const addressOfHDKey = (hdKey) => {
|
|
8
|
+
const shouldSanitizePublicKey = true;
|
|
9
|
+
const derivedPublicKey = hdKey.publicKey;
|
|
10
|
+
const ethereumAddressWithoutPrefix = Buffer.from(publicKeyToAddress(derivedPublicKey, shouldSanitizePublicKey)).toString('hex');
|
|
11
|
+
const address = addHexPrefix(ethereumAddressWithoutPrefix);
|
|
12
|
+
return address;
|
|
13
|
+
};
|
|
14
|
+
export default class AccountManager {
|
|
15
|
+
wallets = [];
|
|
16
|
+
constructor() {
|
|
17
|
+
this.wallets = [];
|
|
18
|
+
}
|
|
19
|
+
async getWallets(baseDerivationPath, derivationPathType) {
|
|
20
|
+
const { start, end } = this.getOffset();
|
|
21
|
+
/**
|
|
22
|
+
* 1. Wallets are not yet fetched at all,
|
|
23
|
+
* 2. Wallets are not yet fetched for that offset
|
|
24
|
+
*/
|
|
25
|
+
if (!this.hasWallets() || !this.hasWalletsInOffset(start)) {
|
|
26
|
+
await this.getWalletsBasedOnIndex({
|
|
27
|
+
start,
|
|
28
|
+
end,
|
|
29
|
+
baseDerivationPath,
|
|
30
|
+
derivationPathType,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return this.wallets.slice(start, end);
|
|
34
|
+
}
|
|
35
|
+
getTrezorDerivationPathBasedOnType = ({ fullBaseDerivationPath, derivationPathType, index, }) => {
|
|
36
|
+
if (derivationPathType === TrezorDerivationPathType.Bip44) {
|
|
37
|
+
return `${fullBaseDerivationPath}/${index}'/0/0`;
|
|
38
|
+
}
|
|
39
|
+
if (derivationPathType === TrezorDerivationPathType.Legacy) {
|
|
40
|
+
return `m/${index}`;
|
|
41
|
+
}
|
|
42
|
+
return `${fullBaseDerivationPath}/0'/0/${index}`;
|
|
43
|
+
};
|
|
44
|
+
async getWalletsBasedOnIndex({ start, end, baseDerivationPath, derivationPathType, }) {
|
|
45
|
+
const pathsToFetch = [];
|
|
46
|
+
for (let index = start; index < end; index += 1) {
|
|
47
|
+
const path = this.getTrezorDerivationPathBasedOnType({
|
|
48
|
+
fullBaseDerivationPath: baseDerivationPath,
|
|
49
|
+
derivationPathType,
|
|
50
|
+
index,
|
|
51
|
+
});
|
|
52
|
+
pathsToFetch.push({
|
|
53
|
+
path,
|
|
54
|
+
showOnTrezor: false,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const result = await TrezorConnect.ethereumGetPublicKey({
|
|
58
|
+
bundle: pathsToFetch,
|
|
59
|
+
});
|
|
60
|
+
if (!result.success) {
|
|
61
|
+
throw new TrezorException(new Error((result.payload && result.payload.error) ||
|
|
62
|
+
'Please make sure your Trezor is connected and unlocked'));
|
|
63
|
+
}
|
|
64
|
+
for (const item of result.payload) {
|
|
65
|
+
const hdKey = new HDNode();
|
|
66
|
+
hdKey.publicKey = Buffer.from(item.publicKey, 'hex');
|
|
67
|
+
hdKey.chainCode = Buffer.from(item.chainCode, 'hex');
|
|
68
|
+
const address = addressOfHDKey(hdKey);
|
|
69
|
+
this.wallets.push({
|
|
70
|
+
hdKey,
|
|
71
|
+
derivationPath: item.serializedPath,
|
|
72
|
+
address: address.toLowerCase(),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
hasWallets() {
|
|
77
|
+
return this.wallets.length > 0;
|
|
78
|
+
}
|
|
79
|
+
hasWalletsInOffset(offset) {
|
|
80
|
+
return this.wallets.length > offset;
|
|
81
|
+
}
|
|
82
|
+
getOffset() {
|
|
83
|
+
const totalWallets = this.wallets.length;
|
|
84
|
+
const nextBatchStart = totalWallets;
|
|
85
|
+
const nextBatchEnd = totalWallets + DEFAULT_NUM_ADDRESSES_TO_FETCH;
|
|
86
|
+
return {
|
|
87
|
+
start: nextBatchStart,
|
|
88
|
+
end: nextBatchEnd,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
hasWalletForAddress(address) {
|
|
92
|
+
return (this.wallets.find((wallet) => wallet.address.toLowerCase() === address.toLowerCase()) !== undefined);
|
|
93
|
+
}
|
|
94
|
+
async getWalletForAddress(address) {
|
|
95
|
+
return this.wallets.find((wallet) => wallet.address.toLowerCase() === address.toLowerCase());
|
|
96
|
+
}
|
|
97
|
+
reset() {
|
|
98
|
+
this.wallets = [];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import AccountManager from './../AccountManager.js';
|
|
2
|
+
export default class BaseTrezorTransport {
|
|
3
|
+
accountManager = null;
|
|
4
|
+
async connect() {
|
|
5
|
+
return Promise.resolve();
|
|
6
|
+
}
|
|
7
|
+
async getAccountManager() {
|
|
8
|
+
if (!this.accountManager) {
|
|
9
|
+
this.accountManager = new AccountManager();
|
|
10
|
+
}
|
|
11
|
+
return this.accountManager;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TrezorConnect } from '@bangjelkoski/trezor-connect-web';
|
|
2
|
+
import { WalletException } from '@injectivelabs/exceptions';
|
|
3
|
+
import BaseTrezorTransport from './base.js';
|
|
4
|
+
const TREZOR_CONNECT_MANIFEST = {
|
|
5
|
+
email: 'contact@injectivelabs.org',
|
|
6
|
+
appUrl: 'https://injectivelabs.org',
|
|
7
|
+
};
|
|
8
|
+
export default class TrezorTransportInit extends BaseTrezorTransport {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
try {
|
|
12
|
+
TrezorConnect.init({
|
|
13
|
+
lazyLoad: true,
|
|
14
|
+
manifest: TREZOR_CONNECT_MANIFEST,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
throw new WalletException(e);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export var TrezorDerivationPathType;
|
|
2
|
+
(function (TrezorDerivationPathType) {
|
|
3
|
+
TrezorDerivationPathType["Bip32"] = "bip32";
|
|
4
|
+
TrezorDerivationPathType["Bip44"] = "bip44";
|
|
5
|
+
TrezorDerivationPathType["Legacy"] = "legacy";
|
|
6
|
+
})(TrezorDerivationPathType || (TrezorDerivationPathType = {}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type TypedMessageV4 } from '@injectivelabs/sdk-ts';
|
|
2
|
+
/**
|
|
3
|
+
* Calculates the domain_separator_hash and message_hash from an EIP-712 Typed Data object.
|
|
4
|
+
*
|
|
5
|
+
* The Trezor Model 1 does not currently support constructing the hash on the device,
|
|
6
|
+
* so this function pre-computes them.
|
|
7
|
+
*
|
|
8
|
+
* @template {TypedMessage} T
|
|
9
|
+
* @param {T} data - The EIP-712 Typed Data object.
|
|
10
|
+
* @param {boolean} metamask_v4_compat - Set to `true` for compatibility with Metamask's signTypedData_v4 function.
|
|
11
|
+
* @returns {{domain_separator_hash: string, message_hash?: string} & T} The hashes.
|
|
12
|
+
*/
|
|
13
|
+
export declare const transformTypedData: <T extends TypedMessageV4>(data: T, metamask_v4_compat?: boolean) => {
|
|
14
|
+
domain_separator_hash: string;
|
|
15
|
+
message_hash?: string;
|
|
16
|
+
} & T;
|