@exodus/web3-ethereum 10.7.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,16 @@
1
1
  import { fetchGasLimit, getNonce as apiGetNonce, getServer, } from '@exodus/ethereum-api';
2
+ import { InvalidInputError } from '@exodus/web3-errors';
3
+ import { signMessage, signTypedData } from '@exodus/web3-ethereum-utils';
4
+ import { SignTypedDataVersion } from '@metamask/eth-sig-util';
2
5
  import BN from 'bn.js';
6
+ async function getDefaultPurposeForLedger(asset) {
7
+ const purposes = await asset.api.getSupportedPurposes({
8
+ compatibilityMode: 'ledger',
9
+ });
10
+ return purposes[0];
11
+ }
3
12
  const createEvmDepsFactory = ({ analytics, blockchainMetadata, }) => {
4
- return ({ assetName, origin, getAsset, getAddress: _getAddress, getPrivateKey: _getPrivateKey, getFeeData: getFeeConfig, getCustomFeeRate, getActiveWalletAccount, simulateEthereumTransactions, }) => {
13
+ return ({ assetName, origin, getAsset, getAddress: _getAddress, getPrivateKey: _getPrivateKey, getFeeData: getFeeConfig, getCustomFeeRate, getActiveWalletAccount, simulateEthereumTransactions, getActiveWalletAccountData, transactionSigner, getLedgerDevice, }) => {
5
14
  const asset = getAsset(assetName);
6
15
  const server = getServer(asset);
7
16
  const forwardRequest = async ({ method, params }) => {
@@ -107,6 +116,44 @@ const createEvmDepsFactory = ({ analytics, blockchainMetadata, }) => {
107
116
  });
108
117
  return true;
109
118
  };
119
+ const messageSigner = {
120
+ signMessage: async ({ baseAssetName, walletAccount, message, }) => {
121
+ const { rawMessage, EIP712Message } = message;
122
+ if (walletAccount.source === 'exodus') {
123
+ const privateKey = await getPrivateKey();
124
+ if (rawMessage) {
125
+ return Buffer.from(signMessage(rawMessage.toString(), privateKey));
126
+ }
127
+ if (EIP712Message) {
128
+ const typedDataVersion = Array.isArray(EIP712Message)
129
+ ? SignTypedDataVersion.V1
130
+ : SignTypedDataVersion.V4;
131
+ return Buffer.from(signTypedData(EIP712Message, privateKey, typedDataVersion));
132
+ }
133
+ }
134
+ else if (getLedgerDevice) {
135
+ const device = await getLedgerDevice();
136
+ const purpose = await getDefaultPurposeForLedger(asset);
137
+ const { derivationPath } = await getAsset(assetName).baseAsset.api.getKeyIdentifier({
138
+ compatibilityMode: 'ledger',
139
+ purpose,
140
+ accountIndex: 0,
141
+ chainIndex: 0,
142
+ addressIndex: 0,
143
+ });
144
+ const signedMessage = await device.signMessage({
145
+ assetName: baseAssetName,
146
+ derivationPath,
147
+ message: {
148
+ rawMessage,
149
+ EIP712Message,
150
+ },
151
+ });
152
+ return Buffer.from(signedMessage);
153
+ }
154
+ throw new InvalidInputError();
155
+ },
156
+ };
110
157
  return {
111
158
  chainId: 'undefined',
112
159
  forwardRequest,
@@ -119,6 +166,9 @@ const createEvmDepsFactory = ({ analytics, blockchainMetadata, }) => {
119
166
  getCustomFeeData,
120
167
  onEthWalletWatchAssetRequest: trackWalletWatchAssetUse,
121
168
  simulateEthereumTransactions,
169
+ transactionSigner,
170
+ messageSigner,
171
+ getActiveWalletAccountData,
122
172
  };
123
173
  };
124
174
  };
@@ -1,5 +1,4 @@
1
1
  import { AssetNotSupportedError, InvalidInputError, UnauthorizedError, UserRejectedRequestError, } from '@exodus/web3-errors';
2
- import { getTransactionId, signMessage, signTransaction, signTypedData, } from '@exodus/web3-ethereum-utils';
3
2
  import { connect } from '@exodus/web3-rpc-handlers';
4
3
  import { hexToBN } from '@exodus/web3-utils';
5
4
  import { SignTypedDataVersion } from '@metamask/eth-sig-util';
@@ -62,7 +61,7 @@ const isValidGasLimitValue = (value) => {
62
61
  return proposedGasLimit.lte(maximumBlockGasLimit);
63
62
  };
64
63
  export function exposeHandlers(rpc, deps) {
65
- const { chainId, isTrusted, isAutoApproved, ensureTrusted, approveConnection, approveMessage, approveTransactions, forwardRequest, getAddress, getPrivateKey, getEstimatedGas, getCustomFeeData, getFeeData, getNonce, sendRawTransaction, simulateEthereumTransactions, scanDomains, onTransactionsSigned = () => { }, onEthWalletWatchAssetRequest = () => { }, isUnlocked = () => true, ensureUnlocked = async () => true, getAsset, getOrigin, } = deps;
64
+ const { chainId, isTrusted, isAutoApproved, ensureTrusted, approveConnection, approveMessage, approveTransactions, forwardRequest, getAddress, getEstimatedGas, getCustomFeeData, getFeeData, getNonce, sendRawTransaction, simulateEthereumTransactions, scanDomains, onTransactionsSigned = () => { }, onEthWalletWatchAssetRequest = () => { }, isUnlocked = () => true, ensureUnlocked = async () => true, getAsset, getOrigin, getActiveWalletAccountData, transactionSigner, messageSigner, } = deps;
66
65
  const network = `evm:${chainId}`;
67
66
  async function assertTrusted() {
68
67
  const trusted = await isTrusted();
@@ -142,26 +141,48 @@ export function exposeHandlers(rpc, deps) {
142
141
  });
143
142
  await approve(approveTransactions, network, simulatedChanges);
144
143
  const modifiedTransaction = await applyCustomFeeRate(preparedTransaction);
145
- const privateKey = await getPrivateKey();
146
- const signedTransaction = signTransaction({ ...modifiedTransaction, chainId }, privateKey);
147
144
  const isEIP1559Enabled = !!modifiedTransaction.maxFeePerGas;
148
- const transactionId = getTransactionId(signedTransaction, isEIP1559Enabled);
149
- onTransactionsSigned(network, [transactionId]);
150
- return `0x${signedTransaction.toString('hex')}`;
145
+ const walletAccount = await getActiveWalletAccountData();
146
+ const { rawTx: signedTransaction, txId } = await transactionSigner.signTransaction({
147
+ baseAssetName: asset.baseAssetName,
148
+ walletAccount,
149
+ unsignedTx: {
150
+ txData: { transaction: { ...modifiedTransaction, chainId } },
151
+ txMeta: { eip1559Enabled: isEIP1559Enabled },
152
+ },
153
+ });
154
+ onTransactionsSigned(network, [txId]);
155
+ return `0x${Buffer.from(signedTransaction).toString('hex')}`;
151
156
  }
152
157
  async function approveAndSignMessage(message) {
153
158
  await assertTrusted();
154
159
  await approve(approveMessage, network, message);
155
- const privateKey = await getPrivateKey();
156
- return signMessage(message, privateKey);
160
+ const walletAccount = await getActiveWalletAccountData();
161
+ const asset = await getAsset(network);
162
+ const signedMessageBuffer = await messageSigner.signMessage({
163
+ walletAccount,
164
+ baseAssetName: asset.baseAssetName,
165
+ message: {
166
+ rawMessage: Buffer.from(message),
167
+ },
168
+ });
169
+ return signedMessageBuffer.toString();
157
170
  }
158
171
  async function approveAndSignTypedData(typedData) {
159
172
  await assertTrusted();
160
173
  const parsedTypedData = parseAndValidateTypedData(typedData, { chainId });
161
174
  const message = typedDataToMessage(typedData, SignTypedDataVersion.V4);
162
175
  await approve(approveMessage, network, message);
163
- const privateKey = await getPrivateKey();
164
- return signTypedData(parsedTypedData, privateKey, SignTypedDataVersion.V4);
176
+ const walletAccount = await getActiveWalletAccountData();
177
+ const asset = await getAsset(network);
178
+ const signedMessageBuffer = await messageSigner.signMessage({
179
+ walletAccount,
180
+ baseAssetName: asset.baseAssetName,
181
+ message: {
182
+ EIP712Message: parsedTypedData,
183
+ },
184
+ });
185
+ return signedMessageBuffer.toString();
165
186
  }
166
187
  function exposeEvmFunction(name,
167
188
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -203,8 +224,16 @@ export function exposeHandlers(rpc, deps) {
203
224
  await assertTrusted();
204
225
  const message = typedDataToMessage(typedData, SignTypedDataVersion.V1);
205
226
  await approve(approveMessage, network, message);
206
- const privateKey = await getPrivateKey();
207
- return signTypedData(typedData, privateKey, SignTypedDataVersion.V1);
227
+ const walletAccount = await getActiveWalletAccountData();
228
+ const asset = await getAsset(network);
229
+ const signedMessageBuffer = await messageSigner.signMessage({
230
+ walletAccount,
231
+ baseAssetName: asset.baseAssetName,
232
+ message: {
233
+ EIP712Message: typedData,
234
+ },
235
+ });
236
+ return signedMessageBuffer.toString();
208
237
  });
209
238
  exposeEvmFunction('eth_signTypedData_v3', async (account, typedData) => approveAndSignTypedData(typedData));
210
239
  exposeEvmFunction('eth_signTypedData_v4', async (account, typedData) => approveAndSignTypedData(typedData));
@@ -15,6 +15,9 @@ const validateEVMDeps = (evm) => {
15
15
  'getNonce',
16
16
  'sendRawTransaction',
17
17
  'simulateEthereumTransactions',
18
+ 'getActiveWalletAccountData',
19
+ 'transactionSigner',
20
+ 'messageSigner',
18
21
  ];
19
22
  const optionalKeys = ['onEthWalletWatchAssetRequest'];
20
23
  validateDeps(evm, requiredKeys, optionalKeys);
package/lib/types.d.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  import type { EthereumProvider } from './provider/index.js';
3
3
  import type { EthAggregatedTransactionSimulationResult, EthSimulateTransactionParams, EthTransaction, EthTransactionHash, EthWalletWatchAsset } from '@exodus/web3-ethereum-utils';
4
+ import type { EthTransactionParams } from '@exodus/web3-ethereum-utils';
4
5
  import type { WalletStandardCommonDeps } from '@exodus/web3-provider';
5
6
  import type { CommonDeps } from '@exodus/web3-rpc-handlers';
6
- import type { Asset, IAnalyticsModule, IBlockchainMetadataModule, EthereumFeeData, GetFeeDataParams, CreateSimulationServiceParams, NumberUnit } from '@exodus/web3-types';
7
+ import type { Asset, CreateSimulationServiceParams, EthereumFeeData, GetActiveWalletAccountData, GetFeeDataParams, GetLedgerDevice, IAnalyticsModule, IBlockchainMetadataModule, IMessageSignerModule, ITransactionSignerModule, NumberUnit } from '@exodus/web3-types';
8
+ import type { TypedDataV1 } from '@metamask/eth-sig-util';
9
+ import type { MessageTypes, TypedMessage } from '@metamask/eth-sig-util/sign-typed-data';
7
10
  /**
8
11
  * EVM-compatible chains.
9
12
  */
@@ -34,8 +37,12 @@ export interface CreateEvmDepsParams {
34
37
  privateKey: Buffer;
35
38
  }>;
36
39
  simulateEthereumTransactions: SimulateTransactionsFn;
40
+ getActiveWalletAccountData: GetActiveWalletAccountData;
41
+ transactionSigner: EVMTransactionSignerModule;
42
+ getLedgerDevice?: GetLedgerDevice;
37
43
  }
