@exodus/ethereum-api 8.73.1 → 8.73.3
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 +24 -0
- package/package.json +4 -5
- package/src/error-wrapper.js +7 -4
- package/src/staking/ethereum/api.js +22 -3
- package/src/staking/ethereum/everstake.js +53 -0
- package/src/staking/ethereum/service.js +382 -141
- package/src/staking/ethereum/staking-utils.js +268 -1
- package/src/tx-log/get-optimistic-txlog-effects.js +49 -0
- package/src/tx-log-staking-processor/asset-staking-tx-data.js +40 -13
- package/src/tx-log-staking-processor/index.js +9 -13
- package/src/tx-send/nonce-utils.js +3 -1
- package/src/etherscan/account.js +0 -50
- package/src/etherscan/index.js +0 -28
- package/src/etherscan/logs.js +0 -17
- package/src/etherscan/proxy.js +0 -48
- package/src/etherscan/request.js +0 -26
- package/src/etherscan/ws.js +0 -88
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,30 @@
|
|
|
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.73.3](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.73.2...@exodus/ethereum-api@8.73.3) (2026-05-06)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: correct misleading assertion and error messages (#7965)
|
|
13
|
+
|
|
14
|
+
* fix(ethereum-api): avoid mutating caller's txLog in resolveNonce (#7996)
|
|
15
|
+
|
|
16
|
+
* fix(ethereum-api): filter hints before pushing to stack in EthLikeError (#7991)
|
|
17
|
+
|
|
18
|
+
* fix: missing matic claim unstake transactions (#8006)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## [8.73.2](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.73.1...@exodus/ethereum-api@8.73.2) (2026-05-05)
|
|
23
|
+
|
|
24
|
+
**Note:** Version bump only for package @exodus/ethereum-api
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
6
30
|
## [8.73.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.73.0...@exodus/ethereum-api@8.73.1) (2026-05-04)
|
|
7
31
|
|
|
8
32
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-api",
|
|
3
|
-
"version": "8.73.
|
|
3
|
+
"version": "8.73.3",
|
|
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",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@exodus/simple-retry": "^0.0.6",
|
|
40
40
|
"@exodus/solidity-contract": "^1.3.0",
|
|
41
41
|
"@exodus/traceparent": "^3.0.1",
|
|
42
|
-
"@exodus/web3-ethereum-utils": "^4.
|
|
42
|
+
"@exodus/web3-ethereum-utils": "^4.7.4",
|
|
43
43
|
"bn.js": "^5.2.1",
|
|
44
44
|
"delay": "^4.0.1",
|
|
45
45
|
"eventemitter3": "^4.0.7",
|
|
@@ -49,8 +49,7 @@
|
|
|
49
49
|
"make-concurrent": "^4.0.0",
|
|
50
50
|
"minimalistic-assert": "^1.0.1",
|
|
51
51
|
"ms": "^2.1.1",
|
|
52
|
-
"socket.io-client": "^2.1.1"
|
|
53
|
-
"ws": "^6.1.0"
|
|
52
|
+
"socket.io-client": "^2.1.1"
|
|
54
53
|
},
|
|
55
54
|
"devDependencies": {
|
|
56
55
|
"@exodus/assets-testing": "^1.0.0",
|
|
@@ -68,5 +67,5 @@
|
|
|
68
67
|
"type": "git",
|
|
69
68
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
70
69
|
},
|
|
71
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "fe7c27f31aa14bf777660af02300c92def4b4a8c"
|
|
72
71
|
}
|
package/src/error-wrapper.js
CHANGED
|
@@ -293,9 +293,12 @@ export class EthLikeError extends Error {
|
|
|
293
293
|
constructor({ message, errorReasonInfo, hint, traceId, baseAssetName }) {
|
|
294
294
|
super(message)
|
|
295
295
|
this.name = safeString`EthLikeError`
|
|
296
|
-
|
|
296
|
+
const filteredHint = this.#extractHint(hint)
|
|
297
|
+
// Only filtered hints are kept on the stack so that subsequent joins via
|
|
298
|
+
// `addHint` cannot leak sensitive info or untruncated content.
|
|
299
|
+
this.#hintStack = filteredHint ? [filteredHint] : []
|
|
297
300
|
this.reason = errorReasonInfo.reason
|
|
298
|
-
this.hint =
|
|
301
|
+
this.hint = filteredHint
|
|
299
302
|
this.type = errorReasonInfo.type
|
|
300
303
|
this.traceId = traceId
|
|
301
304
|
this.baseAssetName = baseAssetName
|
|
@@ -307,8 +310,8 @@ export class EthLikeError extends Error {
|
|
|
307
310
|
return this
|
|
308
311
|
}
|
|
309
312
|
|
|
310
|
-
this.#hintStack.push(
|
|
311
|
-
this.hint =
|
|
313
|
+
this.#hintStack.push(filteredHint)
|
|
314
|
+
this.hint = this.#hintStack.join(':')
|
|
312
315
|
return this
|
|
313
316
|
}
|
|
314
317
|
|
|
@@ -12,6 +12,11 @@ const RETRY_DELAYS = ['10s']
|
|
|
12
12
|
|
|
13
13
|
const EVERSTAKE_API_URL = 'https://eth-clarity.a.exodus.io/everstake-rewards'
|
|
14
14
|
|
|
15
|
+
export const UNSTAKE_DEFAULTS = {
|
|
16
|
+
allowedInterchangeNum: 0,
|
|
17
|
+
source: '2',
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
export class EthereumStaking {
|
|
16
21
|
static addresses = {
|
|
17
22
|
ethereum: {
|
|
@@ -229,8 +234,22 @@ export class EthereumStaking {
|
|
|
229
234
|
throw new Error(`Min Amount ${this.minAmount}`)
|
|
230
235
|
}
|
|
231
236
|
|
|
232
|
-
|
|
233
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Unstake funds from the validator. The unstaked amount enters a withdrawal
|
|
239
|
+
* queue and must be claimed via `claimWithdrawRequest` after the validator exits.
|
|
240
|
+
*
|
|
241
|
+
* @param {number} allowedInterchangeNum - Max number of incoming stake requests
|
|
242
|
+
* the contract may use to immediately return ETH to the unstaker (interchange).
|
|
243
|
+
* When 0 (default), no interchange occurs and the full amount is queued.
|
|
244
|
+
* When > 0, the contract may match up to N new stakers' deposits against this
|
|
245
|
+
* unstake, returning ETH immediately without waiting for validator exit.
|
|
246
|
+
*/
|
|
247
|
+
async unstake({
|
|
248
|
+
address,
|
|
249
|
+
amount,
|
|
250
|
+
allowedInterchangeNum = UNSTAKE_DEFAULTS.allowedInterchangeNum,
|
|
251
|
+
source = UNSTAKE_DEFAULTS.source,
|
|
252
|
+
}) {
|
|
234
253
|
const amountWei = amount.toBaseString()
|
|
235
254
|
const balance = await this.autocompoundBalanceOf(address) // amount staked into the validator (active balance)
|
|
236
255
|
|
|
@@ -281,7 +300,7 @@ export class EthereumStaking {
|
|
|
281
300
|
throw new Error(err)
|
|
282
301
|
}
|
|
283
302
|
} else {
|
|
284
|
-
throw new Error(`
|
|
303
|
+
throw new Error(`Max Amount for unstakePending ${pendingBalance}`)
|
|
285
304
|
}
|
|
286
305
|
}
|
|
287
306
|
}
|
|
@@ -2,7 +2,10 @@ import { fetch as exodusFetch } from '@exodus/fetch'
|
|
|
2
2
|
import { TraceId } from '@exodus/traceparent'
|
|
3
3
|
import assert from 'minimalistic-assert'
|
|
4
4
|
|
|
5
|
+
import { UNSTAKE_DEFAULTS } from './api.js'
|
|
6
|
+
|
|
5
7
|
const BASE_URL = 'https://eth-clarity.a.exodus.io/api/v2/ethereum/proxy/everstake/'
|
|
8
|
+
const WALLET_SDK_BASE_URL = 'https://wallet-sdk-api.everstake.one/'
|
|
6
9
|
|
|
7
10
|
const fetch = async (path, config = Object.create(null)) => {
|
|
8
11
|
const url = new URL(path, BASE_URL).toString()
|
|
@@ -26,6 +29,56 @@ const fetch = async (path, config = Object.create(null)) => {
|
|
|
26
29
|
|
|
27
30
|
const isFiniteInteger = (e) => Number.isInteger(e) && Number.isFinite(e)
|
|
28
31
|
|
|
32
|
+
// Simulate an unstake to predict how much ETH the interchange pool returns instantly.
|
|
33
|
+
// https://wallet-sdk-api.everstake.one/swagger/#/Ethereum/post_ethereum_pool_simulate_unstake
|
|
34
|
+
//
|
|
35
|
+
// Inputs:
|
|
36
|
+
// address: staker address (0x...)
|
|
37
|
+
// amount: unstake amount in ETH (default units), e.g. "1.5" — NOT wei
|
|
38
|
+
// allowedInterchangeNum: interchange pool parameter (default from UNSTAKE_DEFAULTS)
|
|
39
|
+
// source: source identifier (default from UNSTAKE_DEFAULTS)
|
|
40
|
+
//
|
|
41
|
+
// Success (200): { result: <number> } — ETH returned instantly (capped by pool liquidity)
|
|
42
|
+
// Error (500): { "Internal Server Error": "Error: Max Amount For Unstake <max_eth>" }
|
|
43
|
+
// when amount exceeds the staker's active balance
|
|
44
|
+
export const simulateEverstakeUnstake = async ({
|
|
45
|
+
address,
|
|
46
|
+
amount,
|
|
47
|
+
allowedInterchangeNum = UNSTAKE_DEFAULTS.allowedInterchangeNum,
|
|
48
|
+
source = UNSTAKE_DEFAULTS.source,
|
|
49
|
+
}) => {
|
|
50
|
+
try {
|
|
51
|
+
assert(typeof address === 'string' && address.startsWith('0x'), 'expected valid address')
|
|
52
|
+
assert(typeof amount === 'string' && amount.length > 0, 'expected amount in ETH as string')
|
|
53
|
+
|
|
54
|
+
const url = new URL('ethereum/pool/simulate_unstake', WALLET_SDK_BASE_URL).toString()
|
|
55
|
+
|
|
56
|
+
const response = await exodusFetch(url, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: { 'Content-Type': 'application/json' },
|
|
59
|
+
body: JSON.stringify({ address, amount, allowedInterchangeNum, source }),
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
const body = await response.json().catch(() => null)
|
|
64
|
+
const serverMsg = body?.['Internal Server Error'] || response.statusText
|
|
65
|
+
console.warn(`simulate_unstake failed: ${serverMsg}`)
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const data = await response.json()
|
|
70
|
+
if (!data || typeof data.result !== 'number') {
|
|
71
|
+
console.warn('simulate_unstake: malformed response', data)
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { instantReturnEth: data.result }
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.warn('simulate_unstake error:', e.message)
|
|
78
|
+
return null
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
29
82
|
export const getEverstakeValidatorsQueue = async () => {
|
|
30
83
|
// https://swagger.eth-api-b2c.everstake.one/#/Staking/validatorsQueue
|
|
31
84
|
const result = await fetch('v1/validators/queue')
|