@exodus/ethereum-api 7.2.1 → 7.3.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/package.json +9 -4
- package/src/address-has-history.js +6 -0
- package/src/create-asset.js +216 -0
- package/src/create-token-factory.js +72 -0
- package/src/eth-like-util.js +2 -3
- package/src/exodus-eth-server/api-coin-nodes.js +2 -3
- package/src/exodus-eth-server/api.js +2 -3
- package/src/exodus-eth-server/clarity.js +6 -4
- package/src/get-balances.js +35 -13
- package/src/get-fee.js +97 -0
- package/src/hooks/index.js +1 -0
- package/src/hooks/monitor.js +88 -0
- package/src/index.js +3 -0
- package/src/number-utils.js +8 -0
- package/src/optimism-gas/index.js +4 -4
- package/src/staking/ethereum/service.js +4 -4
- package/src/staking-api.js +5 -0
- package/src/tx-log/clarity-monitor.js +4 -9
- package/src/tx-log/ethereum-monitor.js +2 -3
- package/src/tx-log/ethereum-no-history-monitor.js +2 -3
- package/src/tx-log-staking-processor/asset-staking-tx-data.js +48 -0
- package/src/tx-log-staking-processor/derive-txs.js +59 -0
- package/src/tx-log-staking-processor/get-asset-tx-amount.js +26 -0
- package/src/tx-log-staking-processor/index.js +36 -0
- package/src/tx-log-staking-processor/utils.js +70 -0
- package/src/tx-send/get-fee-info.js +41 -0
- package/src/tx-send/index.js +2 -0
- package/src/tx-send/tx-send.js +300 -0
package/src/index.js
CHANGED
|
@@ -11,3 +11,6 @@ export * from './staking'
|
|
|
11
11
|
export * from './simulate-tx'
|
|
12
12
|
export * from './allowance'
|
|
13
13
|
export * from './optimism-gas'
|
|
14
|
+
export * from './number-utils'
|
|
15
|
+
export { txSendFactory, getFeeInfo } from './tx-send'
|
|
16
|
+
export { createAssetFactory } from './create-asset'
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import BN from 'bn.js'
|
|
2
1
|
import * as ethUtil from '@exodus/ethereumjs-util'
|
|
3
2
|
import { createEthereumJsTx, createContract } from '@exodus/ethereum-lib'
|
|
4
3
|
import { getServerByName } from '../exodus-eth-server'
|
|
5
4
|
import { GAS_ORACLE_ADDRESS } from './addresses'
|
|
5
|
+
import { fromHexToBigInt } from '../number-utils'
|
|
6
6
|
|
|
7
7
|
const gasContract = createContract(GAS_ORACLE_ADDRESS, 'optimismGasOracle')
|
|
8
8
|
|
|
@@ -14,8 +14,8 @@ export async function estimateOptimismL1DataFee({ unsignedTx }) {
|
|
|
14
14
|
const data = ethUtil.bufferToHex(buffer)
|
|
15
15
|
const server = getServerByName('optimism')
|
|
16
16
|
const hex = await server.ethCall({ to: GAS_ORACLE_ADDRESS, data }, 'latest')
|
|
17
|
-
const l1DataFee =
|
|
18
|
-
const padFee = l1DataFee
|
|
19
|
-
const maxL1DataFee = l1DataFee
|
|
17
|
+
const l1DataFee = fromHexToBigInt(hex)
|
|
18
|
+
const padFee = l1DataFee / BigInt(4)
|
|
19
|
+
const maxL1DataFee = l1DataFee + padFee
|
|
20
20
|
return maxL1DataFee.toString()
|
|
21
21
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { estimateGasLimit } from '../../gas-estimation'
|
|
2
2
|
import { getServer } from '../../exodus-eth-server'
|
|
3
3
|
import { isNumberUnit } from '@exodus/currency'
|
|
4
|
-
import BN from 'bn.js'
|
|
5
4
|
import { stakingProviderClientFactory } from '../staking-provider-client'
|
|
6
5
|
import { EthereumStaking } from './api'
|
|
6
|
+
import { fromHexToBigInt } from '../../number-utils'
|
|
7
7
|
|
|
8
8
|
const extraGasLimit = 20_000 // extra gas Limit to prevent tx failing if something change on pool state (till tx is in mempool)
|
|
9
9
|
|
|
@@ -233,12 +233,12 @@ export function createEthereumStakingService({
|
|
|
233
233
|
gasPrice = await getServer(asset).gasPrice()
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
gasPrice =
|
|
237
|
-
const fee =
|
|
236
|
+
gasPrice = fromHexToBigInt(gasPrice)
|
|
237
|
+
const fee = gasPrice * BigInt(gasLimit + extraGasLimit)
|
|
238
238
|
|
|
239
239
|
return {
|
|
240
240
|
gasLimit,
|
|
241
|
-
gasPrice: asset.currency.baseUnit(gasPrice),
|
|
241
|
+
gasPrice: asset.currency.baseUnit(gasPrice.toString()),
|
|
242
242
|
fee: asset.currency.baseUnit(fee.toString()),
|
|
243
243
|
}
|
|
244
244
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import BN from 'bn.js'
|
|
2
1
|
import { BaseMonitor } from '@exodus/asset-lib'
|
|
3
2
|
import { getAssetAddresses, isRpcBalanceAsset } from '@exodus/ethereum-lib'
|
|
4
3
|
import { isEmpty } from 'lodash'
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
excludeUnchangedTokenBalances,
|
|
11
10
|
} from './monitor-utils'
|
|
12
11
|
import { getLogItemsFromServerTx, getDeriveDataNeededForTick, filterEffects } from './clarity-utils'
|
|
12
|
+
import { fromHexToString } from '../number-utils'
|
|
13
13
|
|
|
14
14
|
export class ClarityMonitor extends BaseMonitor {
|
|
15
15
|
constructor({ server, config, ...args }) {
|
|
@@ -250,8 +250,7 @@ export class ClarityMonitor extends BaseMonitor {
|
|
|
250
250
|
const entries = pairs.map((pair, idx) => {
|
|
251
251
|
const balanceHex = responses[idx]
|
|
252
252
|
const name = pair[0]
|
|
253
|
-
const
|
|
254
|
-
const balance = new BN(hex, 'hex').toString()
|
|
253
|
+
const balance = fromHexToString(balanceHex)
|
|
255
254
|
return [name, balance]
|
|
256
255
|
})
|
|
257
256
|
return Object.fromEntries(entries)
|
|
@@ -273,13 +272,9 @@ export class ClarityMonitor extends BaseMonitor {
|
|
|
273
272
|
|
|
274
273
|
async updateGasPrice({ gasPrice, baseFeePerGas }) {
|
|
275
274
|
try {
|
|
276
|
-
const
|
|
277
|
-
const feeConfig = { gasPrice: `${new BN(gasPriceHex, 'hex').toString()} wei` }
|
|
275
|
+
const feeConfig = { gasPrice: `${fromHexToString(gasPrice).toString()} wei` }
|
|
278
276
|
if (baseFeePerGas) {
|
|
279
|
-
|
|
280
|
-
? baseFeePerGas.slice(2)
|
|
281
|
-
: baseFeePerGas
|
|
282
|
-
feeConfig.baseFeePerGas = `${new BN(baseFeePerGasHex, 'hex').toString()} wei`
|
|
277
|
+
feeConfig.baseFeePerGas = `${fromHexToString(baseFeePerGas)} wei`
|
|
283
278
|
}
|
|
284
279
|
|
|
285
280
|
this.logger.debug(
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import BN from 'bn.js'
|
|
2
1
|
import { getServer } from '../exodus-eth-server'
|
|
3
2
|
import { isRpcBalanceAsset, getAssetAddresses } from '@exodus/ethereum-lib'
|
|
4
3
|
|
|
@@ -21,6 +20,7 @@ import {
|
|
|
21
20
|
import { isEmpty } from 'lodash'
|
|
22
21
|
|
|
23
22
|
import { BaseMonitor } from '@exodus/asset-lib'
|
|
23
|
+
import { fromHexToString } from '../number-utils'
|
|
24
24
|
|
|
25
25
|
// The base ethereum monitor class handles listening for, fetching,
|
|
26
26
|
// formatting, and populating-to-state all ETH/ETC/ERC20 transactions.
|
|
@@ -211,8 +211,7 @@ export class EthereumMonitor extends BaseMonitor {
|
|
|
211
211
|
const server = this.server
|
|
212
212
|
if (isRpcBalanceAsset(asset)) {
|
|
213
213
|
const result = await server.getBalanceProxied(ourWalletAddress)
|
|
214
|
-
const
|
|
215
|
-
const balance = new BN(hex, 'hex').toString()
|
|
214
|
+
const balance = fromHexToString(result)
|
|
216
215
|
newAccountState.balance = asset.currency.baseUnit(balance)
|
|
217
216
|
}
|
|
218
217
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import BN from 'bn.js'
|
|
2
1
|
import { getServer } from '../exodus-eth-server'
|
|
3
2
|
import { DEFAULT_SERVER_URLS } from '@exodus/ethereum-lib'
|
|
4
3
|
import { Tx } from '@exodus/models'
|
|
@@ -14,6 +13,7 @@ import { isEmpty, unionBy, zipObject } from 'lodash'
|
|
|
14
13
|
import { BaseMonitor } from '@exodus/asset-lib'
|
|
15
14
|
|
|
16
15
|
import { UNCONFIRMED_TX_LIMIT } from './monitor-utils/get-derive-transactions-to-check'
|
|
16
|
+
import { fromHexToString } from '../number-utils'
|
|
17
17
|
|
|
18
18
|
// The base ethereum monitor no history class handles listening for assets with no history
|
|
19
19
|
|
|
@@ -57,8 +57,7 @@ export class EthereumNoHistoryMonitor extends BaseMonitor {
|
|
|
57
57
|
const entries = pairs.map((pair, idx) => {
|
|
58
58
|
const balanceHex = responses[idx]
|
|
59
59
|
const name = pair[0]
|
|
60
|
-
const
|
|
61
|
-
const balance = new BN(hex, 'hex').toString()
|
|
60
|
+
const balance = fromHexToString(balanceHex)
|
|
62
61
|
return [name, balance]
|
|
63
62
|
})
|
|
64
63
|
return Object.fromEntries(entries)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isEthereumClaimUndelegate,
|
|
3
|
+
isEthereumDelegate,
|
|
4
|
+
isEthereumUndelegate,
|
|
5
|
+
isEthereumUndelegatePending,
|
|
6
|
+
} from '../staking/ethereum/staking-utils'
|
|
7
|
+
|
|
8
|
+
import { isPolygonClaimUndelegate, isPolygonDelegate } from '../staking/matic'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
decodePolygonStakingTxInputAmount,
|
|
12
|
+
isEthereumTxCountedForRewards,
|
|
13
|
+
isEthereumUndelegateTx,
|
|
14
|
+
} from './utils.js'
|
|
15
|
+
|
|
16
|
+
const getEthereumStakeTxType = ({ tx }) => {
|
|
17
|
+
// only unstake txs with ZERO amount are used to calculate rewards
|
|
18
|
+
const skipTx = tx.coinAmount.isZero && !isEthereumUndelegateTx(tx)
|
|
19
|
+
if (skipTx) return
|
|
20
|
+
|
|
21
|
+
if (isEthereumDelegate(tx)) return { delegate: tx.coinAmount.toDefaultString() }
|
|
22
|
+
// undelegate must be taken in consideration, if unstaked ETH is still
|
|
23
|
+
// in the pool queue, undelgate transfers staked funds back inmediatly to the user
|
|
24
|
+
if (isEthereumUndelegatePending(tx)) return { undelegatePending: tx.coinAmount.toDefaultString() }
|
|
25
|
+
if (isEthereumUndelegate(tx) && !isEthereumTxCountedForRewards(tx))
|
|
26
|
+
return { undelegate: tx.coinAmount.toDefaultString() }
|
|
27
|
+
// In the case of the ETH being actually staked and earning,
|
|
28
|
+
// unstake has a withdraw period, after that, unstaked can be claimed.
|
|
29
|
+
if (isEthereumClaimUndelegate(tx) && !isEthereumTxCountedForRewards(tx))
|
|
30
|
+
return { claimUndelegate: tx.coinAmount.toDefaultString() }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const getPolygonStakeTxType = ({ tx, currency }) => {
|
|
34
|
+
if (tx.coinAmount.isZero) return
|
|
35
|
+
|
|
36
|
+
if (isPolygonDelegate(tx)) {
|
|
37
|
+
const stakeTxAmount = currency.baseUnit(decodePolygonStakingTxInputAmount(tx)).toDefaultString()
|
|
38
|
+
return { delegate: stakeTxAmount }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (isPolygonClaimUndelegate(tx)) return { undelegate: tx.coinAmount.toDefaultString() }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const assetStakingTxData = {
|
|
45
|
+
polygon: getPolygonStakeTxType,
|
|
46
|
+
ethereum: getEthereumStakeTxType,
|
|
47
|
+
ethereumholesky: getEthereumStakeTxType,
|
|
48
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { decodeEthLikeStakingTxInputAmount } from './utils'
|
|
2
|
+
|
|
3
|
+
const deriveEthereumTxs = ({ currency }) => {
|
|
4
|
+
let totalUnstaked = currency.ZERO
|
|
5
|
+
|
|
6
|
+
return function ({ tx, txStakeData }) {
|
|
7
|
+
const { claimUndelegate, undelegate } = txStakeData
|
|
8
|
+
|
|
9
|
+
if (claimUndelegate && totalUnstaked.isPositive) {
|
|
10
|
+
// calculate and add a new reward tx based 'totalUnstaked' (unstaked amount counted so far)
|
|
11
|
+
const claimedWithRewards = currency.defaultUnit(claimUndelegate)
|
|
12
|
+
const reward = claimedWithRewards.sub(totalUnstaked)
|
|
13
|
+
const claimed = claimedWithRewards.sub(reward)
|
|
14
|
+
// count again for new rewards in upcoming unstake txs
|
|
15
|
+
totalUnstaked = currency.ZERO
|
|
16
|
+
return reward.isPositive
|
|
17
|
+
? [
|
|
18
|
+
{
|
|
19
|
+
...tx,
|
|
20
|
+
coinAmount: reward,
|
|
21
|
+
data: {
|
|
22
|
+
reward: reward.toDefaultString(),
|
|
23
|
+
claim: claimed.toDefaultString(),
|
|
24
|
+
countedForRewards: true,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
]
|
|
28
|
+
: []
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (undelegate) {
|
|
32
|
+
// Only care about amount requested in 'unstake()'; considered to be in progress.
|
|
33
|
+
// Counting unstake (not unstake pending) amount until 'claimUnstake()' is called,
|
|
34
|
+
// then use the counted unstaked amount to derive rewards with:
|
|
35
|
+
// rewards = claimUstaked - totalUnstaked
|
|
36
|
+
const unstakeInProgress = currency.baseUnit(decodeEthLikeStakingTxInputAmount(tx))
|
|
37
|
+
totalUnstaked = totalUnstaked.add(unstakeInProgress)
|
|
38
|
+
return [
|
|
39
|
+
{
|
|
40
|
+
...tx,
|
|
41
|
+
coinAmount: currency.ZERO,
|
|
42
|
+
data: { ...tx.data, countedForRewards: true },
|
|
43
|
+
},
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// undelegate pending excluded as unstaked funds are moved inmediatly to user address
|
|
48
|
+
return []
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const deriveAssetTxsFactory = ({ assetName, currency }) => {
|
|
53
|
+
const deriveTxHandlers = {
|
|
54
|
+
ethereum: deriveEthereumTxs({ currency }),
|
|
55
|
+
ethereumholesky: deriveEthereumTxs({ currency }),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return deriveTxHandlers[assetName]
|
|
59
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { calculateTxAmountAndRewardFromStakeTx } from './utils.js'
|
|
2
|
+
|
|
3
|
+
const getPolygonTxAmount = ({ currency, tx, type }) => {
|
|
4
|
+
if ('delegate' in type) {
|
|
5
|
+
return calculateTxAmountAndRewardFromStakeTx({ tx, currency })
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return currency.ZERO
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const getEthereumTxAmount = ({ currency, tx, type }) => {
|
|
12
|
+
const isStakingTx = ['delegate', 'undelegatePending', 'undelegate', 'claimUndelegate'].some(
|
|
13
|
+
(stakingType) => type[stakingType]
|
|
14
|
+
)
|
|
15
|
+
if (isStakingTx) {
|
|
16
|
+
return currency.ZERO
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return tx.coinAmount
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const getStakeTxAmount = {
|
|
23
|
+
polygon: getPolygonTxAmount,
|
|
24
|
+
ethereum: getEthereumTxAmount,
|
|
25
|
+
ethereumholesky: getEthereumTxAmount,
|
|
26
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { assetStakingTxData } from './asset-staking-tx-data'
|
|
2
|
+
import { deriveAssetTxsFactory } from './derive-txs'
|
|
3
|
+
import { getStakeTxAmount } from './get-asset-tx-amount'
|
|
4
|
+
|
|
5
|
+
const getTxStakeData = ({ assetName, currency, tx }) => {
|
|
6
|
+
return assetStakingTxData[assetName]({ tx, currency })
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const processTxLog = async ({ asset, assetClientInterface: aci, walletAccount, batch }) => {
|
|
10
|
+
const { name: assetName, currency } = asset
|
|
11
|
+
const txs = await aci.getTxLog({ assetName, walletAccount })
|
|
12
|
+
const deriveAssetTxs = deriveAssetTxsFactory({ assetName, currency })
|
|
13
|
+
|
|
14
|
+
const newTxs = []
|
|
15
|
+
for (const tx of txs) {
|
|
16
|
+
const txStakeData = getTxStakeData({ assetName, currency, tx })
|
|
17
|
+
if (txStakeData) {
|
|
18
|
+
const txAmount = getStakeTxAmount[assetName]({ tx, currency, type: txStakeData })
|
|
19
|
+
newTxs.push({
|
|
20
|
+
...tx,
|
|
21
|
+
coinAmount: txAmount,
|
|
22
|
+
data: { ...tx.data, ...txStakeData },
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (txStakeData && deriveAssetTxs) {
|
|
27
|
+
newTxs.push(...deriveAssetTxs({ tx, txStakeData }))
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (newTxs.length > 0) {
|
|
32
|
+
aci.updateTxLogAndNotifyBatch({ assetName, walletAccount, txs: newTxs, batch })
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default processTxLog
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { EthereumStaking, isEthereumStakingTx, MaticStakingApi } from '../staking'
|
|
2
|
+
import { asset as ethereum } from '@exodus/ethereum-meta'
|
|
3
|
+
import { asset as ethereumholesky } from '@exodus/ethereumholesky-meta'
|
|
4
|
+
|
|
5
|
+
const polygonStakingApi = new MaticStakingApi()
|
|
6
|
+
const ethereumStakingApi = new EthereumStaking(ethereum)
|
|
7
|
+
const ethereumHoleskyStakingApi = new EthereumStaking(ethereumholesky)
|
|
8
|
+
|
|
9
|
+
export const decodePolygonStakingTxInputAmount = (tx) => {
|
|
10
|
+
const {
|
|
11
|
+
data: { data: txInput },
|
|
12
|
+
} = tx
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
values: [amount], // stake or unstake amount
|
|
16
|
+
} = polygonStakingApi.validatorShareContract.decodeInput(txInput)
|
|
17
|
+
|
|
18
|
+
return amount
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const calculateTxAmountAndRewardFromStakeTx = ({ tx, currency }) => {
|
|
22
|
+
const stakedAmount = currency.baseUnit(decodePolygonStakingTxInputAmount(tx))
|
|
23
|
+
const { reward } = tx.data
|
|
24
|
+
// stake tx might have rewards in it,
|
|
25
|
+
// i.e: https://etherscan.io/tx/0x0a81d266109034a3a70c6f1b9601c105d8caebbd0de652a0619344f9559ae4fa
|
|
26
|
+
// thus reward = txInputAmount(amount to stake) - tx.coinAmount
|
|
27
|
+
// tx.coinAmount is already computed from monitor; incoming - outgoing ERC20 token txs
|
|
28
|
+
const stakeTxContainsReward = !stakedAmount.equals(tx.coinAmount.abs())
|
|
29
|
+
|
|
30
|
+
if (reward) {
|
|
31
|
+
// cache rewards
|
|
32
|
+
return currency.baseUnit(reward)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (stakeTxContainsReward) {
|
|
36
|
+
const txAmount = stakedAmount.sub(tx.coinAmount.abs()).abs()
|
|
37
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only -- TODO: Fix this the next time the file is edited.
|
|
38
|
+
tx.data.reward = txAmount.toBaseString()
|
|
39
|
+
return txAmount
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// no rewards, set stake tx amount to ZERO
|
|
43
|
+
return currency.ZERO
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const decodeEthLikeStakingTxInputAmount = (tx) => {
|
|
47
|
+
const {
|
|
48
|
+
data: { data: txInput },
|
|
49
|
+
coinName: assetName,
|
|
50
|
+
} = tx
|
|
51
|
+
|
|
52
|
+
const ethereumLikeContracts = {
|
|
53
|
+
ethereum: ethereumStakingApi,
|
|
54
|
+
ethereumholesky: ethereumHoleskyStakingApi,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const ethLikeContract = ethereumLikeContracts[assetName]
|
|
58
|
+
|
|
59
|
+
const {
|
|
60
|
+
values: [amount], // stake or unstake amount
|
|
61
|
+
} = ethLikeContract.contractPool.decodeInput(txInput)
|
|
62
|
+
|
|
63
|
+
return amount
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// TODO: fix this in eth libraries
|
|
67
|
+
export const isEthereumUndelegateTx = (tx) =>
|
|
68
|
+
isEthereumStakingTx(tx) && tx.data?.methodId === EthereumStaking.METHODS_IDS.UNSTAKE
|
|
69
|
+
|
|
70
|
+
export const isEthereumTxCountedForRewards = (tx) => !!tx.data?.countedForRewards
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { fetchGasLimit } from '../gas-estimation'
|
|
2
|
+
|
|
3
|
+
const getFeeInfo = async function getFeeInfo({
|
|
4
|
+
assetClientInterface,
|
|
5
|
+
asset,
|
|
6
|
+
fromAddress,
|
|
7
|
+
toAddress,
|
|
8
|
+
amount,
|
|
9
|
+
isExchange,
|
|
10
|
+
txInput,
|
|
11
|
+
feeOpts = {},
|
|
12
|
+
}) {
|
|
13
|
+
const {
|
|
14
|
+
gasPrice: gasPrice_,
|
|
15
|
+
tipGasPrice: tipGasPrice_,
|
|
16
|
+
gasPriceEconomicalRate,
|
|
17
|
+
} = await assetClientInterface.getFeeData({
|
|
18
|
+
assetName: asset.name,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
let { gasLimit, gasPrice = gasPrice_, tipGasPrice = tipGasPrice_ } = feeOpts
|
|
22
|
+
|
|
23
|
+
if (!gasLimit) {
|
|
24
|
+
gasLimit = await fetchGasLimit({
|
|
25
|
+
asset,
|
|
26
|
+
fromAddress,
|
|
27
|
+
toAddress,
|
|
28
|
+
amount,
|
|
29
|
+
txInput,
|
|
30
|
+
throwOnError: false,
|
|
31
|
+
isContract: feeOpts.isContract ?? undefined,
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const economicalFeeMultiplier = isExchange ? 1 : gasPriceEconomicalRate || 1
|
|
36
|
+
|
|
37
|
+
const fee = gasPrice.mul(economicalFeeMultiplier).mul(gasLimit)
|
|
38
|
+
return { gasPrice, gasLimit, fee, tipGasPrice }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default getFeeInfo
|