@exodus/ethereum-api 8.23.2 → 8.24.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 +20 -0
- package/LICENSE +7 -0
- package/README.md +119 -1
- package/package.json +7 -7
- package/src/staking/ethereum/service.js +15 -18
- package/src/staking/matic/service.js +24 -24
- package/src/watch-tx.js +32 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [8.24.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.24.0...@exodus/ethereum-api@8.24.1) (2024-12-19)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### License
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* license: re-license under MIT license (#4694)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [8.24.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.23.2...@exodus/ethereum-api@8.24.0) (2024-12-17)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
* feat: evm staking send simplification (#4681)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
## [8.23.2](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.23.1...@exodus/ethereum-api@8.23.2) (2024-12-17)
|
|
7
27
|
|
|
8
28
|
|
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) 2024 Exodus Movement, Inc.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,121 @@
|
|
|
1
1
|
# @exodus/ethereum-api
|
|
2
2
|
|
|
3
|
-
Transaction monitors, fee monitors, RPC with the blockchain node, and other networking code for Ethereum and EVM-based blockchains. See [Asset Packages](../../docs/asset-packages.md) for more detail on this package
|
|
3
|
+
Transaction monitors, fee monitors, RPC with the blockchain node, and other networking code for Ethereum and EVM-based blockchains. See [Asset Packages](../../docs/asset-packages.md) for more detail on this package`s role.
|
|
4
|
+
|
|
5
|
+
## Fees
|
|
6
|
+
|
|
7
|
+
This section explains how fees currently work in Exodus and provides guidance on troubleshooting and tuning them via remote configuration. It reverse-engineers the existing unified implementation. The document aims to help readers understand the fee mechanism and suggest ways to improve it further.
|
|
8
|
+
|
|
9
|
+
### Gas Price
|
|
10
|
+
|
|
11
|
+
Excluding custom fees, the result `gasPrice * gasPriceMultiplier` is used to resolve the transaction's gas price (legacy) and max gas price (EIP-1559).
|
|
12
|
+
|
|
13
|
+
The `gasPrice` value is, in preference order, loaded from:
|
|
14
|
+
|
|
15
|
+
1. Remote config
|
|
16
|
+
2. The node via the fee data monitor
|
|
17
|
+
3. The default configuration.
|
|
18
|
+
|
|
19
|
+
Using remote config is never recommended, as manually updating this value won't keep up with network activity.
|
|
20
|
+
|
|
21
|
+
Fee and remote monitors are executed as soon as the wallet starts. The default fee data fields defined in code would be overridden (if they are set) before the user can interact with the wallet.
|
|
22
|
+
|
|
23
|
+
To tune the fee resolution, we can:
|
|
24
|
+
|
|
25
|
+
- Increase or decrease `gasPriceMultiplier` via remote config. For example, `1.2` would bump the current network gas price by 20%.
|
|
26
|
+
- Set a `min` value via remote config. Gas price will never be lower than this value.
|
|
27
|
+
- Set a `max` value via remote config. Gas price will never be higher than this value.
|
|
28
|
+
|
|
29
|
+
If the `gasPrice` returned by the node is not accurate or lower than the network's, the transaction may get stuck in pending status or may not be broadcast to the blockchain.
|
|
30
|
+
|
|
31
|
+
This is an undesirable situation:
|
|
32
|
+
|
|
33
|
+
- We could increase the nonce for the second transaction, but if the first one drops, the second one will also fail, even if the fees of the second one are high enough.
|
|
34
|
+
- If the wallet assumes the transaction was dropped and the nonce is reused, the network will interpret this unrelated second transaction as attempting to replace the first one (transaction replacement underprice error).
|
|
35
|
+
- The user submitting a second transaction to "retry" could be dangerous. Both transactions might get mined, causing the user to execute the swap twice instead of once.
|
|
36
|
+
|
|
37
|
+
One escape valve could be to update the `min`, `max`, or `gasPriceMultiplier` via remote config. This should be a temporary patch that needs to be rolled back once the node's gas price stabilizes.
|
|
38
|
+
|
|
39
|
+
### Base Gas Price
|
|
40
|
+
|
|
41
|
+
The base gas price (or base fee) is the minimum amount of gas required to be paid per unit of gas to include a transaction in a block.
|
|
42
|
+
|
|
43
|
+
It can be found in `feeData.baseFeePerGas`. The fee monitor keeps it up to date by monitoring the latest block's information. It could be tuned by remote config, but this is not recommended.
|
|
44
|
+
|
|
45
|
+
The `feeData.baseFeePerGas` is only used when showing an "estimated fee" in the UI and not when sending a transaction.
|
|
46
|
+
|
|
47
|
+
One possible improvement is to define the max gas price based on the base gas price rather than the network's current gas price.
|
|
48
|
+
|
|
49
|
+
### Gas Limit
|
|
50
|
+
|
|
51
|
+
The `gasLimit` refers to the maximum amount of gas a transaction or block is allowed to consume during its execution.
|
|
52
|
+
Most EVMs assume 21,000 when transferring the main asset. Some EVMs, like Mantle, Arbitrum One, and Arbitrum Nova, use a different gas limit. These gas limits need to be estimated, similar to when performing smart contract calls.
|
|
53
|
+
|
|
54
|
+
For smart contract calls, like sending or swapping, the wallet estimates a gas limit based on the contract, the sender, the receiver, the amounts, etc. The gas limit is then bumped by a 20% `extraPercentage` as a safety net.
|
|
55
|
+
|
|
56
|
+
If the gas limit estimation fails, the code may fall back to a high default value defined per asset (`asset.gasLimit`).
|
|
57
|
+
|
|
58
|
+
Currently, there is no way to tune the gas limit resolution via remote config, and "extra percentage" values are hardcoded in the code.
|
|
59
|
+
|
|
60
|
+
Both the bumped `gasLimit` and the bumped `gasPrice` resolved when showing the fees are reused when sending.
|
|
61
|
+
|
|
62
|
+
The higher the gas limit and the gas price, the higher the max network fee, even though not all that gas may be used. The higher the max network fee, the lower the user's available balance.
|
|
63
|
+
|
|
64
|
+
### Additional L2 Fees
|
|
65
|
+
|
|
66
|
+
L2 networks may have additional fees. Arbitrum One, Arbitrum Nova, and Mantle include the fees in the gas estimation (`forceGasLimitEstimation`). Base and Aptos need an additional fee estimation to get this extra fee (`estimateL1DataFee`).
|
|
67
|
+
|
|
68
|
+
The L2 extra fee needs to be considered when showing the fee to the user, resolving the available balance, and creating the transaction. The fee may be implicit in the transaction.
|
|
69
|
+
|
|
70
|
+
### Custom Fees
|
|
71
|
+
|
|
72
|
+
Custom fees allow users to set a custom `gasPrice`. The wallet allows a range, as follows:
|
|
73
|
+
|
|
74
|
+
- `recommended: gasPrice * gasPriceMultiplier`
|
|
75
|
+
- `min: gasPrice * gasPriceMultiplier * gasPriceMinimumRate`
|
|
76
|
+
- `max: gasPrice * gasPriceMultiplier * gasPriceMaximumRate`
|
|
77
|
+
|
|
78
|
+
If the user picks the recommended value, the custom fee is not set, leaving the default fee behavior.
|
|
79
|
+
Custom fees can be disabled by setting `rbfEnabled: false` via remote config. Currently, only Ethereum allows custom fees. Other EVMs could be included in the future.
|
|
80
|
+
|
|
81
|
+
The wallet allows acceleration when custom fees are allowed (and vice versa).
|
|
82
|
+
|
|
83
|
+
If the user picks a different custom fee in that range, the fee is calculated as `customFee * gasLimit`. `gasPriceMultiplier` is not applied to the custom gas price.
|
|
84
|
+
|
|
85
|
+
A transaction created with a low custom fee may be stuck for a while, blocking future transactions, and it may create issues with the nonce, as explained above.
|
|
86
|
+
|
|
87
|
+
Min and max values can be tuned by changing `gasPriceMinimumRate` and `gasPriceMaximumRate` via remote config.
|
|
88
|
+
|
|
89
|
+
### TX formulas
|
|
90
|
+
|
|
91
|
+
Table shows how the txs are create for both legacy and 1559 logic for major use case:
|
|
92
|
+
|
|
93
|
+
| | Send some main | Send all main | Send token/contract call | Send main with custom fee | Send token/contract with custom fee | Accelerate |
|
|
94
|
+
| ------------------ | ----------------------------- | ----------------------------- | ----------------------------- | ------------------------- | ----------------------------------- | ------------------------------------------------------------ |
|
|
95
|
+
| Legacy Gas Price | gasPrice \* gasPriceMultipler | gasPrice \* gasPriceMultipler | gasPrice \* gasPriceMultipler | customFee | customFee | max(current gasPrice,original tx gasPrice) \* BUMP_RATE 1.2 |
|
|
96
|
+
| Legacy Gas Limit | 21000 | 21000 | estimated + 20% extra | 21000 | estimated + 20% extra | original tx gasLimit |
|
|
97
|
+
| - | - | - | - | - | - | - |
|
|
98
|
+
| 1559 Max gas Price | gasPrice \* gasPriceMultipler | gasPrice \* gasPriceMultipler | gasPrice \* gasPriceMultipler | customFee | customFee | max(current gasPrice, original tx gasPrice) \* BUMP_RATE 1.2 |
|
|
99
|
+
| 1559 Tip gas Price | tipGasPrice | gasPrice \* gasPriceMultipler | tipGasPrice | customFee | tipGasPrice | orginal tx tipGasPrice \* BUMP_RATE 1.2 |
|
|
100
|
+
| 1559 Gas Limit | 21000 | 21000 | estimated + 20% extra | 21000 | estimated + 20% extra | original tx gasLimit |
|
|
101
|
+
|
|
102
|
+
### Fee Data Example
|
|
103
|
+
|
|
104
|
+
This is the default fee data configuration for Ethereum. Other EVMs have different default fee data.
|
|
105
|
+
|
|
106
|
+
All these values can be tuned via remote config, although it may not be recommended as they are also tuned by the fee monitors:
|
|
107
|
+
|
|
108
|
+
- **`baseFeePerGas`:** `50 Gwei` – Reference value for the base gas price. It is quickly updated by the fee monitor.
|
|
109
|
+
- **`gasPrice`:** `75 Gwei` – Reference value for the network gas price. It is quickly updated by the fee monitor.
|
|
110
|
+
- **`tipGasPrice`:** `2 Gwei` – Controls the `maxPriorityFeePerGas` for all transactions when EIP-1559 is enabled.
|
|
111
|
+
- **`eip1559Enabled`:** `true` – Enables or disables EIP-1559. A value of `false` means legacy fees and transactions.
|
|
112
|
+
- **`rbfEnabled`:** `true` – Enables custom fees and acceleration. Currently, this is only available for Ethereum but can be expanded to other EVMs.
|
|
113
|
+
- **`gasPriceMaximumRate`:** `1.3` – Controls the maximum value in the custom fee slider.
|
|
114
|
+
- **`gasPriceMinimumRate`:** `0.5` – Controls the minimum value in the custom fee slider.
|
|
115
|
+
- **`gasPriceMultiplier`:** `1` – Controls the `gasPrice` and `maxFeePerGas` of transactions, resolved as `current gas price * this multiplier`.
|
|
116
|
+
- **`max`:** `250 Gwei` – Controls the maximum gas price value that can be set.
|
|
117
|
+
- **`min`:** `1 Gwei` – Controls the minimum gas price value that can be set.
|
|
118
|
+
- **`fuelThreshold`:** `0.025 ETH` – If the balance falls below this value and the user holds tokens, a low balance warning is displayed.
|
|
119
|
+
- **`enableFeeDelegation`:** `false` – Not implemented.
|
|
120
|
+
- **`origin`:** `75 Gwei` – Legacy; consider removing.
|
|
121
|
+
- **`swapFee`:** `0.05 ETH` – Legacy; consider removing.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-api",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.24.1",
|
|
4
4
|
"description": "Transaction monitors, fee monitors, RPC with the blockchain node, and other networking code for Ethereum and EVM-based blockchains",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"!src/**/__tests__"
|
|
11
11
|
],
|
|
12
12
|
"author": "Exodus Movement, Inc.",
|
|
13
|
-
"license": "
|
|
13
|
+
"license": "MIT",
|
|
14
14
|
"homepage": "https://github.com/ExodusMovement/assets/tree/master/ethereum/ethereum-api",
|
|
15
15
|
"publishConfig": {
|
|
16
|
-
"access": "
|
|
16
|
+
"access": "public"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
19
|
"test": "run -T exodus-test --jest",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@exodus/bip44-constants": "^195.0.0",
|
|
29
29
|
"@exodus/crypto": "^1.0.0-rc.13",
|
|
30
30
|
"@exodus/currency": "^6.0.1",
|
|
31
|
-
"@exodus/ethereum-lib": "^5.8.
|
|
31
|
+
"@exodus/ethereum-lib": "^5.8.2",
|
|
32
32
|
"@exodus/ethereum-meta": "^2.1.5",
|
|
33
33
|
"@exodus/ethereumholesky-meta": "^2.0.0",
|
|
34
34
|
"@exodus/ethereumjs": "^1.0.0",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@exodus/solidity-contract": "^1.1.3",
|
|
39
39
|
"@exodus/web3-ethereum-utils": "^3.27.1",
|
|
40
40
|
"bn.js": "^5.2.1",
|
|
41
|
+
"delay": "^4.0.1",
|
|
41
42
|
"events": "^1.1.1",
|
|
42
43
|
"idna-uts46-hx": "^2.3.1",
|
|
43
44
|
"lodash": "^4.17.15",
|
|
@@ -54,8 +55,7 @@
|
|
|
54
55
|
"@exodus/ethereumgoerli-meta": "^2.0.0",
|
|
55
56
|
"@exodus/ethereumsepolia-meta": "^2.0.0",
|
|
56
57
|
"@exodus/fantommainnet-meta": "^2.0.0",
|
|
57
|
-
"@exodus/rootstock-meta": "^2.0.0"
|
|
58
|
-
"delay": "4.0.1"
|
|
58
|
+
"@exodus/rootstock-meta": "^2.0.0"
|
|
59
59
|
},
|
|
60
60
|
"bugs": {
|
|
61
61
|
"url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Aethereum-api"
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"type": "git",
|
|
65
65
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "9f590f5439d73cba02054d608fb3d5c62fbdcf34"
|
|
68
68
|
}
|
|
@@ -3,6 +3,7 @@ import { isNumberUnit } from '@exodus/currency'
|
|
|
3
3
|
import { getServer } from '../../exodus-eth-server/index.js'
|
|
4
4
|
import { estimateGasLimit } from '../../gas-estimation.js'
|
|
5
5
|
import { fromHexToBigInt } from '../../number-utils.js'
|
|
6
|
+
import { createWatchTx as defaultCreateWatch } from '../../watch-tx.js'
|
|
6
7
|
import { stakingProviderClientFactory } from '../staking-provider-client.js'
|
|
7
8
|
import { EthereumStaking } from './api.js'
|
|
8
9
|
|
|
@@ -11,7 +12,7 @@ const extraGasLimit = 20_000 // extra gas Limit to prevent tx failing if somethi
|
|
|
11
12
|
export function createEthereumStakingService({
|
|
12
13
|
asset,
|
|
13
14
|
assetClientInterface,
|
|
14
|
-
|
|
15
|
+
createWatchTx = defaultCreateWatch,
|
|
15
16
|
}) {
|
|
16
17
|
const staking = new EthereumStaking(asset)
|
|
17
18
|
const stakingProvider = stakingProviderClientFactory()
|
|
@@ -33,7 +34,7 @@ export function createEthereumStakingService({
|
|
|
33
34
|
amount,
|
|
34
35
|
})
|
|
35
36
|
|
|
36
|
-
const { gasPrice, gasLimit
|
|
37
|
+
const { gasPrice, gasLimit } = await estimateTxFee(delegatorAddress, to, amount, data)
|
|
37
38
|
|
|
38
39
|
console.log(
|
|
39
40
|
`delegator address ${delegatorAddress} staking ${amount.toDefaultString({
|
|
@@ -48,7 +49,6 @@ export function createEthereumStakingService({
|
|
|
48
49
|
txData: data,
|
|
49
50
|
gasPrice,
|
|
50
51
|
gasLimit,
|
|
51
|
-
fee,
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
// Goerli is not supported
|
|
@@ -226,7 +226,7 @@ export function createEthereumStakingService({
|
|
|
226
226
|
})
|
|
227
227
|
if (withdrawRequest) {
|
|
228
228
|
const { to, data } = withdrawRequest
|
|
229
|
-
const { gasPrice, gasLimit
|
|
229
|
+
const { gasPrice, gasLimit } = await estimateTxFee(delegatorAddress, to, null, data)
|
|
230
230
|
return prepareAndSendTx({
|
|
231
231
|
asset,
|
|
232
232
|
walletAccount,
|
|
@@ -234,7 +234,6 @@ export function createEthereumStakingService({
|
|
|
234
234
|
txData: data,
|
|
235
235
|
gasPrice,
|
|
236
236
|
gasLimit,
|
|
237
|
-
fee,
|
|
238
237
|
})
|
|
239
238
|
}
|
|
240
239
|
}
|
|
@@ -314,7 +313,6 @@ export function createEthereumStakingService({
|
|
|
314
313
|
txData: txInput,
|
|
315
314
|
gasPrice,
|
|
316
315
|
gasLimit,
|
|
317
|
-
fee,
|
|
318
316
|
waitForConfirmation = false,
|
|
319
317
|
} = Object.create(null)
|
|
320
318
|
) {
|
|
@@ -323,28 +321,27 @@ export function createEthereumStakingService({
|
|
|
323
321
|
walletAccount,
|
|
324
322
|
address: to,
|
|
325
323
|
amount: amount || asset.currency.ZERO,
|
|
326
|
-
// unified tx-send param
|
|
327
324
|
shouldLog: true,
|
|
328
|
-
txInput,
|
|
329
|
-
feeAmount: fee,
|
|
330
|
-
feeOpts: {
|
|
331
|
-
gasPrice,
|
|
332
|
-
gasLimit,
|
|
333
|
-
},
|
|
334
|
-
// mobile: tx-send parms
|
|
335
325
|
options: {
|
|
336
326
|
shouldLog: true,
|
|
337
327
|
txInput,
|
|
338
328
|
gasPrice,
|
|
339
329
|
gasLimit,
|
|
340
|
-
feeAmount: fee,
|
|
341
330
|
},
|
|
342
|
-
waitForConfirmation,
|
|
343
331
|
}
|
|
344
332
|
|
|
345
|
-
|
|
333
|
+
const { txId } = await asset.baseAsset.api.sendTx(sendTxArgs)
|
|
346
334
|
|
|
347
|
-
const
|
|
335
|
+
const baseAsset = asset.baseAsset
|
|
336
|
+
if (waitForConfirmation) {
|
|
337
|
+
const getTxLog = (...args) => assetClientInterface.getTxLog(...args)
|
|
338
|
+
const watchTx = createWatchTx({
|
|
339
|
+
walletAccount,
|
|
340
|
+
getTxLog,
|
|
341
|
+
baseAsset,
|
|
342
|
+
})
|
|
343
|
+
await watchTx(txId)
|
|
344
|
+
}
|
|
348
345
|
|
|
349
346
|
return txId
|
|
350
347
|
}
|
|
@@ -3,10 +3,14 @@ import BN from 'bn.js'
|
|
|
3
3
|
|
|
4
4
|
import { getServer } from '../../exodus-eth-server/index.js'
|
|
5
5
|
import { estimateGasLimit } from '../../gas-estimation.js'
|
|
6
|
+
import { createWatchTx as defaultCreateWatch } from '../../watch-tx.js'
|
|
6
7
|
import { stakingProviderClientFactory } from '../staking-provider-client.js'
|
|
7
8
|
import { MaticStakingApi } from './api.js'
|
|
8
9
|
|
|
9
|
-
export function createPolygonStakingService({
|
|
10
|
+
export function createPolygonStakingService({
|
|
11
|
+
assetClientInterface,
|
|
12
|
+
createWatchTx = defaultCreateWatch,
|
|
13
|
+
}) {
|
|
10
14
|
const stakingApi = new MaticStakingApi()
|
|
11
15
|
const assetName = 'ethereum'
|
|
12
16
|
const stakingProvider = stakingProviderClientFactory()
|
|
@@ -33,7 +37,7 @@ export function createPolygonStakingService({ assetClientInterface, createAndBro
|
|
|
33
37
|
amount = amountToCurrency({ asset, amount })
|
|
34
38
|
|
|
35
39
|
const txApproveData = await stakingApi.approveStakeManager(amount)
|
|
36
|
-
let { gasPrice, gasLimit
|
|
40
|
+
let { gasPrice, gasLimit } = await estimateTxFee(
|
|
37
41
|
delegatorAddress,
|
|
38
42
|
stakingApi.polygonContract.address,
|
|
39
43
|
txApproveData
|
|
@@ -45,11 +49,10 @@ export function createPolygonStakingService({ assetClientInterface, createAndBro
|
|
|
45
49
|
txData: txApproveData,
|
|
46
50
|
gasPrice,
|
|
47
51
|
gasLimit,
|
|
48
|
-
fee,
|
|
49
52
|
})
|
|
50
53
|
|
|
51
54
|
const txDelegateData = await stakingApi.delegate({ amount })
|
|
52
|
-
;({ gasPrice, gasLimit
|
|
55
|
+
;({ gasPrice, gasLimit } = await estimateTxFee(
|
|
53
56
|
delegatorAddress,
|
|
54
57
|
stakingApi.validatorShareContract.address,
|
|
55
58
|
txDelegateData
|
|
@@ -61,7 +64,6 @@ export function createPolygonStakingService({ assetClientInterface, createAndBro
|
|
|
61
64
|
txData: txDelegateData,
|
|
62
65
|
gasPrice,
|
|
63
66
|
gasLimit,
|
|
64
|
-
fee,
|
|
65
67
|
})
|
|
66
68
|
|
|
67
69
|
await stakingProvider.notifyStaking({
|
|
@@ -85,7 +87,7 @@ export function createPolygonStakingService({ assetClientInterface, createAndBro
|
|
|
85
87
|
amount = amountToCurrency({ asset, amount })
|
|
86
88
|
|
|
87
89
|
const txUndelegateData = await stakingApi.undelegate({ amount })
|
|
88
|
-
const { gasPrice, gasLimit
|
|
90
|
+
const { gasPrice, gasLimit } = await estimateTxFee(
|
|
89
91
|
delegatorAddress.toLowerCase(),
|
|
90
92
|
stakingApi.validatorShareContract.address,
|
|
91
93
|
txUndelegateData
|
|
@@ -96,7 +98,6 @@ export function createPolygonStakingService({ assetClientInterface, createAndBro
|
|
|
96
98
|
txData: txUndelegateData,
|
|
97
99
|
gasPrice,
|
|
98
100
|
gasLimit,
|
|
99
|
-
fee,
|
|
100
101
|
})
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -108,7 +109,7 @@ export function createPolygonStakingService({ assetClientInterface, createAndBro
|
|
|
108
109
|
const delegatorAddress = address.toLowerCase()
|
|
109
110
|
|
|
110
111
|
const txWithdrawRewardsData = await stakingApi.withdrawRewards()
|
|
111
|
-
const { gasPrice, gasLimit
|
|
112
|
+
const { gasPrice, gasLimit } = await estimateTxFee(
|
|
112
113
|
delegatorAddress,
|
|
113
114
|
stakingApi.validatorShareContract.address,
|
|
114
115
|
txWithdrawRewardsData
|
|
@@ -119,7 +120,6 @@ export function createPolygonStakingService({ assetClientInterface, createAndBro
|
|
|
119
120
|
txData: txWithdrawRewardsData,
|
|
120
121
|
gasPrice,
|
|
121
122
|
gasLimit,
|
|
122
|
-
fee,
|
|
123
123
|
})
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -267,37 +267,37 @@ export function createPolygonStakingService({ assetClientInterface, createAndBro
|
|
|
267
267
|
txData: txInput,
|
|
268
268
|
gasPrice,
|
|
269
269
|
gasLimit,
|
|
270
|
-
fee,
|
|
271
270
|
waitForConfirmation = false,
|
|
272
271
|
} = {}) {
|
|
273
|
-
const { ethereum } = await assetClientInterface.getAssetsForNetwork({
|
|
272
|
+
const { ethereum: asset } = await assetClientInterface.getAssetsForNetwork({
|
|
274
273
|
baseAssetName: 'ethereum',
|
|
275
274
|
})
|
|
276
275
|
const sendTxArgs = {
|
|
277
|
-
asset
|
|
276
|
+
asset,
|
|
278
277
|
walletAccount,
|
|
279
278
|
address: to,
|
|
280
|
-
amount:
|
|
281
|
-
// unified tx-send param
|
|
282
|
-
shouldLog: true,
|
|
283
|
-
txInput,
|
|
284
|
-
feeAmount: fee,
|
|
285
|
-
feeOpts: {
|
|
286
|
-
gasPrice,
|
|
287
|
-
gasLimit,
|
|
288
|
-
},
|
|
289
|
-
// mobile: tx-send parms
|
|
279
|
+
amount: asset.currency.ZERO,
|
|
290
280
|
options: {
|
|
291
281
|
shouldLog: true,
|
|
292
282
|
txInput,
|
|
293
283
|
gasPrice,
|
|
294
284
|
gasLimit,
|
|
295
|
-
feeAmount: fee,
|
|
296
285
|
},
|
|
297
286
|
waitForConfirmation,
|
|
298
287
|
}
|
|
299
288
|
|
|
300
|
-
const { txId } = await
|
|
289
|
+
const { txId } = await asset.baseAsset.api.sendTx(sendTxArgs)
|
|
290
|
+
|
|
291
|
+
const baseAsset = asset.baseAsset
|
|
292
|
+
if (waitForConfirmation) {
|
|
293
|
+
const getTxLog = (...args) => assetClientInterface.getTxLog(...args)
|
|
294
|
+
const watchTx = createWatchTx({
|
|
295
|
+
walletAccount,
|
|
296
|
+
getTxLog,
|
|
297
|
+
baseAsset,
|
|
298
|
+
})
|
|
299
|
+
await watchTx(txId)
|
|
300
|
+
}
|
|
301
301
|
|
|
302
302
|
return txId
|
|
303
303
|
}
|
package/src/watch-tx.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import delay from 'delay'
|
|
2
|
+
import ms from 'ms'
|
|
3
|
+
|
|
4
|
+
const WATCH_TX_DELAY = ms('5s')
|
|
5
|
+
const WATCH_TX_TIMEOUT = ms('5m')
|
|
6
|
+
|
|
7
|
+
// this could go to asset-lib
|
|
8
|
+
export const createWatchTx =
|
|
9
|
+
({
|
|
10
|
+
walletAccount,
|
|
11
|
+
getTxLog,
|
|
12
|
+
baseAsset,
|
|
13
|
+
watchTxDelay = WATCH_TX_DELAY,
|
|
14
|
+
watchTxTimeout = WATCH_TX_TIMEOUT,
|
|
15
|
+
}) =>
|
|
16
|
+
async (txId) => {
|
|
17
|
+
const start = Date.now()
|
|
18
|
+
let txConfirmed = false
|
|
19
|
+
let hasTimedOut = false
|
|
20
|
+
|
|
21
|
+
while (!hasTimedOut && !txConfirmed) {
|
|
22
|
+
await delay(watchTxDelay)
|
|
23
|
+
const baseAssetTxLog = await getTxLog({
|
|
24
|
+
assetName: baseAsset.name,
|
|
25
|
+
walletAccount,
|
|
26
|
+
})
|
|
27
|
+
txConfirmed = baseAssetTxLog.get(txId)?.confirmed
|
|
28
|
+
hasTimedOut = Date.now() - start > watchTxTimeout
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { txId, confirmed: txConfirmed, hasTimedOut }
|
|
32
|
+
}
|