@exodus/ethereum-api 9.0.0-alpha.3 → 9.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.
- package/CHANGELOG.md +2121 -0
- package/LICENSE +7 -0
- package/README.md +124 -0
- package/package.json +34 -33
- package/src/address-has-history.js +6 -2
- package/src/allowance/constants.js +4 -5
- package/src/allowance/index.js +159 -40
- package/src/check-tx/create-assess-transaction.js +23 -0
- package/src/check-tx/create-check-tx.js +104 -0
- package/src/check-tx/index.js +1 -0
- package/src/create-asset-plugin-factory.js +115 -0
- package/src/create-asset-utils.js +520 -0
- package/src/create-asset.js +272 -97
- package/src/create-token-factory.js +47 -17
- package/src/custom-fees.js +57 -0
- package/src/eip7702-whitelist.js +62 -0
- package/src/ens/index.js +12 -17
- package/src/error-wrapper.js +383 -0
- package/src/eth-like-util.js +172 -33
- package/src/exodus-eth-server/api-coin-nodes.js +27 -196
- package/src/exodus-eth-server/api.js +23 -14
- package/src/exodus-eth-server/clarity-v2.js +255 -0
- package/src/exodus-eth-server/clarity.js +67 -265
- package/src/exodus-eth-server/errors.js +40 -0
- package/src/exodus-eth-server/eth-like-server.js +385 -0
- package/src/exodus-eth-server/fetch-json.js +48 -0
- package/src/exodus-eth-server/index.js +77 -0
- package/src/exodus-eth-server/utils.js +31 -0
- package/src/exodus-eth-server/ws-gateway.js +306 -0
- package/src/exodus-eth-server/ws.js +1 -2
- package/src/fee-data/EthLikeFeeData.js +81 -0
- package/src/fee-data/index.js +54 -0
- package/src/fee-utils.js +229 -0
- package/src/gas-estimation.js +183 -66
- package/src/get-balance-for-address.js +1 -1
- package/src/get-balances.js +285 -27
- package/src/get-fee.js +92 -56
- package/src/get-historical-balance.js +58 -0
- package/src/hooks/index.js +1 -1
- package/src/hooks/monitor.js +182 -43
- package/src/hooks/staking-freshness.js +58 -0
- package/src/index.js +118 -12
- package/src/move-funds.js +153 -0
- package/src/multicall3/index.js +212 -0
- package/src/multisig-address.js +146 -0
- package/src/nft-utils.js +60 -0
- package/src/number-utils.js +34 -2
- package/src/optimism-gas/index.js +13 -5
- package/src/send-validations.js +58 -0
- package/src/server-based-fee-monitor.js +12 -19
- package/src/simulate-tx/fetch-tx-preview.js +0 -2
- package/src/simulate-tx/index.js +2 -2
- package/src/simulate-tx/simulate-eth-tx.js +24 -11
- package/src/simulation/common.js +34 -0
- package/src/simulation/create-simulate-message.js +49 -0
- package/src/simulation/create-simulate-transactions.js +108 -0
- package/src/simulation/estimate-fee.js +14 -0
- package/src/simulation/estimate-simple-transfer.js +15 -0
- package/src/simulation/get-message-type.js +18 -0
- package/src/simulation/simulate-message-api.js +68 -0
- package/src/simulation/simulate-transactions-api.js +266 -0
- package/src/simulation/simulate-transactions.js +16 -0
- package/src/simulation/transactions.js +52 -0
- package/src/simulation/try-estimating-changes-locally.js +26 -0
- package/src/staking/api/index.js +43 -0
- package/src/staking/cached-read.js +33 -0
- package/src/staking/ethereum/api.js +166 -34
- package/src/staking/ethereum/deps.js +37 -0
- package/src/staking/ethereum/everstake.js +113 -0
- package/src/staking/ethereum/index.js +4 -3
- package/src/staking/ethereum/service.js +682 -181
- package/src/staking/ethereum/staking-utils.js +275 -4
- package/src/staking/fantom-staking.js +9 -9
- package/src/staking/index.js +4 -4
- package/src/staking/matic/addresses.js +2 -0
- package/src/staking/matic/api.js +69 -49
- package/src/staking/matic/index.js +3 -3
- package/src/staking/matic/matic-staking-utils.js +243 -5
- package/src/staking/matic/matic-staking.md +53 -0
- package/src/staking/staking-provider-client.js +1 -1
- package/src/staking/utils/index.js +39 -0
- package/src/tx-create.js +666 -0
- package/src/tx-log/clarity-monitor.js +273 -103
- package/src/tx-log/clarity-truncated-history-monitor.js +109 -0
- package/src/tx-log/clarity-truncated-history-monitor.md +219 -0
- package/src/tx-log/clarity-utils/absolute.js +96 -0
- package/src/tx-log/clarity-utils/get-log-items-from-server-tx.js +94 -31
- package/src/tx-log/clarity-utils/get-names-of-tokens-transferred-by-server-tx.js +3 -2
- package/src/tx-log/clarity-utils/index.js +9 -3
- package/src/tx-log/clarity-utils/is-spam-pending-tx.js +13 -0
- package/src/tx-log/clarity-utils/normalize-transactions-response.js +65 -0
- package/src/tx-log/ethereum-monitor.js +93 -47
- package/src/tx-log/ethereum-no-history-monitor.js +52 -41
- package/src/tx-log/get-optimistic-txlog-effects.js +379 -0
- package/src/tx-log/index.js +5 -3
- package/src/tx-log/monitor-utils/check-pending-transactions.js +14 -5
- package/src/tx-log/monitor-utils/exclude-unchanged-token-balances.js +1 -1
- package/src/tx-log/monitor-utils/extract-balance-from-clarity-account-info.js +108 -0
- package/src/tx-log/monitor-utils/get-balance-updates.js +44 -0
- package/src/tx-log/monitor-utils/get-batched-rpc-balances.js +47 -0
- package/src/tx-log/monitor-utils/get-current-blacklist-status.js +38 -0
- package/src/tx-log/monitor-utils/get-current-eip7702-delegation.js +79 -0
- package/src/tx-log/monitor-utils/get-derive-transactions-to-check.js +10 -5
- package/src/tx-log/monitor-utils/get-fee-amount.js +1 -1
- package/src/tx-log/monitor-utils/get-history-from-server.js +1 -1
- package/src/tx-log/monitor-utils/get-log-items-from-server-tx.js +75 -33
- package/src/tx-log/monitor-utils/get-names-of-tokens-transferred-by-server-tx.js +3 -2
- package/src/tx-log/monitor-utils/get-raw-transfer-amount.js +29 -0
- package/src/tx-log/monitor-utils/get-transfers-by-token-name.js +3 -2
- package/src/tx-log/monitor-utils/get-value-of-transfers.js +10 -12
- package/src/tx-log/monitor-utils/index.js +12 -7
- package/src/tx-log/monitor-utils/is-unverifiable-pending-tx-expired.js +19 -0
- package/src/tx-log/monitor-utils/verify-pending-tx-status-rpc.js +90 -0
- package/src/tx-log-staking-processor/asset-staking-tx-data.js +82 -24
- package/src/tx-log-staking-processor/index.js +28 -14
- package/src/tx-log-staking-processor/utils.js +21 -20
- package/src/tx-send/broadcast-error-handler.js +63 -0
- package/src/tx-send/index.js +1 -2
- package/src/tx-send/nonce-utils.js +97 -0
- package/src/tx-send/tx-send.js +94 -288
- package/src/tx-sign/index.js +17 -0
- package/src/tx-type/index.js +280 -0
- package/src/watch-tx.js +36 -0
- package/src/web3/createSimulateMessage.js +3 -2
- package/src/web3/createSimulateTransactions.js +11 -0
- package/src/web3/index.js +3 -1
- package/src/etherscan/account.js +0 -49
- package/src/etherscan/index.js +0 -28
- package/src/etherscan/logs.js +0 -16
- package/src/etherscan/proxy.js +0 -47
- package/src/etherscan/request.js +0 -26
- package/src/etherscan/ws.js +0 -88
- package/src/exodus-eth-server/server-factory.js +0 -28
- package/src/exodus-eth-server/server-map.js +0 -21
- package/src/get-fee-async.js +0 -97
- package/src/staking/matic/service.js +0 -437
- package/src/staking-api.js +0 -5
- package/src/tx-log/clarity-utils/get-derive-data-needed-for-tick.js +0 -12
- package/src/tx-log-staking-processor/get-asset-tx-amount.js +0 -26
- package/src/tx-send/get-fee-info.js +0 -41
- package/src/websocket/index.android.js +0 -2
- package/src/websocket/index.ios.js +0 -2
- package/src/websocket/index.js +0 -21
package/src/create-asset.js
CHANGED
|
@@ -1,43 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { ClarityMonitor } from './tx-log/clarity-monitor'
|
|
6
|
-
import { EthereumNoHistoryMonitor } from './tx-log/ethereum-no-history-monitor'
|
|
7
|
-
import { EthereumMonitor } from './tx-log/ethereum-monitor'
|
|
8
|
-
|
|
9
|
-
import { createEvmServer } from './exodus-eth-server/server-factory'
|
|
10
|
-
|
|
1
|
+
import { mapValues } from '@exodus/basic-utils'
|
|
2
|
+
import { createConsoleLogger } from '@exodus/asset-lib'
|
|
3
|
+
import { ASSET_FAMILY, connectAssetsList } from '@exodus/assets'
|
|
4
|
+
import bip44Constants from '@exodus/bip44-constants/by-ticker.js'
|
|
11
5
|
import {
|
|
12
6
|
createEthereumLikeAccountState,
|
|
13
7
|
createGetKeyIdentifier as defaultCreateGetKeyIdentifier,
|
|
8
|
+
createUnsignedTxFactory,
|
|
9
|
+
DEFAULT_FEE_MONITOR_INTERVAL,
|
|
14
10
|
encodePrivate,
|
|
15
11
|
encodePublicFactory,
|
|
12
|
+
getActivityTxs,
|
|
16
13
|
hasChecksum,
|
|
17
|
-
|
|
18
|
-
signUnsignedTxWithSigner,
|
|
14
|
+
signHardwareFactory,
|
|
19
15
|
signMessage,
|
|
20
16
|
signMessageWithSigner,
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
signUnsignedTx,
|
|
18
|
+
signUnsignedTxWithSigner,
|
|
23
19
|
validateFactory,
|
|
24
|
-
createUnsignedTxFactory,
|
|
25
20
|
} from '@exodus/ethereum-lib'
|
|
21
|
+
import { toChecksumAddress } from '@exodus/ethereumjs/util'
|
|
26
22
|
import assert from 'minimalistic-assert'
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
import
|
|
23
|
+
|
|
24
|
+
import { addressHasHistoryFactory } from './address-has-history.js'
|
|
25
|
+
import { createAssessTransaction } from './check-tx/create-assess-transaction.js'
|
|
26
|
+
import { createCheckTx } from './check-tx/index.js'
|
|
27
|
+
import {
|
|
28
|
+
createGetBlackListStatus,
|
|
29
|
+
createHistoryMonitorFactory,
|
|
30
|
+
createRpcRequestAccumulatorFactory,
|
|
31
|
+
createSecurityChecks,
|
|
32
|
+
createTransactionPrivacyFactory,
|
|
33
|
+
getNonceFactory,
|
|
34
|
+
resolveMonitorSettings,
|
|
35
|
+
} from './create-asset-utils.js'
|
|
36
|
+
import { createTokenFactory } from './create-token-factory.js'
|
|
37
|
+
import { createCustomFeesApi } from './custom-fees.js'
|
|
38
|
+
import { createEip7702Whitelist } from './eip7702-whitelist.js'
|
|
39
|
+
import { getEIP7702Delegation, getIsNftContract } from './eth-like-util.js'
|
|
40
|
+
import { createEvmServer } from './exodus-eth-server/index.js'
|
|
41
|
+
import { createFeeData } from './fee-data/index.js'
|
|
42
|
+
import { createGetBalanceForAddress } from './get-balance-for-address.js'
|
|
43
|
+
import { getBalancesFactory } from './get-balances.js'
|
|
44
|
+
import { getFeeFactory } from './get-fee.js'
|
|
45
|
+
import { getHistoricalBalanceFactory } from './get-historical-balance.js'
|
|
46
|
+
import { moveFundsFactory } from './move-funds.js'
|
|
47
|
+
import { createEncodeMultisigContract } from './multisig-address.js'
|
|
48
|
+
import { estimateL1DataFeeFactory, getL1GetFeeFactory } from './optimism-gas/index.js'
|
|
49
|
+
import { createSendValidations } from './send-validations.js'
|
|
50
|
+
import { serverBasedFeeMonitorFactoryFactory } from './server-based-fee-monitor.js'
|
|
51
|
+
import { stakingApiFactory } from './staking/api/index.js'
|
|
52
|
+
import { createTxFactory } from './tx-create.js'
|
|
53
|
+
import { txSendFactory } from './tx-send/index.js'
|
|
54
|
+
import { createWeb3API } from './web3/index.js'
|
|
41
55
|
|
|
42
56
|
export const createAssetFactory = ({
|
|
43
57
|
AccountState: CustomAccountState,
|
|
@@ -45,27 +59,43 @@ export const createAssetFactory = ({
|
|
|
45
59
|
confirmationsNumber,
|
|
46
60
|
customBip44,
|
|
47
61
|
customCreateGetKeyIdentifier,
|
|
48
|
-
customTokens = true,
|
|
62
|
+
customTokens: defaultCustomTokens = true,
|
|
49
63
|
erc20FuelBuffer,
|
|
50
|
-
feeData,
|
|
64
|
+
feeData: providedFeeData,
|
|
65
|
+
feeDataConfig,
|
|
51
66
|
feeMonitorInterval,
|
|
52
67
|
fuelThreshold,
|
|
53
68
|
isMaxFeeAsset = false,
|
|
54
69
|
isTestnet = false,
|
|
55
70
|
l1GasOracleAddress, // l1 extra fee for base and optostakingConfiguration = {},
|
|
56
|
-
monitorInterval,
|
|
57
|
-
monitorType = 'magnifier',
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
monitorInterval: defaultMonitorInterval,
|
|
72
|
+
monitorType: defaultMonitorType = 'magnifier',
|
|
73
|
+
multicall3Address: defaultMulticall3Address,
|
|
74
|
+
nfts: defaultNfts = false,
|
|
75
|
+
serverUrl: defaultServerUrl,
|
|
76
|
+
stakingConfiguration = Object.create(null),
|
|
77
|
+
stakingDependencies = Object.create(null),
|
|
61
78
|
useEip1191ChainIdChecksum = false,
|
|
79
|
+
forceGasLimitEstimation = false,
|
|
80
|
+
rpcBalanceAssetNames = [],
|
|
81
|
+
blacklistChecks = [],
|
|
82
|
+
supportsCustomFees: defaultSupportsCustomFees = false,
|
|
83
|
+
useAbsoluteBalanceAndNonce = false,
|
|
84
|
+
delisted = false,
|
|
85
|
+
supportsTransactionPrivacy: defaultSupportsTransactionPrivacy,
|
|
86
|
+
wsGatewayUri: defaultWsGatewayUri,
|
|
87
|
+
eip7623Supported = false,
|
|
88
|
+
eip7702Supported,
|
|
89
|
+
transactionAssessment: defaultTransactionAssessment,
|
|
62
90
|
}) => {
|
|
63
91
|
assert(assetsList, 'assetsList is required')
|
|
64
|
-
assert(
|
|
65
|
-
assert(
|
|
92
|
+
assert(providedFeeData || feeDataConfig, 'feeData or feeDataConfig is required')
|
|
93
|
+
assert(defaultServerUrl, 'serverUrl is required')
|
|
66
94
|
assert(confirmationsNumber, 'confirmationsNumber is required')
|
|
67
95
|
|
|
68
96
|
const base = assetsList.find((asset) => asset.name === asset.baseAssetName)
|
|
97
|
+
|
|
98
|
+
const feeData = providedFeeData || createFeeData({ currency: base.currency, feeDataConfig })
|
|
69
99
|
assert(base, 'base is required')
|
|
70
100
|
|
|
71
101
|
const chainId = base.chainId
|
|
@@ -73,32 +103,66 @@ export const createAssetFactory = ({
|
|
|
73
103
|
|
|
74
104
|
const createGetKeyIdentifier = customCreateGetKeyIdentifier || defaultCreateGetKeyIdentifier
|
|
75
105
|
|
|
106
|
+
const defaultConfig = {
|
|
107
|
+
allowMetaMaskCompat: false,
|
|
108
|
+
supportsStaking: false,
|
|
109
|
+
supportsCustomFees: defaultSupportsCustomFees,
|
|
110
|
+
nfts: defaultNfts,
|
|
111
|
+
customTokens: defaultCustomTokens,
|
|
112
|
+
supportsTransactionPrivacy: defaultSupportsTransactionPrivacy,
|
|
113
|
+
transactionAssessment: defaultTransactionAssessment,
|
|
114
|
+
multicall3Address: defaultMulticall3Address,
|
|
115
|
+
}
|
|
76
116
|
return (
|
|
77
117
|
{
|
|
78
118
|
assetClientInterface,
|
|
79
|
-
config =
|
|
80
|
-
allowMetaMaskCompat: false,
|
|
81
|
-
supportsStaking: false,
|
|
82
|
-
},
|
|
119
|
+
config = Object.create(null),
|
|
83
120
|
overrideCallback = ({ asset }) => asset,
|
|
84
121
|
} = Object.create(null)
|
|
85
122
|
) => {
|
|
86
123
|
const assets = connectAssetsList(assetsList)
|
|
87
124
|
|
|
88
|
-
const {
|
|
125
|
+
const configWithOverrides = { ...defaultConfig, ...config }
|
|
126
|
+
|
|
127
|
+
const {
|
|
128
|
+
allowMetaMaskCompat,
|
|
129
|
+
supportsStaking,
|
|
130
|
+
nfts,
|
|
131
|
+
customTokens,
|
|
132
|
+
supportsCustomFees,
|
|
133
|
+
useAbsoluteBalanceAndNonce: overrideUseAbsoluteBalanceAndNonce,
|
|
134
|
+
supportsTransactionPrivacy,
|
|
135
|
+
transactionAssessment,
|
|
136
|
+
multicall3Address,
|
|
137
|
+
} = configWithOverrides
|
|
89
138
|
|
|
90
139
|
const asset = assets[base.name]
|
|
91
140
|
|
|
92
|
-
const
|
|
141
|
+
const { monitorType, serverUrl, monitorInterval } = resolveMonitorSettings({
|
|
142
|
+
asset,
|
|
143
|
+
configWithOverrides,
|
|
144
|
+
defaultMonitorInterval,
|
|
145
|
+
defaultMonitorType,
|
|
146
|
+
defaultServerUrl,
|
|
147
|
+
defaultWsGatewayUri,
|
|
148
|
+
})
|
|
93
149
|
|
|
94
|
-
|
|
150
|
+
if (overrideUseAbsoluteBalanceAndNonce !== undefined) {
|
|
151
|
+
useAbsoluteBalanceAndNonce = overrideUseAbsoluteBalanceAndNonce
|
|
152
|
+
}
|
|
95
153
|
|
|
96
|
-
const
|
|
154
|
+
const server = createEvmServer({
|
|
155
|
+
assetName: asset.name,
|
|
156
|
+
serverUrl,
|
|
157
|
+
monitorType,
|
|
158
|
+
})
|
|
97
159
|
|
|
98
160
|
const address = {
|
|
99
161
|
validate: validateFactory({ chainId, useEip1191ChainIdChecksum }),
|
|
100
162
|
hasChecksum,
|
|
101
163
|
isContract: server.isContract,
|
|
164
|
+
displayAddress: (addr) =>
|
|
165
|
+
useEip1191ChainIdChecksum ? toChecksumAddress(addr, chainId) : toChecksumAddress(addr),
|
|
102
166
|
}
|
|
103
167
|
|
|
104
168
|
const bip44 = customBip44 || bip44Constants['ETH']
|
|
@@ -108,36 +172,88 @@ export const createAssetFactory = ({
|
|
|
108
172
|
encodePublic: encodePublicFactory({ chainId, useEip1191ChainIdChecksum }),
|
|
109
173
|
}
|
|
110
174
|
|
|
111
|
-
|
|
175
|
+
// The Safe 4337 contract constants baked into the derivation are chainId 1 specific
|
|
176
|
+
const encodeMultisigContract =
|
|
177
|
+
chainId === 1
|
|
178
|
+
? createEncodeMultisigContract({ chainId, encodePublic: keys.encodePublic })
|
|
179
|
+
: undefined
|
|
180
|
+
|
|
181
|
+
const getBalances = getBalancesFactory({
|
|
182
|
+
monitorType,
|
|
183
|
+
useAbsoluteBalance: useAbsoluteBalanceAndNonce,
|
|
184
|
+
rpcBalanceAssetNames,
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
const historicalBalanceSupported = monitorType !== 'no-history'
|
|
188
|
+
const getHistoricalBalance = getHistoricalBalanceFactory({
|
|
189
|
+
assetClientInterface,
|
|
190
|
+
getBalances,
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
const createRpcRequestAccumulator = createRpcRequestAccumulatorFactory({
|
|
194
|
+
multicall3Address,
|
|
195
|
+
})
|
|
112
196
|
|
|
113
197
|
const { createToken, getTokens } = createTokenFactory(
|
|
114
|
-
{
|
|
198
|
+
{
|
|
199
|
+
address,
|
|
200
|
+
bip44,
|
|
201
|
+
keys,
|
|
202
|
+
getBalances,
|
|
203
|
+
getHistoricalBalance,
|
|
204
|
+
historicalBalance: historicalBalanceSupported,
|
|
205
|
+
assetClientInterface,
|
|
206
|
+
server,
|
|
207
|
+
stakingConfiguration,
|
|
208
|
+
stakingDependencies,
|
|
209
|
+
createRpcRequestAccumulator,
|
|
210
|
+
},
|
|
115
211
|
assets
|
|
116
212
|
)
|
|
117
213
|
|
|
118
214
|
const addressHasHistory = addressHasHistoryFactory({ server })
|
|
119
215
|
|
|
120
|
-
const
|
|
216
|
+
const isWebSocket = monitorType !== 'no-history'
|
|
217
|
+
|
|
218
|
+
const resolvedFeeMonitorInterval =
|
|
219
|
+
config.feeMonitorInterval ||
|
|
220
|
+
feeMonitorInterval ||
|
|
221
|
+
(isWebSocket ? null : DEFAULT_FEE_MONITOR_INTERVAL) // null means do not start the timer
|
|
121
222
|
|
|
122
223
|
const createFeeMonitor = serverBasedFeeMonitorFactoryFactory({
|
|
123
|
-
|
|
124
|
-
interval:
|
|
125
|
-
|
|
224
|
+
asset: base,
|
|
225
|
+
interval: resolvedFeeMonitorInterval,
|
|
226
|
+
aci: assetClientInterface,
|
|
126
227
|
server,
|
|
127
228
|
})
|
|
128
229
|
|
|
230
|
+
const { broadcastPrivateBundle, broadcastPrivateTx, sendPrivateTx, sendPrivateBundle } =
|
|
231
|
+
createTransactionPrivacyFactory({
|
|
232
|
+
assetClientInterface,
|
|
233
|
+
assetName: asset.name,
|
|
234
|
+
server,
|
|
235
|
+
supportsTransactionPrivacy,
|
|
236
|
+
})
|
|
237
|
+
|
|
129
238
|
const features = {
|
|
130
239
|
accountState: true,
|
|
131
240
|
customTokens,
|
|
132
|
-
|
|
241
|
+
family: ASSET_FAMILY.EVM,
|
|
242
|
+
feeMonitor: true,
|
|
133
243
|
feesApi: true,
|
|
244
|
+
historicalBalance: historicalBalanceSupported,
|
|
134
245
|
isMaxFeeAsset,
|
|
135
246
|
isTestnet,
|
|
247
|
+
moveFunds: true,
|
|
248
|
+
multisig: Boolean(encodeMultisigContract),
|
|
136
249
|
nfts,
|
|
137
250
|
noHistory: monitorType === 'no-history',
|
|
138
251
|
signWithSigner: true,
|
|
139
252
|
signMessageWithSigner: true,
|
|
253
|
+
supportsCustomFees,
|
|
254
|
+
supportsTransactionPrivacy: Boolean(supportsTransactionPrivacy),
|
|
140
255
|
...(supportsStaking && { staking: {} }),
|
|
256
|
+
...(delisted && { delisted }),
|
|
141
257
|
}
|
|
142
258
|
|
|
143
259
|
const stakingAssetNames = Object.keys(stakingConfiguration)
|
|
@@ -145,6 +261,8 @@ export const createAssetFactory = ({
|
|
|
145
261
|
const extraData =
|
|
146
262
|
stakingAssetNames.length > 0
|
|
147
263
|
? {
|
|
264
|
+
// Persist ownership independently of host annotations and balances.
|
|
265
|
+
stakingSnapshotOwners: {},
|
|
148
266
|
staking: mapValues(
|
|
149
267
|
stakingConfiguration,
|
|
150
268
|
(assetStakinConfiguration) => assetStakinConfiguration.accountStateExtraData
|
|
@@ -152,76 +270,102 @@ export const createAssetFactory = ({
|
|
|
152
270
|
}
|
|
153
271
|
: undefined
|
|
154
272
|
|
|
273
|
+
const getBlackListStatus = createGetBlackListStatus({ server, address, blacklistChecks })
|
|
274
|
+
|
|
275
|
+
// eip7702Supported is the chain-level feature flag ([] when supported).
|
|
276
|
+
// The whitelist itself is populated from remote config through the
|
|
277
|
+
// history monitor's setServer.
|
|
278
|
+
const eip7702Whitelist = createEip7702Whitelist(eip7702Supported)
|
|
279
|
+
|
|
155
280
|
const accountStateClass =
|
|
156
281
|
CustomAccountState || createEthereumLikeAccountState({ asset: base, assets, extraData })
|
|
157
282
|
|
|
158
|
-
const createHistoryMonitor = (
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
})
|
|
170
|
-
break
|
|
171
|
-
case 'magnifier':
|
|
172
|
-
monitor = new EthereumMonitor({ interval: ms(monitorInterval || '15s'), server, ...args })
|
|
173
|
-
break
|
|
174
|
-
default:
|
|
175
|
-
throw new Error(`Monitor type ${monitorType} of evm asset ${asset.name} is unknown`)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (stakingAssetNames.length > 0) {
|
|
179
|
-
const afterTickHook = createEthereumHooks({
|
|
180
|
-
assetClientInterface,
|
|
181
|
-
assetName: asset.name,
|
|
182
|
-
stakingAssetNames,
|
|
183
|
-
server,
|
|
184
|
-
})['after-tick']
|
|
185
|
-
monitor.addHook('after-tick', afterTickHook)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return monitor
|
|
189
|
-
}
|
|
283
|
+
const createHistoryMonitor = createHistoryMonitorFactory({
|
|
284
|
+
assetName: asset.name,
|
|
285
|
+
assetClientInterface,
|
|
286
|
+
monitorInterval,
|
|
287
|
+
monitorType,
|
|
288
|
+
server,
|
|
289
|
+
stakingConfiguration,
|
|
290
|
+
rpcBalanceAssetNames,
|
|
291
|
+
eip7702Whitelist,
|
|
292
|
+
getBlackListStatus,
|
|
293
|
+
})
|
|
190
294
|
|
|
191
295
|
const defaultAddressPath = 'm/0/0'
|
|
192
296
|
|
|
193
297
|
const createUnsignedTx = createUnsignedTxFactory({ chainId })
|
|
194
298
|
|
|
299
|
+
const createTx = createTxFactory({
|
|
300
|
+
chainId,
|
|
301
|
+
assetClientInterface,
|
|
302
|
+
useAbsoluteNonce: useAbsoluteBalanceAndNonce,
|
|
303
|
+
})
|
|
304
|
+
|
|
195
305
|
const sendTx = txSendFactory({
|
|
196
306
|
assetClientInterface,
|
|
197
|
-
|
|
307
|
+
createTx,
|
|
198
308
|
})
|
|
199
309
|
|
|
310
|
+
const getFeeAsync = async (...args) => {
|
|
311
|
+
const { unsignedTx, amount, ...rest } = await createTx(...args)
|
|
312
|
+
return rest
|
|
313
|
+
}
|
|
314
|
+
|
|
200
315
|
const estimateL1DataFee = l1GasOracleAddress
|
|
201
316
|
? estimateL1DataFeeFactory({ l1GasOracleAddress, server })
|
|
202
317
|
: undefined
|
|
203
318
|
|
|
204
|
-
const originalGetFee = getFeeFactory(
|
|
319
|
+
const originalGetFee = getFeeFactory()
|
|
205
320
|
|
|
206
321
|
const getFee = l1GasOracleAddress
|
|
207
322
|
? getL1GetFeeFactory({ asset, originalGetFee })
|
|
208
323
|
: originalGetFee
|
|
209
324
|
|
|
325
|
+
const { getNonce } = getNonceFactory({ assetClientInterface, useAbsoluteBalanceAndNonce })
|
|
326
|
+
|
|
327
|
+
const securityChecks = createSecurityChecks({ eip7702Whitelist })
|
|
328
|
+
|
|
329
|
+
const web3 = createWeb3API({ asset })
|
|
330
|
+
|
|
331
|
+
let checkTx
|
|
332
|
+
let sendValidations = []
|
|
333
|
+
if (transactionAssessment?.enabled) {
|
|
334
|
+
checkTx = createCheckTx({
|
|
335
|
+
makeApiCall: createAssessTransaction({ apiUrl: transactionAssessment.apiUrl }),
|
|
336
|
+
logger: createConsoleLogger('@exodus/ethereum-api:check-tx'),
|
|
337
|
+
})
|
|
338
|
+
sendValidations = createSendValidations({ assetClientInterface, checkTx })
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const moveFunds = moveFundsFactory({
|
|
342
|
+
baseAssetName: asset.name,
|
|
343
|
+
assetClientInterface,
|
|
344
|
+
createTx,
|
|
345
|
+
server,
|
|
346
|
+
})
|
|
347
|
+
|
|
210
348
|
const api = {
|
|
211
349
|
addressHasHistory,
|
|
212
350
|
broadcastTx: (...args) => server.sendRawTransaction(...args),
|
|
213
351
|
createAccountState: () => accountStateClass,
|
|
352
|
+
securityChecks,
|
|
214
353
|
createFeeMonitor,
|
|
215
354
|
createHistoryMonitor,
|
|
216
355
|
createToken,
|
|
217
|
-
|
|
356
|
+
createTx,
|
|
357
|
+
createUnsignedTx, // @deprecated use createTx instead
|
|
358
|
+
customFees: createCustomFeesApi({ baseAsset: asset }),
|
|
218
359
|
defaultAddressPath,
|
|
219
360
|
features,
|
|
361
|
+
getActivityTxs,
|
|
220
362
|
getBalances,
|
|
363
|
+
...(features.historicalBalance && { getHistoricalBalance }),
|
|
221
364
|
getBalanceForAddress: createGetBalanceForAddress({ asset, server }),
|
|
365
|
+
...(getBlackListStatus && { getBlackListStatus }),
|
|
222
366
|
getConfirmationsNumber: () => confirmationsNumber,
|
|
223
367
|
getDefaultAddressPath: () => defaultAddressPath,
|
|
224
|
-
getFeeAsync
|
|
368
|
+
getFeeAsync, // createTx alias, remove me when possible
|
|
225
369
|
getFee,
|
|
226
370
|
getFeeData: () => feeData,
|
|
227
371
|
getKeyIdentifier: createGetKeyIdentifier({
|
|
@@ -230,38 +374,69 @@ export const createAssetFactory = ({
|
|
|
230
374
|
assetName: asset.name,
|
|
231
375
|
}),
|
|
232
376
|
getSupportedPurposes: () => [44],
|
|
377
|
+
...(sendValidations.length > 0 && { getSendValidations: () => sendValidations }),
|
|
233
378
|
getTokens,
|
|
234
379
|
hasFeature: (feature) => !!features[feature], // @deprecated use api.features instead
|
|
380
|
+
moveFunds,
|
|
381
|
+
privateKeyEncodingDefinition: { encoding: 'hex' },
|
|
235
382
|
sendTx,
|
|
236
383
|
signTx: ({ unsignedTx, privateKey, signer }) =>
|
|
237
384
|
signer
|
|
238
385
|
? signUnsignedTxWithSigner(unsignedTx, signer)
|
|
239
386
|
: signUnsignedTx(unsignedTx, privateKey),
|
|
240
|
-
signHardware: signHardwareFactory({
|
|
387
|
+
signHardware: signHardwareFactory({
|
|
388
|
+
baseAssetName: asset.name,
|
|
389
|
+
getIsNft: ({ address }) => getIsNftContract({ server, address }),
|
|
390
|
+
}),
|
|
241
391
|
signMessage: ({ message, privateKey, signer }) =>
|
|
242
392
|
signer ? signMessageWithSigner({ message, signer }) : signMessage({ privateKey, message }),
|
|
243
|
-
...(
|
|
393
|
+
...(checkTx && { checkTx }),
|
|
394
|
+
...(supportsStaking &&
|
|
395
|
+
stakingDependencies[asset.name] && {
|
|
396
|
+
staking: stakingApiFactory({
|
|
397
|
+
assetName: asset.name,
|
|
398
|
+
currency: asset.currency,
|
|
399
|
+
assetClientInterface,
|
|
400
|
+
server,
|
|
401
|
+
stakingConfiguration: stakingConfiguration[asset.name],
|
|
402
|
+
stakingDependencies: stakingDependencies[asset.name],
|
|
403
|
+
}),
|
|
404
|
+
}),
|
|
244
405
|
validateAssetId: address.validate,
|
|
245
|
-
web3
|
|
406
|
+
web3,
|
|
246
407
|
}
|
|
247
408
|
|
|
248
409
|
const fullAsset = {
|
|
249
410
|
...asset,
|
|
250
|
-
...pick(config, ['accountReserve']),
|
|
251
|
-
gasLimit,
|
|
252
|
-
contractGasLimit,
|
|
253
411
|
bip44,
|
|
254
412
|
keys,
|
|
255
413
|
address,
|
|
256
414
|
api,
|
|
257
415
|
chainId,
|
|
416
|
+
...(encodeMultisigContract && { encodeMultisigContract }),
|
|
258
417
|
monitorType,
|
|
259
418
|
estimateL1DataFee,
|
|
419
|
+
forceGasLimitEstimation,
|
|
420
|
+
eip7623Supported,
|
|
421
|
+
// Stable array reference kept up to date with remote config by the
|
|
422
|
+
// history monitor's setServer.
|
|
423
|
+
eip7702Supported: eip7702Whitelist.get(),
|
|
424
|
+
getEIP7702Delegation: (addr) => getEIP7702Delegation({ address: addr, server }),
|
|
425
|
+
getNonce,
|
|
260
426
|
server,
|
|
261
427
|
...(erc20FuelBuffer && { erc20FuelBuffer }),
|
|
262
428
|
...(fuelThreshold && { fuelThreshold: asset.currency.defaultUnit(fuelThreshold) }),
|
|
263
|
-
|
|
429
|
+
broadcastPrivateBundle,
|
|
430
|
+
broadcastPrivateTx,
|
|
431
|
+
createRpcRequestAccumulator,
|
|
432
|
+
sendPrivateTx,
|
|
433
|
+
sendPrivateBundle,
|
|
264
434
|
}
|
|
265
|
-
return overrideCallback({
|
|
435
|
+
return overrideCallback({
|
|
436
|
+
asset: fullAsset,
|
|
437
|
+
stakingConfiguration,
|
|
438
|
+
assetClientInterface,
|
|
439
|
+
monitorInterval,
|
|
440
|
+
})
|
|
266
441
|
}
|
|
267
442
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ASSET_FAMILY } from '@exodus/assets'
|
|
2
2
|
import { createContract } from '@exodus/ethereum-lib'
|
|
3
|
-
|
|
4
|
-
import { createStakingApi } from './staking-api'
|
|
5
3
|
import assert from 'minimalistic-assert'
|
|
6
4
|
|
|
5
|
+
import { stakingApiFactory } from './staking/api/index.js'
|
|
6
|
+
import {
|
|
7
|
+
isPolygonClaimUndelegate,
|
|
8
|
+
isPolygonDelegate,
|
|
9
|
+
isPolygonUndelegate,
|
|
10
|
+
} from './staking/matic/index.js'
|
|
11
|
+
|
|
7
12
|
const defaultTokenFeatures = {
|
|
13
|
+
family: ASSET_FAMILY.EVM,
|
|
8
14
|
isMaxFeeAsset: true,
|
|
9
15
|
}
|
|
10
16
|
|
|
@@ -29,31 +35,55 @@ const getPolygonActivityTxs = ({ txs }) =>
|
|
|
29
35
|
const getActivityTxs = ({ txs }) => txs.filter((tx) => !smallbalanceTx(tx))
|
|
30
36
|
|
|
31
37
|
const getCreateBaseToken =
|
|
32
|
-
({
|
|
38
|
+
({
|
|
39
|
+
getBalances,
|
|
40
|
+
getHistoricalBalance,
|
|
41
|
+
historicalBalance,
|
|
42
|
+
assetClientInterface,
|
|
43
|
+
server,
|
|
44
|
+
stakingConfiguration = Object.create(null),
|
|
45
|
+
stakingDependencies = Object.create(null),
|
|
46
|
+
createRpcRequestAccumulator,
|
|
47
|
+
...props
|
|
48
|
+
}) =>
|
|
33
49
|
({ name, contract, features, ...tokenDef }) => {
|
|
34
50
|
assert(getBalances, 'getBalances is required')
|
|
35
51
|
const tokenSpecificFeatures = name === 'polygon' ? { staking: {} } : {}
|
|
36
|
-
const tokenSpecificApiFunctions =
|
|
37
|
-
name === 'polygon' ? { staking: createStakingApi({ network: name }) } : {}
|
|
38
52
|
|
|
39
53
|
const tokenFeatures = { ...defaultTokenFeatures, ...features, ...tokenSpecificFeatures }
|
|
40
|
-
|
|
54
|
+
const baseApi = {
|
|
55
|
+
getActivityTxs: name === 'polygon' ? getPolygonActivityTxs : getActivityTxs,
|
|
56
|
+
features: tokenFeatures,
|
|
57
|
+
hasFeature: (feature) => !!tokenFeatures[feature], // @deprecated use api.features instead
|
|
58
|
+
getBalances,
|
|
59
|
+
...(historicalBalance && { getHistoricalBalance }),
|
|
60
|
+
getTxLogFilter: name === 'polygon' ? getPolygonTxLogFilter : getTxLogFilter,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const tokenAsset = {
|
|
41
64
|
...tokenDef,
|
|
42
65
|
addresses: contract,
|
|
43
|
-
assetId: contract.current,
|
|
66
|
+
assetId: contract.current.toLowerCase(),
|
|
44
67
|
contract: createContract(contract.current, name),
|
|
45
68
|
gasLimit: 120_000,
|
|
46
69
|
name,
|
|
47
|
-
api:
|
|
48
|
-
|
|
49
|
-
features: tokenFeatures,
|
|
50
|
-
hasFeature: (feature) => !!tokenFeatures[feature], // @deprecated use api.features instead
|
|
51
|
-
getBalances,
|
|
52
|
-
getTxLogFilter: name === 'polygon' ? getPolygonTxLogFilter : getTxLogFilter,
|
|
53
|
-
...tokenSpecificApiFunctions,
|
|
54
|
-
},
|
|
55
|
-
...props, // override props above, add new props
|
|
70
|
+
api: baseApi,
|
|
71
|
+
...props,
|
|
56
72
|
}
|
|
73
|
+
|
|
74
|
+
if (name === 'polygon' && stakingDependencies[name]) {
|
|
75
|
+
baseApi.staking = stakingApiFactory({
|
|
76
|
+
assetName: tokenAsset.name,
|
|
77
|
+
currency: tokenAsset.currency,
|
|
78
|
+
assetClientInterface,
|
|
79
|
+
server,
|
|
80
|
+
stakingConfiguration: stakingConfiguration[name],
|
|
81
|
+
stakingDependencies: stakingDependencies[name],
|
|
82
|
+
createRpcRequestAccumulator,
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return tokenAsset
|
|
57
87
|
}
|
|
58
88
|
|
|
59
89
|
export const createTokenFactory = (props, assets) => {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import NumberUnit from '@exodus/currency'
|
|
2
|
+
|
|
3
|
+
import { resolveGasPrice } from './fee-utils.js'
|
|
4
|
+
|
|
5
|
+
const calculateMinCustomFee = ({ feeData }) => {
|
|
6
|
+
const { eip1559Enabled, baseFeePerGas, gasPriceMinimumRate } = feeData
|
|
7
|
+
|
|
8
|
+
// On `eip1559Enabled` networks, the `baseFeePerGas` is
|
|
9
|
+
// the minimum a transaction should be sent using, else
|
|
10
|
+
// get rejected by the RPC.
|
|
11
|
+
if (eip1559Enabled && baseFeePerGas) return baseFeePerGas.mul(Math.max(gasPriceMinimumRate, 1))
|
|
12
|
+
|
|
13
|
+
// On legacy networks, senders are permitted to send
|
|
14
|
+
// transactions below the `baseFeePerGas` (since these
|
|
15
|
+
// would not be rejected by the RPC - in fact, it was
|
|
16
|
+
// even possible to mine transactions with a `gasPrice`
|
|
17
|
+
// of `0`!).
|
|
18
|
+
return resolveGasPrice({ feeData }).mul(gasPriceMinimumRate)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const calculateRecommendedCustomFee = ({ min, feeData }) => {
|
|
22
|
+
const recommended = resolveGasPrice({ feeData })
|
|
23
|
+
// The `recommended` fee must be at least the `min`.
|
|
24
|
+
return recommended.gt(min) ? recommended : min
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const calculateMaxCustomFee = ({ feeData, recommended }) => {
|
|
28
|
+
const { gasPriceMinimumRate, gasPriceMaximumRate } = feeData
|
|
29
|
+
|
|
30
|
+
const maxGasPrice = resolveGasPrice({ feeData }).mul(
|
|
31
|
+
Math.max(gasPriceMaximumRate, gasPriceMinimumRate)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
// When calculating the `max` custom fee, the returned fee
|
|
35
|
+
// must be at least the `recommended` price.
|
|
36
|
+
return recommended.gt(maxGasPrice) ? recommended : maxGasPrice
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const createCustomFeesApi = ({ baseAsset }) => {
|
|
40
|
+
const Gwei = baseAsset.currency.units.Gwei
|
|
41
|
+
return {
|
|
42
|
+
getRecommendedMinMaxFeeUnitPrices: ({ feeData }) => {
|
|
43
|
+
const min = calculateMinCustomFee({ feeData })
|
|
44
|
+
const recommended = calculateRecommendedCustomFee({ feeData, min })
|
|
45
|
+
const max = calculateMaxCustomFee({ feeData, recommended })
|
|
46
|
+
return {
|
|
47
|
+
recommended: recommended.toNumber(Gwei),
|
|
48
|
+
min: min.toNumber(Gwei),
|
|
49
|
+
max: max.toNumber(Gwei),
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
unit: 'gwei/gas',
|
|
53
|
+
feeUnitPriceToNumber: (feeNumberUnit) => feeNumberUnit.toNumber(Gwei),
|
|
54
|
+
numberToFeeUnitPrice: (value) => NumberUnit.create(value, Gwei),
|
|
55
|
+
isEnabled: ({ feeData }) => Boolean(feeData.rbfEnabled),
|
|
56
|
+
}
|
|
57
|
+
}
|