@exodus/ethereum-api 9.0.0-alpha.3 → 9.0.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/CHANGELOG.md +2139 -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 +273 -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 +276 -103
- package/src/tx-log/clarity-truncated-history-monitor.js +130 -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,44 @@ 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
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
monitorInterval: defaultMonitorInterval,
|
|
72
|
+
monitorType: defaultMonitorType,
|
|
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')
|
|
94
|
+
assert(defaultMonitorType, 'monitorType is required')
|
|
66
95
|
assert(confirmationsNumber, 'confirmationsNumber is required')
|
|
67
96
|
|
|
68
97
|
const base = assetsList.find((asset) => asset.name === asset.baseAssetName)
|
|
98
|
+
|
|
99
|
+
const feeData = providedFeeData || createFeeData({ currency: base.currency, feeDataConfig })
|
|
69
100
|
assert(base, 'base is required')
|
|
70
101
|
|
|
71
102
|
const chainId = base.chainId
|
|
@@ -73,32 +104,66 @@ export const createAssetFactory = ({
|
|
|
73
104
|
|
|
74
105
|
const createGetKeyIdentifier = customCreateGetKeyIdentifier || defaultCreateGetKeyIdentifier
|
|
75
106
|
|
|
107
|
+
const defaultConfig = {
|
|
108
|
+
allowMetaMaskCompat: false,
|
|
109
|
+
supportsStaking: false,
|
|
110
|
+
supportsCustomFees: defaultSupportsCustomFees,
|
|
111
|
+
nfts: defaultNfts,
|
|
112
|
+
customTokens: defaultCustomTokens,
|
|
113
|
+
supportsTransactionPrivacy: defaultSupportsTransactionPrivacy,
|
|
114
|
+
transactionAssessment: defaultTransactionAssessment,
|
|
115
|
+
multicall3Address: defaultMulticall3Address,
|
|
116
|
+
}
|
|
76
117
|
return (
|
|
77
118
|
{
|
|
78
119
|
assetClientInterface,
|
|
79
|
-
config =
|
|
80
|
-
allowMetaMaskCompat: false,
|
|
81
|
-
supportsStaking: false,
|
|
82
|
-
},
|
|
120
|
+
config = Object.create(null),
|
|
83
121
|
overrideCallback = ({ asset }) => asset,
|
|
84
122
|
} = Object.create(null)
|
|
85
123
|
) => {
|
|
86
124
|
const assets = connectAssetsList(assetsList)
|
|
87
125
|
|
|
88
|
-
const {
|
|
126
|
+
const configWithOverrides = { ...defaultConfig, ...config }
|
|
127
|
+
|
|
128
|
+
const {
|
|
129
|
+
allowMetaMaskCompat,
|
|
130
|
+
supportsStaking,
|
|
131
|
+
nfts,
|
|
132
|
+
customTokens,
|
|
133
|
+
supportsCustomFees,
|
|
134
|
+
useAbsoluteBalanceAndNonce: overrideUseAbsoluteBalanceAndNonce,
|
|
135
|
+
supportsTransactionPrivacy,
|
|
136
|
+
transactionAssessment,
|
|
137
|
+
multicall3Address,
|
|
138
|
+
} = configWithOverrides
|
|
89
139
|
|
|
90
140
|
const asset = assets[base.name]
|
|
91
141
|
|
|
92
|
-
const
|
|
142
|
+
const { monitorType, serverUrl, monitorInterval } = resolveMonitorSettings({
|
|
143
|
+
asset,
|
|
144
|
+
configWithOverrides,
|
|
145
|
+
defaultMonitorInterval,
|
|
146
|
+
defaultMonitorType,
|
|
147
|
+
defaultServerUrl,
|
|
148
|
+
defaultWsGatewayUri,
|
|
149
|
+
})
|
|
93
150
|
|
|
94
|
-
|
|
151
|
+
if (overrideUseAbsoluteBalanceAndNonce !== undefined) {
|
|
152
|
+
useAbsoluteBalanceAndNonce = overrideUseAbsoluteBalanceAndNonce
|
|
153
|
+
}
|
|
95
154
|
|
|
96
|
-
const
|
|
155
|
+
const server = createEvmServer({
|
|
156
|
+
assetName: asset.name,
|
|
157
|
+
serverUrl,
|
|
158
|
+
monitorType,
|
|
159
|
+
})
|
|
97
160
|
|
|
98
161
|
const address = {
|
|
99
162
|
validate: validateFactory({ chainId, useEip1191ChainIdChecksum }),
|
|
100
163
|
hasChecksum,
|
|
101
164
|
isContract: server.isContract,
|
|
165
|
+
displayAddress: (addr) =>
|
|
166
|
+
useEip1191ChainIdChecksum ? toChecksumAddress(addr, chainId) : toChecksumAddress(addr),
|
|
102
167
|
}
|
|
103
168
|
|
|
104
169
|
const bip44 = customBip44 || bip44Constants['ETH']
|
|
@@ -108,36 +173,88 @@ export const createAssetFactory = ({
|
|
|
108
173
|
encodePublic: encodePublicFactory({ chainId, useEip1191ChainIdChecksum }),
|
|
109
174
|
}
|
|
110
175
|
|
|
111
|
-
|
|
176
|
+
// The Safe 4337 contract constants baked into the derivation are chainId 1 specific
|
|
177
|
+
const encodeMultisigContract =
|
|
178
|
+
chainId === 1
|
|
179
|
+
? createEncodeMultisigContract({ chainId, encodePublic: keys.encodePublic })
|
|
180
|
+
: undefined
|
|
181
|
+
|
|
182
|
+
const getBalances = getBalancesFactory({
|
|
183
|
+
monitorType,
|
|
184
|
+
useAbsoluteBalance: useAbsoluteBalanceAndNonce,
|
|
185
|
+
rpcBalanceAssetNames,
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
const historicalBalanceSupported = monitorType !== 'no-history'
|
|
189
|
+
const getHistoricalBalance = getHistoricalBalanceFactory({
|
|
190
|
+
assetClientInterface,
|
|
191
|
+
getBalances,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const createRpcRequestAccumulator = createRpcRequestAccumulatorFactory({
|
|
195
|
+
multicall3Address,
|
|
196
|
+
})
|
|
112
197
|
|
|
113
198
|
const { createToken, getTokens } = createTokenFactory(
|
|
114
|
-
{
|
|
199
|
+
{
|
|
200
|
+
address,
|
|
201
|
+
bip44,
|
|
202
|
+
keys,
|
|
203
|
+
getBalances,
|
|
204
|
+
getHistoricalBalance,
|
|
205
|
+
historicalBalance: historicalBalanceSupported,
|
|
206
|
+
assetClientInterface,
|
|
207
|
+
server,
|
|
208
|
+
stakingConfiguration,
|
|
209
|
+
stakingDependencies,
|
|
210
|
+
createRpcRequestAccumulator,
|
|
211
|
+
},
|
|
115
212
|
assets
|
|
116
213
|
)
|
|
117
214
|
|
|
118
215
|
const addressHasHistory = addressHasHistoryFactory({ server })
|
|
119
216
|
|
|
120
|
-
const
|
|
217
|
+
const isWebSocket = monitorType !== 'no-history'
|
|
218
|
+
|
|
219
|
+
const resolvedFeeMonitorInterval =
|
|
220
|
+
config.feeMonitorInterval ||
|
|
221
|
+
feeMonitorInterval ||
|
|
222
|
+
(isWebSocket ? null : DEFAULT_FEE_MONITOR_INTERVAL) // null means do not start the timer
|
|
121
223
|
|
|
122
224
|
const createFeeMonitor = serverBasedFeeMonitorFactoryFactory({
|
|
123
|
-
|
|
124
|
-
interval:
|
|
125
|
-
|
|
225
|
+
asset: base,
|
|
226
|
+
interval: resolvedFeeMonitorInterval,
|
|
227
|
+
aci: assetClientInterface,
|
|
126
228
|
server,
|
|
127
229
|
})
|
|
128
230
|
|
|
231
|
+
const { broadcastPrivateBundle, broadcastPrivateTx, sendPrivateTx, sendPrivateBundle } =
|
|
232
|
+
createTransactionPrivacyFactory({
|
|
233
|
+
assetClientInterface,
|
|
234
|
+
assetName: asset.name,
|
|
235
|
+
server,
|
|
236
|
+
supportsTransactionPrivacy,
|
|
237
|
+
})
|
|
238
|
+
|
|
129
239
|
const features = {
|
|
130
240
|
accountState: true,
|
|
131
241
|
customTokens,
|
|
132
|
-
|
|
242
|
+
family: ASSET_FAMILY.EVM,
|
|
243
|
+
feeMonitor: true,
|
|
133
244
|
feesApi: true,
|
|
245
|
+
historicalBalance: historicalBalanceSupported,
|
|
134
246
|
isMaxFeeAsset,
|
|
135
247
|
isTestnet,
|
|
248
|
+
moveFunds: true,
|
|
249
|
+
multisig: Boolean(encodeMultisigContract),
|
|
136
250
|
nfts,
|
|
137
251
|
noHistory: monitorType === 'no-history',
|
|
138
252
|
signWithSigner: true,
|
|
139
253
|
signMessageWithSigner: true,
|
|
254
|
+
supportsCustomFees,
|
|
255
|
+
supportsTransactionPrivacy: Boolean(supportsTransactionPrivacy),
|
|
140
256
|
...(supportsStaking && { staking: {} }),
|
|
257
|
+
...(delisted && { delisted }),
|
|
141
258
|
}
|
|
142
259
|
|
|
143
260
|
const stakingAssetNames = Object.keys(stakingConfiguration)
|
|
@@ -145,6 +262,8 @@ export const createAssetFactory = ({
|
|
|
145
262
|
const extraData =
|
|
146
263
|
stakingAssetNames.length > 0
|
|
147
264
|
? {
|
|
265
|
+
// Persist ownership independently of host annotations and balances.
|
|
266
|
+
stakingSnapshotOwners: {},
|
|
148
267
|
staking: mapValues(
|
|
149
268
|
stakingConfiguration,
|
|
150
269
|
(assetStakinConfiguration) => assetStakinConfiguration.accountStateExtraData
|
|
@@ -152,76 +271,102 @@ export const createAssetFactory = ({
|
|
|
152
271
|
}
|
|
153
272
|
: undefined
|
|
154
273
|
|
|
274
|
+
const getBlackListStatus = createGetBlackListStatus({ server, address, blacklistChecks })
|
|
275
|
+
|
|
276
|
+
// eip7702Supported is the chain-level feature flag ([] when supported).
|
|
277
|
+
// The whitelist itself is populated from remote config through the
|
|
278
|
+
// history monitor's setServer.
|
|
279
|
+
const eip7702Whitelist = createEip7702Whitelist(eip7702Supported)
|
|
280
|
+
|
|
155
281
|
const accountStateClass =
|
|
156
282
|
CustomAccountState || createEthereumLikeAccountState({ asset: base, assets, extraData })
|
|
157
283
|
|
|
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
|
-
}
|
|
284
|
+
const createHistoryMonitor = createHistoryMonitorFactory({
|
|
285
|
+
assetName: asset.name,
|
|
286
|
+
assetClientInterface,
|
|
287
|
+
monitorInterval,
|
|
288
|
+
monitorType,
|
|
289
|
+
server,
|
|
290
|
+
stakingConfiguration,
|
|
291
|
+
rpcBalanceAssetNames,
|
|
292
|
+
eip7702Whitelist,
|
|
293
|
+
getBlackListStatus,
|
|
294
|
+
})
|
|
190
295
|
|
|
191
296
|
const defaultAddressPath = 'm/0/0'
|
|
192
297
|
|
|
193
298
|
const createUnsignedTx = createUnsignedTxFactory({ chainId })
|
|
194
299
|
|
|
300
|
+
const createTx = createTxFactory({
|
|
301
|
+
chainId,
|
|
302
|
+
assetClientInterface,
|
|
303
|
+
useAbsoluteNonce: useAbsoluteBalanceAndNonce,
|
|
304
|
+
})
|
|
305
|
+
|
|
195
306
|
const sendTx = txSendFactory({
|
|
196
307
|
assetClientInterface,
|
|
197
|
-
|
|
308
|
+
createTx,
|
|
198
309
|
})
|
|
199
310
|
|
|
311
|
+
const getFeeAsync = async (...args) => {
|
|
312
|
+
const { unsignedTx, amount, ...rest } = await createTx(...args)
|
|
313
|
+
return rest
|
|
314
|
+
}
|
|
315
|
+
|
|
200
316
|
const estimateL1DataFee = l1GasOracleAddress
|
|
201
317
|
? estimateL1DataFeeFactory({ l1GasOracleAddress, server })
|
|
202
318
|
: undefined
|
|
203
319
|
|
|
204
|
-
const originalGetFee = getFeeFactory(
|
|
320
|
+
const originalGetFee = getFeeFactory()
|
|
205
321
|
|
|
206
322
|
const getFee = l1GasOracleAddress
|
|
207
323
|
? getL1GetFeeFactory({ asset, originalGetFee })
|
|
208
324
|
: originalGetFee
|
|
209
325
|
|
|
326
|
+
const { getNonce } = getNonceFactory({ assetClientInterface, useAbsoluteBalanceAndNonce })
|
|
327
|
+
|
|
328
|
+
const securityChecks = createSecurityChecks({ eip7702Whitelist })
|
|
329
|
+
|
|
330
|
+
const web3 = createWeb3API({ asset })
|
|
331
|
+
|
|
332
|
+
let checkTx
|
|
333
|
+
let sendValidations = []
|
|
334
|
+
if (transactionAssessment?.enabled) {
|
|
335
|
+
checkTx = createCheckTx({
|
|
336
|
+
makeApiCall: createAssessTransaction({ apiUrl: transactionAssessment.apiUrl }),
|
|
337
|
+
logger: createConsoleLogger('@exodus/ethereum-api:check-tx'),
|
|
338
|
+
})
|
|
339
|
+
sendValidations = createSendValidations({ assetClientInterface, checkTx })
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const moveFunds = moveFundsFactory({
|
|
343
|
+
baseAssetName: asset.name,
|
|
344
|
+
assetClientInterface,
|
|
345
|
+
createTx,
|
|
346
|
+
server,
|
|
347
|
+
})
|
|
348
|
+
|
|
210
349
|
const api = {
|
|
211
350
|
addressHasHistory,
|
|
212
351
|
broadcastTx: (...args) => server.sendRawTransaction(...args),
|
|
213
352
|
createAccountState: () => accountStateClass,
|
|
353
|
+
securityChecks,
|
|
214
354
|
createFeeMonitor,
|
|
215
355
|
createHistoryMonitor,
|
|
216
356
|
createToken,
|
|
217
|
-
|
|
357
|
+
createTx,
|
|
358
|
+
createUnsignedTx, // @deprecated use createTx instead
|
|
359
|
+
customFees: createCustomFeesApi({ baseAsset: asset }),
|
|
218
360
|
defaultAddressPath,
|
|
219
361
|
features,
|
|
362
|
+
getActivityTxs,
|
|
220
363
|
getBalances,
|
|
364
|
+
...(features.historicalBalance && { getHistoricalBalance }),
|
|
221
365
|
getBalanceForAddress: createGetBalanceForAddress({ asset, server }),
|
|
366
|
+
...(getBlackListStatus && { getBlackListStatus }),
|
|
222
367
|
getConfirmationsNumber: () => confirmationsNumber,
|
|
223
368
|
getDefaultAddressPath: () => defaultAddressPath,
|
|
224
|
-
getFeeAsync
|
|
369
|
+
getFeeAsync, // createTx alias, remove me when possible
|
|
225
370
|
getFee,
|
|
226
371
|
getFeeData: () => feeData,
|
|
227
372
|
getKeyIdentifier: createGetKeyIdentifier({
|
|
@@ -230,38 +375,69 @@ export const createAssetFactory = ({
|
|
|
230
375
|
assetName: asset.name,
|
|
231
376
|
}),
|
|
232
377
|
getSupportedPurposes: () => [44],
|
|
378
|
+
...(sendValidations.length > 0 && { getSendValidations: () => sendValidations }),
|
|
233
379
|
getTokens,
|
|
234
380
|
hasFeature: (feature) => !!features[feature], // @deprecated use api.features instead
|
|
381
|
+
moveFunds,
|
|
382
|
+
privateKeyEncodingDefinition: { encoding: 'hex' },
|
|
235
383
|
sendTx,
|
|
236
384
|
signTx: ({ unsignedTx, privateKey, signer }) =>
|
|
237
385
|
signer
|
|
238
386
|
? signUnsignedTxWithSigner(unsignedTx, signer)
|
|
239
387
|
: signUnsignedTx(unsignedTx, privateKey),
|
|
240
|
-
signHardware: signHardwareFactory({
|
|
388
|
+
signHardware: signHardwareFactory({
|
|
389
|
+
baseAssetName: asset.name,
|
|
390
|
+
getIsNft: ({ address }) => getIsNftContract({ server, address }),
|
|
391
|
+
}),
|
|
241
392
|
signMessage: ({ message, privateKey, signer }) =>
|
|
242
393
|
signer ? signMessageWithSigner({ message, signer }) : signMessage({ privateKey, message }),
|
|
243
|
-
...(
|
|
394
|
+
...(checkTx && { checkTx }),
|
|
395
|
+
...(supportsStaking &&
|
|
396
|
+
stakingDependencies[asset.name] && {
|
|
397
|
+
staking: stakingApiFactory({
|
|
398
|
+
assetName: asset.name,
|
|
399
|
+
currency: asset.currency,
|
|
400
|
+
assetClientInterface,
|
|
401
|
+
server,
|
|
402
|
+
stakingConfiguration: stakingConfiguration[asset.name],
|
|
403
|
+
stakingDependencies: stakingDependencies[asset.name],
|
|
404
|
+
}),
|
|
405
|
+
}),
|
|
244
406
|
validateAssetId: address.validate,
|
|
245
|
-
web3
|
|
407
|
+
web3,
|
|
246
408
|
}
|
|
247
409
|
|
|
248
410
|
const fullAsset = {
|
|
249
411
|
...asset,
|
|
250
|
-
...pick(config, ['accountReserve']),
|
|
251
|
-
gasLimit,
|
|
252
|
-
contractGasLimit,
|
|
253
412
|
bip44,
|
|
254
413
|
keys,
|
|
255
414
|
address,
|
|
256
415
|
api,
|
|
257
416
|
chainId,
|
|
417
|
+
...(encodeMultisigContract && { encodeMultisigContract }),
|
|
258
418
|
monitorType,
|
|
259
419
|
estimateL1DataFee,
|
|
420
|
+
forceGasLimitEstimation,
|
|
421
|
+
eip7623Supported,
|
|
422
|
+
// Stable array reference kept up to date with remote config by the
|
|
423
|
+
// history monitor's setServer.
|
|
424
|
+
eip7702Supported: eip7702Whitelist.get(),
|
|
425
|
+
getEIP7702Delegation: (addr) => getEIP7702Delegation({ address: addr, server }),
|
|
426
|
+
getNonce,
|
|
260
427
|
server,
|
|
261
428
|
...(erc20FuelBuffer && { erc20FuelBuffer }),
|
|
262
429
|
...(fuelThreshold && { fuelThreshold: asset.currency.defaultUnit(fuelThreshold) }),
|
|
263
|
-
|
|
430
|
+
broadcastPrivateBundle,
|
|
431
|
+
broadcastPrivateTx,
|
|
432
|
+
createRpcRequestAccumulator,
|
|
433
|
+
sendPrivateTx,
|
|
434
|
+
sendPrivateBundle,
|
|
264
435
|
}
|
|
265
|
-
return overrideCallback({
|
|
436
|
+
return overrideCallback({
|
|
437
|
+
asset: fullAsset,
|
|
438
|
+
stakingConfiguration,
|
|
439
|
+
assetClientInterface,
|
|
440
|
+
monitorInterval,
|
|
441
|
+
})
|
|
266
442
|
}
|
|
267
443
|
}
|
|
@@ -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
|
+
}
|