@exodus/ethereum-api 10.0.0 → 10.1.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 +18 -0
- package/package.json +3 -3
- package/src/create-asset-utils.js +6 -6
- package/src/create-asset.js +32 -10
- package/src/create-token-factory.js +18 -7
- package/src/index.js +15 -0
- package/src/staking/api/index.js +2 -1
- package/src/staking/ethereum/api.js +2 -3
- package/src/staking/ethereum/deps.js +3 -0
- package/src/staking/ethereum/min-amount.js +1 -0
- package/src/staking/ethereum/service.js +148 -123
- package/src/staking/ethereum/staking-adapter.js +382 -0
- package/src/staking/evm/compose-staking-api.js +42 -0
- package/src/staking/evm/create-evm-staking-api.js +269 -0
- package/src/staking/evm/staking-errors.js +37 -0
- package/src/staking/evm/staking-txs.js +107 -0
- package/src/staking/matic/index.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,24 @@
|
|
|
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
|
+
## [10.1.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@10.1.0...@exodus/ethereum-api@10.1.1) (2026-10-09)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* migrate to @exodus/basic-utils 5 ([#8894](https://github.com/ExodusMovement/assets/issues/8894)) ([ed125f3](https://github.com/ExodusMovement/assets/commit/ed125f3257785c92a3b8f8239a2e9eefe5dc6772))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## [10.1.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@10.0.0...@exodus/ethereum-api@10.1.0) (2026-10-05)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **ethereum:** add evm staking api core with Everstake ETH and polygon adapters ([#8775](https://github.com/ExodusMovement/assets/issues/8775)) ([2d90106](https://github.com/ExodusMovement/assets/commit/2d901069989be82eb56aa253d5171e4f6af97356))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
6
24
|
## [10.0.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@9.0.3...@exodus/ethereum-api@10.0.0) (2026-10-05)
|
|
7
25
|
|
|
8
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-api",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.1.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",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@exodus/asset": "^2.0.4",
|
|
24
24
|
"@exodus/asset-lib": "^5.9.2",
|
|
25
25
|
"@exodus/assets": "^11.4.0",
|
|
26
|
-
"@exodus/basic-utils": "^
|
|
26
|
+
"@exodus/basic-utils": "^5.1.0",
|
|
27
27
|
"@exodus/bip44-constants": "^195.0.0",
|
|
28
28
|
"@exodus/crypto": "^1.0.0-rc.26",
|
|
29
29
|
"@exodus/currency": "^6.0.1",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"type": "git",
|
|
67
67
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "41e6c1bb6a3d919f08cc3ee38068159259b335be"
|
|
70
70
|
}
|
|
@@ -176,7 +176,7 @@ export const createTransactionPrivacyResult = ({
|
|
|
176
176
|
return { nonce, txId }
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
const sendPrivateBundle = async ({ unsignedTxBundle }) => {
|
|
179
|
+
const sendPrivateBundle = async ({ unsignedTxBundle, onBeforeSign }) => {
|
|
180
180
|
assert(
|
|
181
181
|
Array.isArray(unsignedTxBundle) && unsignedTxBundle.length > 0,
|
|
182
182
|
'expected non-empty unsignedTxBundle'
|
|
@@ -188,11 +188,11 @@ export const createTransactionPrivacyResult = ({
|
|
|
188
188
|
await assertNonZeroTipGasPrice({ asset, assetClientInterface, unsignedTx })
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
const signTxResults =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
)
|
|
195
|
-
|
|
191
|
+
const signTxResults = []
|
|
192
|
+
for (const [index, { asset, unsignedTx, walletAccount }] of unsignedTxBundle.entries()) {
|
|
193
|
+
onBeforeSign?.({ index, total: unsignedTxBundle.length })
|
|
194
|
+
signTxResults.push(await signTx({ assetClientInterface, asset, unsignedTx, walletAccount }))
|
|
195
|
+
}
|
|
196
196
|
|
|
197
197
|
const maybeBundleResult = await broadcastPrivateBundle({
|
|
198
198
|
txs: signTxResults.map(({ rawTx }) => rawTx.toString('hex')),
|
package/src/create-asset.js
CHANGED
|
@@ -49,6 +49,11 @@ import { estimateL1DataFeeFactory, getL1GetFeeFactory } from './optimism-gas/ind
|
|
|
49
49
|
import { createSendValidations } from './send-validations.js'
|
|
50
50
|
import { serverBasedFeeMonitorFactoryFactory } from './server-based-fee-monitor.js'
|
|
51
51
|
import { stakingApiFactory } from './staking/api/index.js'
|
|
52
|
+
import {
|
|
53
|
+
applyStakingApiOverrides,
|
|
54
|
+
composeStakingApi,
|
|
55
|
+
isStakingApiEnabled,
|
|
56
|
+
} from './staking/evm/compose-staking-api.js'
|
|
52
57
|
import { createTxFactory } from './tx-create.js'
|
|
53
58
|
import { txSendFactory } from './tx-send/index.js'
|
|
54
59
|
import { createWeb3API } from './web3/index.js'
|
|
@@ -135,8 +140,14 @@ export const createAssetFactory = ({
|
|
|
135
140
|
supportsTransactionPrivacy,
|
|
136
141
|
transactionAssessment,
|
|
137
142
|
multicall3Address,
|
|
143
|
+
stakingApiEnabled: stakingApiOverrides,
|
|
138
144
|
} = configWithOverrides
|
|
139
145
|
|
|
146
|
+
const assetStakingDependencies = applyStakingApiOverrides({
|
|
147
|
+
stakingDependencies,
|
|
148
|
+
overrides: stakingApiOverrides,
|
|
149
|
+
})
|
|
150
|
+
|
|
140
151
|
const asset = assets[base.name]
|
|
141
152
|
|
|
142
153
|
const { monitorType, serverUrl, monitorInterval } = resolveMonitorSettings({
|
|
@@ -206,7 +217,7 @@ export const createAssetFactory = ({
|
|
|
206
217
|
assetClientInterface,
|
|
207
218
|
server,
|
|
208
219
|
stakingConfiguration,
|
|
209
|
-
stakingDependencies,
|
|
220
|
+
stakingDependencies: assetStakingDependencies,
|
|
210
221
|
createRpcRequestAccumulator,
|
|
211
222
|
},
|
|
212
223
|
assets
|
|
@@ -236,6 +247,23 @@ export const createAssetFactory = ({
|
|
|
236
247
|
supportsTransactionPrivacy,
|
|
237
248
|
})
|
|
238
249
|
|
|
250
|
+
const stakingApiEnabled =
|
|
251
|
+
supportsStaking && isStakingApiEnabled(assetStakingDependencies[asset.name])
|
|
252
|
+
|
|
253
|
+
const createAssetStakingApi = () =>
|
|
254
|
+
composeStakingApi({
|
|
255
|
+
assetClientInterface,
|
|
256
|
+
stakingDependencies: assetStakingDependencies[asset.name],
|
|
257
|
+
legacyStakingApi: stakingApiFactory({
|
|
258
|
+
assetName: asset.name,
|
|
259
|
+
currency: asset.currency,
|
|
260
|
+
assetClientInterface,
|
|
261
|
+
server,
|
|
262
|
+
stakingConfiguration: stakingConfiguration[asset.name],
|
|
263
|
+
stakingDependencies: assetStakingDependencies[asset.name],
|
|
264
|
+
}),
|
|
265
|
+
})
|
|
266
|
+
|
|
239
267
|
const features = {
|
|
240
268
|
accountState: true,
|
|
241
269
|
customTokens,
|
|
@@ -254,6 +282,7 @@ export const createAssetFactory = ({
|
|
|
254
282
|
supportsCustomFees,
|
|
255
283
|
supportsTransactionPrivacy: Boolean(supportsTransactionPrivacy),
|
|
256
284
|
...(supportsStaking && { staking: {} }),
|
|
285
|
+
...(stakingApiEnabled && { stakingApi: true }),
|
|
257
286
|
...(delisted && { delisted }),
|
|
258
287
|
}
|
|
259
288
|
|
|
@@ -393,15 +422,8 @@ export const createAssetFactory = ({
|
|
|
393
422
|
signer ? signMessageWithSigner({ message, signer }) : signMessage({ privateKey, message }),
|
|
394
423
|
...(checkTx && { checkTx }),
|
|
395
424
|
...(supportsStaking &&
|
|
396
|
-
|
|
397
|
-
staking:
|
|
398
|
-
assetName: asset.name,
|
|
399
|
-
currency: asset.currency,
|
|
400
|
-
assetClientInterface,
|
|
401
|
-
server,
|
|
402
|
-
stakingConfiguration: stakingConfiguration[asset.name],
|
|
403
|
-
stakingDependencies: stakingDependencies[asset.name],
|
|
404
|
-
}),
|
|
425
|
+
assetStakingDependencies[asset.name] && {
|
|
426
|
+
staking: createAssetStakingApi(),
|
|
405
427
|
}),
|
|
406
428
|
validateAssetId: address.validate,
|
|
407
429
|
web3,
|
|
@@ -3,6 +3,7 @@ import { createContract } from '@exodus/ethereum-lib'
|
|
|
3
3
|
import assert from 'minimalistic-assert'
|
|
4
4
|
|
|
5
5
|
import { stakingApiFactory } from './staking/api/index.js'
|
|
6
|
+
import { composeStakingApi, isStakingApiEnabled } from './staking/evm/compose-staking-api.js'
|
|
6
7
|
import {
|
|
7
8
|
isPolygonClaimUndelegate,
|
|
8
9
|
isPolygonDelegate,
|
|
@@ -48,7 +49,13 @@ const getCreateBaseToken =
|
|
|
48
49
|
}) =>
|
|
49
50
|
({ name, contract, features, ...tokenDef }) => {
|
|
50
51
|
assert(getBalances, 'getBalances is required')
|
|
51
|
-
const tokenSpecificFeatures =
|
|
52
|
+
const tokenSpecificFeatures =
|
|
53
|
+
name === 'polygon'
|
|
54
|
+
? {
|
|
55
|
+
staking: {},
|
|
56
|
+
...(isStakingApiEnabled(stakingDependencies[name]) && { stakingApi: true }),
|
|
57
|
+
}
|
|
58
|
+
: {}
|
|
52
59
|
|
|
53
60
|
const tokenFeatures = { ...defaultTokenFeatures, ...features, ...tokenSpecificFeatures }
|
|
54
61
|
const baseApi = {
|
|
@@ -72,14 +79,18 @@ const getCreateBaseToken =
|
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
if (name === 'polygon' && stakingDependencies[name]) {
|
|
75
|
-
baseApi.staking =
|
|
76
|
-
assetName: tokenAsset.name,
|
|
77
|
-
currency: tokenAsset.currency,
|
|
82
|
+
baseApi.staking = composeStakingApi({
|
|
78
83
|
assetClientInterface,
|
|
79
|
-
server,
|
|
80
|
-
stakingConfiguration: stakingConfiguration[name],
|
|
81
84
|
stakingDependencies: stakingDependencies[name],
|
|
82
|
-
|
|
85
|
+
legacyStakingApi: stakingApiFactory({
|
|
86
|
+
assetName: tokenAsset.name,
|
|
87
|
+
currency: tokenAsset.currency,
|
|
88
|
+
assetClientInterface,
|
|
89
|
+
server,
|
|
90
|
+
stakingConfiguration: stakingConfiguration[name],
|
|
91
|
+
stakingDependencies: stakingDependencies[name],
|
|
92
|
+
createRpcRequestAccumulator,
|
|
93
|
+
}),
|
|
83
94
|
})
|
|
84
95
|
}
|
|
85
96
|
|
package/src/index.js
CHANGED
|
@@ -43,6 +43,20 @@ export { createEncodeMultisigContract } from './multisig-address.js'
|
|
|
43
43
|
export { FantomStaking, stakingProviderClientFactory } from './staking/index.js'
|
|
44
44
|
export { EthLikeRpcRequestAccumulator } from './multicall3/index.js'
|
|
45
45
|
export { createCachedStakingRead } from './staking/cached-read.js'
|
|
46
|
+
export { createStakingTxs, sendStakingTxs, STAKING_TX_MODE } from './staking/evm/staking-txs.js'
|
|
47
|
+
export { createEvmStakingApi } from './staking/evm/create-evm-staking-api.js'
|
|
48
|
+
export {
|
|
49
|
+
createRejectionError as createStakingRejectionError,
|
|
50
|
+
createSubmitError as createStakingSubmitError,
|
|
51
|
+
fail as failStakingCheck,
|
|
52
|
+
pass as passStakingCheck,
|
|
53
|
+
sumOperationFees as sumStakingOperationFees,
|
|
54
|
+
warnIfBelow as warnIfStakingBalanceBelow,
|
|
55
|
+
} from './staking/evm/staking-errors.js'
|
|
56
|
+
export {
|
|
57
|
+
createEverstakeStakingAdapter,
|
|
58
|
+
ETH_STAKING_GAS_LIMITS,
|
|
59
|
+
} from './staking/ethereum/staking-adapter.js'
|
|
46
60
|
export { ethereumStakingDeps } from './staking/ethereum/deps.js'
|
|
47
61
|
export { getEthereumStakingInfo, createEthereumStakingService } from './staking/ethereum/service.js'
|
|
48
62
|
export { EthereumStaking } from './staking/ethereum/api.js'
|
|
@@ -65,6 +79,7 @@ export {
|
|
|
65
79
|
isPolygonReward,
|
|
66
80
|
isPolygonClaimUndelegate,
|
|
67
81
|
isPendingPolygonUndelegateTxInEthereumTxLog,
|
|
82
|
+
isPolygonUndelegateTxInEthereumTxLog,
|
|
68
83
|
} from './staking/matic/matic-staking-utils.js'
|
|
69
84
|
|
|
70
85
|
export { fetchTxPreview } from './simulate-tx/fetch-tx-preview.js'
|
package/src/staking/api/index.js
CHANGED
|
@@ -36,8 +36,9 @@ export const stakingApiFactory = ({
|
|
|
36
36
|
|
|
37
37
|
return {
|
|
38
38
|
...stakingService,
|
|
39
|
+
// @deprecated legacy staking api, remove once evm staking unification is done
|
|
39
40
|
isStaking: async ({ isDelegating }) => isDelegating,
|
|
40
41
|
isUnstaking: async ({ isUndelegateInProgress }) => isUndelegateInProgress,
|
|
41
|
-
isUnstaked: async ({
|
|
42
|
+
isUnstaked: async ({ canClaimUndelegatedBalance }) => canClaimUndelegatedBalance,
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -7,9 +7,8 @@ import assert from 'minimalistic-assert'
|
|
|
7
7
|
import { EVM_ERROR_REASONS, withErrorReason } from '../../error-wrapper.js'
|
|
8
8
|
import { EthLikeRpcRequestAccumulator } from '../../multicall3/index.js'
|
|
9
9
|
import { createCachedStakingRead } from '../cached-read.js'
|
|
10
|
+
import { ETH_STAKING_MIN_AMOUNT } from './min-amount.js'
|
|
10
11
|
|
|
11
|
-
// TODO: Shouldn't this be a function of `ethereumStakingState.minDelegateAmount`?
|
|
12
|
-
const MIN_AMOUNT = '0.1'
|
|
13
12
|
const RETRY_DELAYS = ['10s']
|
|
14
13
|
|
|
15
14
|
const EVERSTAKE_API_URL = 'https://eth-clarity.a.exodus.io/everstake-rewards'
|
|
@@ -46,7 +45,7 @@ export class EthereumStaking {
|
|
|
46
45
|
return txInputHex.toLowerCase().startsWith(EthereumStaking.METHODS_IDS.DELEGATE)
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
constructor(assetName, currency, minAmount =
|
|
48
|
+
constructor(assetName, currency, minAmount = ETH_STAKING_MIN_AMOUNT, server) {
|
|
50
49
|
this.asset = { name: assetName, currency }
|
|
51
50
|
const accountingAddress =
|
|
52
51
|
EthereumStaking.addresses[assetName].EVERSTAKE_ADDRESS_CONTRACT_ACCOUNTING
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EthereumStaking } from './api.js'
|
|
2
2
|
import { createEthereumStakingService, getEthereumStakingInfo } from './service.js'
|
|
3
|
+
import { createEverstakeStakingAdapter } from './staking-adapter.js'
|
|
3
4
|
|
|
4
5
|
/** Staking server factory for ethereum (used by stakingApiFactory). */
|
|
5
6
|
export const stakingServerFactory = ({ assetName, currency, server, minAmount }) =>
|
|
@@ -24,6 +25,7 @@ export const stakingServiceFactory = ({ assetClientInterface, server, stakingSer
|
|
|
24
25
|
useQueueCache,
|
|
25
26
|
background,
|
|
26
27
|
}),
|
|
28
|
+
// @deprecated legacy staking api, remove once evm staking unification is done
|
|
27
29
|
stake: service.delegate,
|
|
28
30
|
unstake: service.undelegate,
|
|
29
31
|
claimUnstaked: service.claimUndelegatedBalance,
|
|
@@ -34,4 +36,5 @@ export const stakingServiceFactory = ({ assetClientInterface, server, stakingSer
|
|
|
34
36
|
export const ethereumStakingDeps = {
|
|
35
37
|
stakingServerFactory,
|
|
36
38
|
stakingServiceFactory,
|
|
39
|
+
createStakingAdapter: ({ service }) => createEverstakeStakingAdapter({ service }),
|
|
37
40
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const ETH_STAKING_MIN_AMOUNT = '0.1'
|