@exodus/ethereum-api 8.23.2 → 8.24.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 CHANGED
@@ -3,6 +3,16 @@
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.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.23.2...@exodus/ethereum-api@8.24.0) (2024-12-17)
7
+
8
+
9
+ ### Features
10
+
11
+
12
+ * feat: evm staking send simplification (#4681)
13
+
14
+
15
+
6
16
  ## [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
17
 
8
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-api",
3
- "version": "8.23.2",
3
+ "version": "8.24.0",
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",
@@ -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": "2036bf64aa16ee26a864a4aa971b050fc4631104"
67
+ "gitHead": "cb07ad7e423a04b4da350bbf159e55b4490e3eae"
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
- createAndBroadcastTX,
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, fee } = await estimateTxFee(delegatorAddress, to, amount, data)
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, fee } = await estimateTxFee(delegatorAddress, to, null, data)
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
- console.log('sending staking tx:', sendTxArgs)
333
+ const { txId } = await asset.baseAsset.api.sendTx(sendTxArgs)
346
334
 
347
- const { txId } = await createAndBroadcastTX(sendTxArgs)
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({ assetClientInterface, createAndBroadcastTX }) {
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, fee } = await estimateTxFee(
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, fee } = await estimateTxFee(
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, fee } = await estimateTxFee(
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, fee } = await estimateTxFee(
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: ethereum,
276
+ asset,
278
277
  walletAccount,
279
278
  address: to,
280
- amount: ethereum.currency.ZERO,
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 createAndBroadcastTX(sendTxArgs)
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
  }
@@ -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
+ }