@exodus/web3-ethereum 2.3.0 → 2.4.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/lib/rpc-handlers/createEvmDeps.d.ts +3 -0
- package/lib/rpc-handlers/createEvmDeps.js +116 -0
- package/lib/rpc-handlers/index.d.ts +1 -1
- package/lib/rpc-handlers/index.js +1 -0
- package/lib/rpc-handlers/parseAndValidateTypedData.js +11 -0
- package/lib/rpc-handlers/validator.js +2 -2
- package/lib/simulation/simulation.d.ts +3 -2
- package/lib/simulation/simulation.js +2 -6
- package/lib/simulation/types.d.ts +0 -2
- package/lib/types.d.ts +12 -2
- package/lib/wallet-standard/wallet.d.ts +1 -1
- package/lib/wallet-standard/wallet.js +1 -1
- package/package.json +8 -7
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { createEvmDepsFactoryParams, EVMFactory } from '../types.js';
|
|
2
|
+
declare const createEvmDepsFactory: ({ analytics, activeWalletAccountAtom, assetsModule, blockchainMetadata, feeMonitors, wallet, walletAccounts, }: createEvmDepsFactoryParams) => EVMFactory;
|
|
3
|
+
export default createEvmDepsFactory;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { fetchGasLimit, getNonce as apiGetNonce, getServer, } from '@exodus/ethereum-api';
|
|
2
|
+
import BN from 'bn.js';
|
|
3
|
+
const createEvmDepsFactory = ({ analytics, activeWalletAccountAtom, assetsModule, blockchainMetadata, feeMonitors, wallet, walletAccounts, }) => {
|
|
4
|
+
return (assetName, origin) => {
|
|
5
|
+
const asset = assetsModule.getAsset(assetName);
|
|
6
|
+
const server = getServer(asset);
|
|
7
|
+
const forwardRequest = async ({ method, params }) => {
|
|
8
|
+
if (server.proxyToCoinNode) {
|
|
9
|
+
return server.proxyToCoinNode({ method, params });
|
|
10
|
+
}
|
|
11
|
+
const request = server.buildRequest({ method, params });
|
|
12
|
+
return server.sendRequest(request);
|
|
13
|
+
};
|
|
14
|
+
const sendRawTransaction = async (rawTransaction) => {
|
|
15
|
+
return server.sendRawTransaction(rawTransaction);
|
|
16
|
+
};
|
|
17
|
+
const _getAccountIndexForActiveWalletAccount = async () => {
|
|
18
|
+
const walletAccount = await activeWalletAccountAtom.get();
|
|
19
|
+
const walletAccountData = walletAccounts.get(walletAccount);
|
|
20
|
+
if (!walletAccountData ||
|
|
21
|
+
walletAccountData.isHardware ||
|
|
22
|
+
walletAccountData.is2FA) {
|
|
23
|
+
throw new Error('Invalid walletAccount');
|
|
24
|
+
}
|
|
25
|
+
const accountIndex = walletAccountData.index;
|
|
26
|
+
return accountIndex;
|
|
27
|
+
};
|
|
28
|
+
const getAddress = async () => {
|
|
29
|
+
const accountIndex = await _getAccountIndexForActiveWalletAccount();
|
|
30
|
+
const { publicKey } = await wallet.getPublicKey({
|
|
31
|
+
baseAssetName: assetName,
|
|
32
|
+
accountIndex,
|
|
33
|
+
});
|
|
34
|
+
return '0x' + publicKey.toString('hex');
|
|
35
|
+
};
|
|
36
|
+
const getPrivateKey = async () => {
|
|
37
|
+
const accountIndex = await _getAccountIndexForActiveWalletAccount();
|
|
38
|
+
const { privateKey } = await wallet.getPrivateKey({
|
|
39
|
+
baseAssetName: assetName,
|
|
40
|
+
accountIndex,
|
|
41
|
+
});
|
|
42
|
+
return privateKey;
|
|
43
|
+
};
|
|
44
|
+
const getNonce = async (account) => {
|
|
45
|
+
// Shouldn't we retrieve the nonce for a given account?
|
|
46
|
+
// We are relying on the assumption here that "account"
|
|
47
|
+
// is always equal to the activeWalletAccount.
|
|
48
|
+
const [baseAssetTxLog, blockchainNonce] = await Promise.all([
|
|
49
|
+
blockchainMetadata.getTxLog({
|
|
50
|
+
assetName,
|
|
51
|
+
walletAccount: await activeWalletAccountAtom.get(),
|
|
52
|
+
}),
|
|
53
|
+
apiGetNonce({ asset, address: account }),
|
|
54
|
+
]);
|
|
55
|
+
const walletNonce = Array.from(baseAssetTxLog)
|
|
56
|
+
.filter((tx) => tx.sent && !tx.dropped && tx.data.nonce != null)
|
|
57
|
+
.reduce((nonce, tx) => Math.max(tx.data.nonce + 1, nonce), 0);
|
|
58
|
+
return `0x${Math.max(walletNonce, blockchainNonce).toString(16)}`;
|
|
59
|
+
};
|
|
60
|
+
const getEstimatedGas = async (transaction) => {
|
|
61
|
+
const EXTRA_PERCENTAGE_GAS_LIMIT = 20;
|
|
62
|
+
const { data: txInput, from: fromAddress, to: toAddress, value: amount, } = transaction;
|
|
63
|
+
const gasLimit = await fetchGasLimit({
|
|
64
|
+
asset,
|
|
65
|
+
amount: amount
|
|
66
|
+
? asset.currency.baseUnit(new BN(amount.slice(2), 'hex'))
|
|
67
|
+
: asset.currency.ZERO,
|
|
68
|
+
fromAddress,
|
|
69
|
+
toAddress,
|
|
70
|
+
txInput,
|
|
71
|
+
extraPercentage: EXTRA_PERCENTAGE_GAS_LIMIT,
|
|
72
|
+
});
|
|
73
|
+
return `0x${gasLimit.toString(16)}`;
|
|
74
|
+
};
|
|
75
|
+
const getFeeData = async () => {
|
|
76
|
+
const { eip1559Enabled, tipGasPrice, gasPrice: _gasPrice, } = await feeMonitors.getFeeData({
|
|
77
|
+
assetName,
|
|
78
|
+
});
|
|
79
|
+
const gasPrice = `0x${_gasPrice.toBaseNumber().toString(16)}`;
|
|
80
|
+
const feeData = {
|
|
81
|
+
gasPrice,
|
|
82
|
+
};
|
|
83
|
+
if (eip1559Enabled) {
|
|
84
|
+
feeData.maxPriorityFeePerGas = `0x${tipGasPrice
|
|
85
|
+
.toBaseNumber()
|
|
86
|
+
.toString(16)}`;
|
|
87
|
+
feeData.maxFeePerGas = gasPrice;
|
|
88
|
+
}
|
|
89
|
+
return feeData;
|
|
90
|
+
};
|
|
91
|
+
const trackWalletWatchAssetUse = async (assetDetails) => {
|
|
92
|
+
// TODO: do we still need this? If yes, this ...assetDetails expansion is no bueno
|
|
93
|
+
// why is this not always returning true in browser?
|
|
94
|
+
analytics.track({
|
|
95
|
+
event: 'DappWalletWatchAsset',
|
|
96
|
+
properties: {
|
|
97
|
+
...assetDetails,
|
|
98
|
+
dappDomain: origin,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
return true;
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
chainId: 'undefined',
|
|
105
|
+
forwardRequest,
|
|
106
|
+
sendRawTransaction,
|
|
107
|
+
getAddress,
|
|
108
|
+
getPrivateKey,
|
|
109
|
+
getNonce,
|
|
110
|
+
getFeeData,
|
|
111
|
+
getEstimatedGas,
|
|
112
|
+
onEthWalletWatchAssetRequest: trackWalletWatchAssetUse,
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
export default createEvmDepsFactory;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { default as createEvmDepsFactory } from './createEvmDeps.js';
|
|
1
2
|
import type { EthRequestArguments } from '../types.js';
|
|
2
3
|
import type { Dependencies } from '../types.js';
|
|
3
4
|
import type RPC from '@exodus/json-rpc';
|
|
@@ -11,4 +12,3 @@ export declare const registerRPCHandlers: ({ deps, RPC, transport, }: {
|
|
|
11
12
|
RPC: RpcConstructor;
|
|
12
13
|
transport: Transport;
|
|
13
14
|
}) => any;
|
|
14
|
-
export {};
|
|
@@ -2,6 +2,7 @@ import { RPC_REQUEST_TIMEOUT } from '@exodus/web3-constants';
|
|
|
2
2
|
import { validate as validateDeps, validateCommonDeps, } from '@exodus/web3-rpc-handlers';
|
|
3
3
|
import { exposeHandlers } from './exposeHandlers.js';
|
|
4
4
|
import { validateRequest } from './validator.js';
|
|
5
|
+
export { default as createEvmDepsFactory } from './createEvmDeps.js';
|
|
5
6
|
const validateEVMDeps = (evm) => {
|
|
6
7
|
const requiredKeys = [
|
|
7
8
|
'chainId',
|
|
@@ -20,6 +20,17 @@ export function parseAndValidateTypedData(typedData, { chainId: activeChainId })
|
|
|
20
20
|
catch (e) {
|
|
21
21
|
throw new InvalidInputError();
|
|
22
22
|
}
|
|
23
|
+
// Security: checking if the 'message' property includes fields that don't belong to the primary type.
|
|
24
|
+
if (!Object.hasOwnProperty.call(parsedTypedData.types, parsedTypedData.primaryType)) {
|
|
25
|
+
throw new InvalidInputError();
|
|
26
|
+
}
|
|
27
|
+
const allowedFieldsSet = new Set(parsedTypedData.types[parsedTypedData.primaryType].map(({ name }) => name));
|
|
28
|
+
for (const field in parsedTypedData.message) {
|
|
29
|
+
if (!allowedFieldsSet.has(field)) {
|
|
30
|
+
throw new InvalidInputError(`field '${field}' is not defined in the primary type definition`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Security: checking if the requested chain matches the active chain ID.
|
|
23
34
|
if (parsedTypedData?.domain?.chainId) {
|
|
24
35
|
const suppliedChainIdHex = convertChainIdToHex(`${parsedTypedData.domain.chainId}`);
|
|
25
36
|
if (activeChainId.toLowerCase() !== suppliedChainIdHex) {
|
|
@@ -611,7 +611,7 @@ export function validateRequest(value) {
|
|
|
611
611
|
}
|
|
612
612
|
return true
|
|
613
613
|
}
|
|
614
|
-
const format5 = new RegExp('^(?!
|
|
614
|
+
const format5 = new RegExp('^(?![\\s_])[\\s\\w!?.,/()[\\]]+$', '')
|
|
615
615
|
const ref9 = function validate(data) {
|
|
616
616
|
validate.errors = null
|
|
617
617
|
if (!Array.isArray(data)) {
|
|
@@ -2348,7 +2348,7 @@ export function parseAndValidateTypedData(value) {
|
|
|
2348
2348
|
/[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length
|
|
2349
2349
|
const pointerPart = (s) =>
|
|
2350
2350
|
/~\//.test(s) ? `${s}`.replace(/~/g, '~0').replace(/\//g, '~1') : s
|
|
2351
|
-
const format0 = new RegExp('^(?!
|
|
2351
|
+
const format0 = new RegExp('^(?![\\s_])[\\s\\w!?.,/()[\\]]+$', '')
|
|
2352
2352
|
const ref2 = function validate(data) {
|
|
2353
2353
|
validate.errors = null
|
|
2354
2354
|
if (!(typeof data === 'object' && data && !Array.isArray(data))) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EthBalanceChanges } from './types.js';
|
|
2
2
|
import type { EthTransaction } from '@exodus/web3-ethereum-utils';
|
|
3
|
+
import type { Asset, NumberUnit } from '@exodus/web3-types';
|
|
3
4
|
export declare const simulateTransaction: (asset: Asset, transaction: EthTransaction) => Promise<{
|
|
4
5
|
assetName: string;
|
|
5
6
|
advancedDetails: never[];
|
|
@@ -7,7 +8,7 @@ export declare const simulateTransaction: (asset: Asset, transaction: EthTransac
|
|
|
7
8
|
displayInfo: {
|
|
8
9
|
title: string;
|
|
9
10
|
};
|
|
10
|
-
txFee:
|
|
11
|
+
txFee: NumberUnit;
|
|
11
12
|
txFeeDetails: {
|
|
12
13
|
gasLimit: number;
|
|
13
14
|
maxFeePerGas: number | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { retrieveSideEffects } from '@exodus/ethereum-api';
|
|
2
2
|
import { SIMULATION_SUPPORTED_ASSET_NAMES } from './constant.js';
|
|
3
|
-
import {
|
|
3
|
+
import { formatAccounts, getEthereumDisplayInfo, hexToBN, isEthTransferTx, } from './utils.js';
|
|
4
4
|
const computeBalanceChanges = async (asset, shouldSimulate, transaction) => {
|
|
5
5
|
let balanceChanges = {
|
|
6
6
|
willReceive: [],
|
|
@@ -10,11 +10,7 @@ const computeBalanceChanges = async (asset, shouldSimulate, transaction) => {
|
|
|
10
10
|
if (isEthTransferTx(transaction)) {
|
|
11
11
|
const txValue = hexToBN(transaction.value).toString();
|
|
12
12
|
balanceChanges.willSend.push({
|
|
13
|
-
balance:
|
|
14
|
-
amount: txValue,
|
|
15
|
-
denominator: asset.currency.defaultUnit.power,
|
|
16
|
-
symbol: asset.displayTicker,
|
|
17
|
-
}),
|
|
13
|
+
balance: asset.currency.baseUnit(txValue),
|
|
18
14
|
});
|
|
19
15
|
}
|
|
20
16
|
else {
|
package/lib/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
import type { EthTransaction, EthTransactionHash, EthWalletWatchAsset } from '@exodus/web3-ethereum-utils';
|
|
3
3
|
import type { CommonDeps } from '@exodus/web3-rpc-handlers';
|
|
4
|
+
import type { IAnalyticsModule, IActiveWalletAccountAtom, IAssetsModule, IBlockchainMetadataModule, IFeeDataModule, IWalletModule, IWalletAccountsModule } from '@exodus/web3-types';
|
|
4
5
|
/**
|
|
5
6
|
* EVM-compatible chains.
|
|
6
7
|
*/
|
|
@@ -8,11 +9,21 @@ export interface EthRequestArguments {
|
|
|
8
9
|
method: string;
|
|
9
10
|
params?: unknown[] | Record<string, unknown>;
|
|
10
11
|
}
|
|
11
|
-
interface FeeData {
|
|
12
|
+
export interface FeeData {
|
|
12
13
|
gasPrice: string;
|
|
13
14
|
maxFeePerGas?: string;
|
|
14
15
|
maxPriorityFeePerGas?: string;
|
|
15
16
|
}
|
|
17
|
+
export interface createEvmDepsFactoryParams {
|
|
18
|
+
activeWalletAccountAtom: IActiveWalletAccountAtom;
|
|
19
|
+
analytics: IAnalyticsModule;
|
|
20
|
+
assetsModule: IAssetsModule;
|
|
21
|
+
blockchainMetadata: IBlockchainMetadataModule;
|
|
22
|
+
feeMonitors: IFeeDataModule;
|
|
23
|
+
wallet: IWalletModule;
|
|
24
|
+
walletAccounts: IWalletAccountsModule;
|
|
25
|
+
}
|
|
26
|
+
export declare type EVMFactory = (assetName: string, origin: string) => EVMDeps;
|
|
16
27
|
export declare type EVMDeps = {
|
|
17
28
|
chainId: string;
|
|
18
29
|
getAddress: () => Promise<string>;
|
|
@@ -27,4 +38,3 @@ export declare type EVMDeps = {
|
|
|
27
38
|
export declare type Dependencies = {
|
|
28
39
|
evms: EVMDeps[];
|
|
29
40
|
} & CommonDeps;
|
|
30
|
-
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": "2.
|
|
4
|
+
"version": "2.4.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"module": "lib/index.js",
|
|
@@ -33,22 +33,23 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@exodus/currency": "^2.1.2",
|
|
35
35
|
"@exodus/ethereum-api": "^6.0.0",
|
|
36
|
-
"@exodus/web3-constants": "^1.
|
|
36
|
+
"@exodus/web3-constants": "^1.19.0",
|
|
37
37
|
"@exodus/web3-ethereum-utils": "^1.8.0",
|
|
38
|
-
"@exodus/web3-provider": "^2.
|
|
39
|
-
"@exodus/web3-rpc-handlers": "^0.
|
|
38
|
+
"@exodus/web3-provider": "^2.17.0",
|
|
39
|
+
"@exodus/web3-rpc-handlers": "^0.14.0",
|
|
40
|
+
"bn.js": "^5.2.0",
|
|
40
41
|
"eth-rpc-errors": "^4.0.3"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@exodus/assets": "^8.0.72",
|
|
44
45
|
"@exodus/json-rpc": "^1.11.0",
|
|
45
46
|
"@exodus/schemasafe": "^1.0.0",
|
|
46
|
-
"@exodus/web3-types": "^1.
|
|
47
|
-
"@exodus/web3-validation": "^1.
|
|
47
|
+
"@exodus/web3-types": "^1.15.0",
|
|
48
|
+
"@exodus/web3-validation": "^1.33.0",
|
|
48
49
|
"@wallet-standard/base": "^1.0.1"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
51
52
|
"@exodus/assets": "^8.0.72"
|
|
52
53
|
},
|
|
53
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "6516ee0735272140b1c48527bf98ed3b7bc54499"
|
|
54
55
|
}
|