38
44
  export declare type EVMFactory = (params: CreateEvmDepsParams) => EVMDeps;
45
+ export declare type EVMTransactionSignerModule = ITransactionSignerModule<EVMUnsignedTransaction>;
39
46
  export declare type EVMDeps = {
40
47
  chainId: string;
41
48
  getAddress: () => Promise<string>;
@@ -47,7 +54,10 @@ export declare type EVMDeps = {
47
54
  getCustomFeeData: () => Promise<FeeData | undefined>;
48
55
  getNonce: () => Promise<string>;
49
56
  forwardRequest: (args: EthRequestArguments) => Promise<unknown>;
57
+ transactionSigner: EVMTransactionSignerModule;
58
+ messageSigner: EVMMessageSigner;
50
59
  onEthWalletWatchAssetRequest?: (assetDetails: EthWalletWatchAsset) => Promise<boolean>;
60
+ getActiveWalletAccountData: GetActiveWalletAccountData;
51
61
  };
52
62
  export declare type Dependencies = {
53
63
  evms: EVMDeps[];
@@ -55,4 +65,17 @@ export declare type Dependencies = {
55
65
  export interface WalletStandardDeps extends WalletStandardCommonDeps {
56
66
  provider: EthereumProvider;
57
67
  }
68
+ export interface EVMUnsignedTransaction {
69
+ txData: {
70
+ transaction: EthTransactionParams;
71
+ };
72
+ txMeta: {
73
+ eip1559Enabled: boolean;
74
+ };
75
+ }
76
+ export interface EVMMesage {
77
+ rawMessage?: Buffer;
78
+ EIP712Message?: TypedDataV1 | TypedMessage<MessageTypes>;
79
+ }
80
+ export declare type EVMMessageSigner = IMessageSignerModule<EVMMesage>;
58
81
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exodus/web3-ethereum",
3
3
  "description": "Apps connectivity library for EVM-compatible chains.",
4
- "version": "10.7.0",
4
+ "version": "11.0.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "module": "lib/index.js",
@@ -33,10 +33,10 @@
33
33
  "@exodus/currency": "^2.1.2",
34
34
  "@exodus/ethereum-api": "^6.3.33",
35
35
  "@exodus/web3-constants": "^1.29.0",
36
- "@exodus/web3-ethereum-utils": "^3.16.0",
37
- "@exodus/web3-provider": "^3.7.0",
38
- "@exodus/web3-rpc-handlers": "^2.13.0",
39
- "@exodus/web3-utils": "^1.37.0",
36
+ "@exodus/web3-ethereum-utils": "^3.17.0",
37
+ "@exodus/web3-provider": "^3.8.0",
38
+ "@exodus/web3-rpc-handlers": "^2.14.0",
39
+ "@exodus/web3-utils": "^1.38.0",
40
40
  "bn.js": "^5.2.0",
41
41
  "eth-rpc-errors": "^4.0.3"
42
42
  },
@@ -44,12 +44,12 @@
44
44
  "@exodus/assets": "^8.0.95",
45
45
  "@exodus/json-rpc": "^1.11.0",
46
46
  "@exodus/schemasafe": "^1.0.0",
47
- "@exodus/web3-types": "^1.43.0",
47
+ "@exodus/web3-types": "^1.44.0",
48
48
  "@exodus/web3-validation": "^1.37.0",
49
49
  "@wallet-standard/base": "^1.0.1"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "@exodus/assets": "^8.0.95"
53
53
  },
54
- "gitHead": "07e0d01d5ba64f77d04412d71195bf4eaf1c09cb"
54
+ "gitHead": "273234a09070d3d7ce08d77cace39695fc27b2c8"
55
55
  }