@exodus/ethereum-api 8.34.7 → 8.34.8
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 +0 -20
- package/package.json +2 -2
- package/src/create-asset.js +2 -1
- package/src/custom-fees.js +10 -40
- package/src/etherscan/ws.js +2 -1
- package/src/exodus-eth-server/ws.js +2 -1
- package/src/fee-utils.js +3 -17
- package/src/gas-estimation.js +6 -11
- package/src/get-fee.js +35 -29
- package/src/index.js +0 -2
- package/src/staking/ethereum/api.js +0 -1
- package/src/staking/ethereum/service.js +92 -116
- package/src/staking/matic/matic-staking.md +0 -53
- package/src/staking/matic/service.js +102 -189
- package/src/staking/utils/index.js +60 -26
- package/src/tx-send/get-fee-info.js +9 -34
- package/src/tx-send/nonce-utils.js +1 -2
- package/src/tx-send/tx-send.js +31 -73
- package/src/websocket/index.android.js +2 -0
- package/src/websocket/index.ios.js +2 -0
- package/src/websocket/index.js +2 -0
- package/src/websocket/websocket.cjs +21 -0
package/src/tx-send/tx-send.js
CHANGED
|
@@ -70,7 +70,7 @@ export const HACK_maybeRefineSendAllAmount = async ({
|
|
|
70
70
|
const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
71
71
|
assert(assetClientInterface, 'assetClientInterface is required')
|
|
72
72
|
assert(createUnsignedTx, 'createUnsignedTx is required')
|
|
73
|
-
return async ({ asset, walletAccount, address, amount,
|
|
73
|
+
return async ({ asset, walletAccount, address, amount, options = {} }) => {
|
|
74
74
|
const {
|
|
75
75
|
nft,
|
|
76
76
|
bumpTxId,
|
|
@@ -93,18 +93,13 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
93
93
|
|
|
94
94
|
const assets = await assetClientInterface.getAssetsForNetwork({ baseAssetName: baseAsset.name })
|
|
95
95
|
|
|
96
|
-
const feeData =
|
|
97
|
-
maybeFeeData ||
|
|
98
|
-
(await assetClientInterface.getFeeData({
|
|
99
|
-
assetName: baseAsset.name,
|
|
100
|
-
}))
|
|
101
|
-
|
|
102
|
-
const { eip1559Enabled } = feeData
|
|
103
|
-
|
|
104
96
|
const fromAddress = await assetClientInterface.getReceiveAddress({
|
|
105
97
|
assetName: baseAsset.name,
|
|
106
98
|
walletAccount,
|
|
107
99
|
})
|
|
100
|
+
const feeData = await assetClientInterface.getFeeData({
|
|
101
|
+
assetName: baseAsset.name,
|
|
102
|
+
})
|
|
108
103
|
|
|
109
104
|
let contractAddress
|
|
110
105
|
if (nft) {
|
|
@@ -117,6 +112,8 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
117
112
|
|
|
118
113
|
let bumpNonce
|
|
119
114
|
|
|
115
|
+
let eip1559Enabled = feeData.eip1559Enabled
|
|
116
|
+
|
|
120
117
|
const baseAssetTxLog = await assetClientInterface.getTxLog({
|
|
121
118
|
assetName: baseAsset.name,
|
|
122
119
|
walletAccount,
|
|
@@ -126,47 +123,36 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
126
123
|
let replacedTx, replacedTokenTx
|
|
127
124
|
if (bumpTxId) {
|
|
128
125
|
replacedTx = baseAssetTxLog.get(bumpTxId)
|
|
129
|
-
|
|
130
126
|
if (!replacedTx || !replacedTx.pending) {
|
|
131
127
|
throw new Error(`Cannot bump transaction ${bumpTxId}: not found or confirmed`)
|
|
132
128
|
}
|
|
133
129
|
|
|
134
130
|
if (replacedTx.tokens.length > 0) {
|
|
135
|
-
const [tokenAssetName] = replacedTx.tokens
|
|
136
131
|
const tokenTxSet = await assetClientInterface.getTxLog({
|
|
137
|
-
assetName:
|
|
132
|
+
assetName: replacedTx.tokens[0],
|
|
138
133
|
walletAccount,
|
|
139
134
|
})
|
|
140
135
|
replacedTokenTx = tokenTxSet.get(bumpTxId)
|
|
141
136
|
|
|
142
137
|
if (replacedTokenTx) {
|
|
143
|
-
|
|
144
|
-
// we're performing a token transaction.
|
|
145
|
-
asset = assets[tokenAssetName]
|
|
146
|
-
if (!asset) {
|
|
147
|
-
console.warn(
|
|
148
|
-
`unable to find ${tokenAssetName} during token bump transaction: asset was not available in assetsForNetwork`
|
|
149
|
-
)
|
|
150
|
-
}
|
|
138
|
+
asset = assets[replacedTx.tokens[0]]
|
|
151
139
|
}
|
|
152
|
-
|
|
153
|
-
// TODO: Should we `throw` if we can't find the asset?
|
|
154
140
|
}
|
|
155
141
|
|
|
156
142
|
address = (replacedTokenTx || replacedTx).to
|
|
157
143
|
amount = (replacedTokenTx || replacedTx).coinAmount.negate()
|
|
158
144
|
feeOpts.gasLimit = replacedTx.data.gasLimit
|
|
159
145
|
|
|
160
|
-
const { gasPrice: currentGasPrice
|
|
146
|
+
const { gasPrice: currentGasPrice } = feeData
|
|
161
147
|
const { bumpedGasPrice, bumpedTipGasPrice } = calculateBumpedGasPrice({
|
|
162
148
|
baseAsset,
|
|
163
149
|
tx: replacedTx,
|
|
164
150
|
currentGasPrice,
|
|
165
|
-
currentBaseFee,
|
|
166
151
|
eip1559Enabled,
|
|
167
152
|
})
|
|
168
153
|
feeOpts.gasPrice = bumpedGasPrice
|
|
169
154
|
feeOpts.tipGasPrice = bumpedTipGasPrice
|
|
155
|
+
eip1559Enabled = feeData.eip1559Enabled && feeOpts.tipGasPrice
|
|
170
156
|
bumpNonce = replacedTx.data.nonce
|
|
171
157
|
txInput = replacedTokenTx ? null : replacedTx.data.data || '0x'
|
|
172
158
|
if (bumpNonce === undefined) {
|
|
@@ -174,40 +160,9 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
174
160
|
}
|
|
175
161
|
}
|
|
176
162
|
|
|
177
|
-
// If we have evaluated a bump transaction and the `providedNonce` differs
|
|
178
|
-
// from the `bumpNonce`, we've encountered a conflict and cannot respect
|
|
179
|
-
// the caller's request.
|
|
180
|
-
if (
|
|
181
|
-
typeof bumpNonce === 'number' &&
|
|
182
|
-
typeof providedNonce === 'number' &&
|
|
183
|
-
bumpNonce !== providedNonce
|
|
184
|
-
)
|
|
185
|
-
throw new ErrorWrapper.EthLikeError({
|
|
186
|
-
message: new Error('incorrect nonce for replacement transaction'),
|
|
187
|
-
reason: ErrorWrapper.reasons.bumpTxFailed,
|
|
188
|
-
hint: 'providedNonce',
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
// Choose a nonce that compensates for transctions which are currently
|
|
192
|
-
// in pending; for example, when we send transactions at low gas which
|
|
193
|
-
// will be stored by `geth` for execution at a later point in time.
|
|
194
|
-
//
|
|
195
|
-
// When we are not intentionally bumping a transaction, users are
|
|
196
|
-
// appending a new transaction to the chain - therefore we should
|
|
197
|
-
// be mindful of nonces belonging to us which are currently pending.
|
|
198
163
|
const resolvedNonce =
|
|
199
|
-
providedNonce ??
|
|
200
164
|
bumpNonce ??
|
|
201
|
-
(await resolveNonce({
|
|
202
|
-
asset,
|
|
203
|
-
fromAddress,
|
|
204
|
-
txLog: baseAssetTxLog,
|
|
205
|
-
// For assets where we'll fall back to querying the coin node, we
|
|
206
|
-
// search for pending transactions. For base assets with history,
|
|
207
|
-
// we'll fall back to the `TxLog` since this also has a knowledge
|
|
208
|
-
// of which transactions are currently in pending.
|
|
209
|
-
tag: 'pending',
|
|
210
|
-
}))
|
|
165
|
+
(await resolveNonce({ asset, fromAddress, providedNonce, txLog: baseAssetTxLog }))
|
|
211
166
|
|
|
212
167
|
const createTxParams = {
|
|
213
168
|
assetClientInterface,
|
|
@@ -217,15 +172,14 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
217
172
|
amount,
|
|
218
173
|
nonce: resolvedNonce,
|
|
219
174
|
fromAddress,
|
|
175
|
+
eip1559Enabled,
|
|
220
176
|
customFee,
|
|
221
177
|
feeOpts,
|
|
222
178
|
txInput,
|
|
223
179
|
keepTxInput,
|
|
224
180
|
isSendAll,
|
|
225
181
|
createUnsignedTx,
|
|
226
|
-
feeData,
|
|
227
182
|
}
|
|
228
|
-
|
|
229
183
|
let { txId, rawTx, nonce, gasLimit, tipGasPrice, gasPrice } = await createTx(createTxParams)
|
|
230
184
|
|
|
231
185
|
const feeAmount = gasPrice.mul(gasLimit)
|
|
@@ -370,13 +324,13 @@ const createTx = async ({
|
|
|
370
324
|
amount,
|
|
371
325
|
nonce,
|
|
372
326
|
txInput,
|
|
327
|
+
eip1559Enabled = true,
|
|
373
328
|
keepTxInput = false,
|
|
374
|
-
customFee,
|
|
329
|
+
customFee: customGasPrice,
|
|
375
330
|
isSendAll,
|
|
376
331
|
fromAddress,
|
|
377
332
|
feeOpts,
|
|
378
333
|
createUnsignedTx,
|
|
379
|
-
feeData,
|
|
380
334
|
}) => {
|
|
381
335
|
assert(
|
|
382
336
|
nonce !== undefined && typeof nonce === 'number',
|
|
@@ -392,7 +346,7 @@ const createTx = async ({
|
|
|
392
346
|
? asset.contract.transfer.build(toAddress.toLowerCase(), amount.toBaseString())
|
|
393
347
|
: txInput
|
|
394
348
|
|
|
395
|
-
let { gasLimit, gasPrice, tipGasPrice
|
|
349
|
+
let { gasLimit, gasPrice, tipGasPrice } = await getFeeInfo({
|
|
396
350
|
assetClientInterface,
|
|
397
351
|
asset,
|
|
398
352
|
fromAddress,
|
|
@@ -400,8 +354,6 @@ const createTx = async ({
|
|
|
400
354
|
amount,
|
|
401
355
|
txInput,
|
|
402
356
|
feeOpts,
|
|
403
|
-
feeData,
|
|
404
|
-
customFee,
|
|
405
357
|
})
|
|
406
358
|
|
|
407
359
|
const isContractToAddress = await isContractAddressCached({ asset, address: toAddress })
|
|
@@ -415,16 +367,22 @@ const createTx = async ({
|
|
|
415
367
|
// versus estimations, anyway.
|
|
416
368
|
const isSendAllBaseAsset = isSendAll && !isToken && !isContractToAddress
|
|
417
369
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
370
|
+
if (eip1559Enabled) {
|
|
371
|
+
if (customGasPrice) {
|
|
372
|
+
gasPrice = customGasPrice // aka maxFeePerGas
|
|
373
|
+
|
|
374
|
+
// We must ensure maxPriorityFeePerGas <= maxFeePerGas or our transaction library throws an error
|
|
375
|
+
// It's a bit counterintuitive since maxPriorityFeePerGas should only contain the tip,
|
|
376
|
+
// so we should be subtracting the base gas price from the custom gas price to keep just the tip
|
|
377
|
+
// but the fee is also limited by our maxFeePerGas above, so that implicitly captures the max tip.
|
|
378
|
+
// Setting this tipGasPrice to undefined will result in a legacy transaction (not an EIP1559 anymore)
|
|
379
|
+
tipGasPrice = customGasPrice // aka maxPriorityFeePerGas
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (isSendAllBaseAsset) {
|
|
383
|
+
// force consuming all gas
|
|
384
|
+
tipGasPrice = gasPrice
|
|
385
|
+
}
|
|
428
386
|
}
|
|
429
387
|
|
|
430
388
|
// HACK: If we are handling a send all transaction, we must ensure
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is a "light" version of @exodus/core resolution to select the native WebSocket on BE
|
|
3
|
+
* It's a workaround until https://github.com/ExodusMovement/assets/pull/72 is merged.
|
|
4
|
+
*
|
|
5
|
+
* Based on https://github.com/ExodusMovement/fetch/blob/master/core.js , note that chooses native on Desktop
|
|
6
|
+
*/
|
|
7
|
+
if (typeof process !== 'undefined' && (process.type === 'renderer' || process.type === 'worker')) {
|
|
8
|
+
// THIS IS FOR DESKTOP
|
|
9
|
+
if (process.env.EXODUS_DISABLE_WS) {
|
|
10
|
+
module.exports = globalThis.WebSocket
|
|
11
|
+
} else {
|
|
12
|
+
module.exports = require('ws')
|
|
13
|
+
}
|
|
14
|
+
// eslint-disable-next-line no-undef
|
|
15
|
+
} else if (typeof WebSocket === 'undefined') {
|
|
16
|
+
// THIS IS FOR UNIT TESTING.
|
|
17
|
+
module.exports = require('ws')
|
|
18
|
+
} else {
|
|
19
|
+
// THIS IS FOR BE
|
|
20
|
+
module.exports = globalThis.WebSocket
|
|
21
|
+
}
|