@exodus/ethereum-api 8.53.6 → 8.54.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 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
+ ## [8.54.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.54.0...@exodus/ethereum-api@8.54.1) (2025-10-24)
7
+
8
+ **Note:** Version bump only for package @exodus/ethereum-api
9
+
10
+
11
+
12
+
13
+
14
+ ## [8.54.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.53.6...@exodus/ethereum-api@8.54.0) (2025-10-23)
15
+
16
+
17
+ ### Features
18
+
19
+
20
+ * feat: enable contract deployment via evm asset api (#6742)
21
+
22
+
23
+
6
24
  ## [8.53.6](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.53.5...@exodus/ethereum-api@8.53.6) (2025-10-23)
7
25
 
8
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-api",
3
- "version": "8.53.6",
3
+ "version": "8.54.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",
@@ -29,7 +29,7 @@
29
29
  "@exodus/bip44-constants": "^195.0.0",
30
30
  "@exodus/crypto": "^1.0.0-rc.26",
31
31
  "@exodus/currency": "^6.0.1",
32
- "@exodus/ethereum-lib": "^5.18.2",
32
+ "@exodus/ethereum-lib": "^5.18.3",
33
33
  "@exodus/ethereum-meta": "^2.9.1",
34
34
  "@exodus/ethereumholesky-meta": "^2.0.5",
35
35
  "@exodus/ethereumjs": "^1.8.0",
@@ -67,5 +67,5 @@
67
67
  "type": "git",
68
68
  "url": "git+https://github.com/ExodusMovement/assets.git"
69
69
  },
70
- "gitHead": "124fa7a939418684d2ae50d8db93ff73c59c4cdc"
70
+ "gitHead": "9d2c245deb27cf3ce56eef0d7ad5c0ab8bd4bc02"
71
71
  }
@@ -7,6 +7,8 @@ import BN from 'bn.js'
7
7
  import { getServerByName } from '../../exodus-eth-server/index.js'
8
8
  import { fromHexToBN, fromHexToString, splitIn32BytesArray } from '../../number-utils.js'
9
9
 
10
+ const EVERSTAKE_API_URL = 'https://polygon-clarity.a.exodus.io/everstake-rewards'
11
+
10
12
  const polygonEthToken = ethAssets.find(({ name: tokenName }) => tokenName === 'polygon')
11
13
 
12
14
  const RETRY_DELAYS = ['10s']
@@ -109,6 +111,7 @@ export class MaticStakingApi {
109
111
  }
110
112
 
111
113
  getLiquidRewards = async (address) => {
114
+ // latest accrued rewards
112
115
  const liquidRewards = await this.#callReadFunctionContract(
113
116
  this.validatorShareContract,
114
117
  'getLiquidRewards',
@@ -117,6 +120,29 @@ export class MaticStakingApi {
117
120
  return polygonEthToken.currency.baseUnit(liquidRewards)
118
121
  }
119
122
 
123
+ getTotalRewards = async (address) => {
124
+ // use external everstake API to get total rewards
125
+ const url = new URL(EVERSTAKE_API_URL)
126
+
127
+ const options = {
128
+ method: 'POST',
129
+ headers: { 'Content-Type': 'application/json' },
130
+ body: JSON.stringify({
131
+ address,
132
+ }),
133
+ }
134
+
135
+ try {
136
+ const response = await fetch(url.toString(), options)
137
+ const res = await response.json()
138
+ if (res === 'address' || !res?.rewards) return polygonEthToken.currency.ZERO // address not found
139
+ return polygonEthToken.currency.baseUnit(res.rewards)
140
+ } catch (error) {
141
+ console.warn('Error fetching Polygon total rewards:', error)
142
+ return polygonEthToken.currency.ZERO
143
+ }
144
+ }
145
+
120
146
  getTotalStake = async (address) => {
121
147
  const stakeInfo = await this.#callReadFunctionContract(
122
148
  this.validatorShareContract,
@@ -482,18 +482,19 @@ async function getUnstakedUnclaimedInfo({
482
482
  }
483
483
 
484
484
  async function fetchRewardsInfo({ stakingApi, delegator, currency }) {
485
- const [minRewardsToWithdraw, rewardsBalance] = await Promise.all([
485
+ const [minRewardsToWithdraw, lastRewards, rewardsBalance] = await Promise.all([
486
486
  stakingApi.getMinRewardsToWithdraw(),
487
487
  stakingApi.getLiquidRewards(delegator),
488
+ stakingApi.getTotalRewards(delegator),
488
489
  ])
489
- const withdrawable = rewardsBalance.sub(minRewardsToWithdraw).gte(currency.ZERO)
490
- ? rewardsBalance
490
+ const withdrawable = lastRewards.sub(minRewardsToWithdraw).gte(currency.ZERO)
491
+ ? lastRewards
491
492
  : currency.ZERO
492
493
 
493
494
  return {
494
- rewardsBalance,
495
+ rewardsBalance: rewardsBalance.add(lastRewards), // all time accrued rewards
495
496
  minRewardsToWithdraw,
496
- withdrawable,
497
+ withdrawable, // unclaimed rewards
497
498
  }
498
499
  }
499
500
 
@@ -6,8 +6,9 @@ import assert from 'minimalistic-assert'
6
6
  import { isContractAddressCached } from '../eth-like-util.js'
7
7
 
8
8
  export const TX_TYPE_TRANSFER = 'transfer'
9
+ export const TX_TYPE_CREATE_CONTRACT = 'create-contract'
9
10
 
10
- const VALID_TX_TYPES = new Set([TX_TYPE_TRANSFER])
11
+ const VALID_TX_TYPES = new Set([TX_TYPE_TRANSFER, TX_TYPE_CREATE_CONTRACT])
11
12
 
12
13
  export const isValidTxType = (txType) => VALID_TX_TYPES.has(txType)
13
14
 
@@ -33,14 +34,21 @@ export const assertCriticalTxAttributes = (criticalTxAttributes) => {
33
34
  const { amount, toAddress, txInput, txToAddress, txType, txValue } = criticalTxAttributes
34
35
 
35
36
  assert(amount instanceof NumberUnit, 'expected NumberUnit amount')
36
- assert(typeof toAddress === 'string', 'expected string toAddress')
37
37
  assert(
38
38
  typeof txInput === 'string' && txInput.startsWith('0x', 'expected hexadecimal string txInput')
39
39
  )
40
- assert(typeof txToAddress === 'string', 'expected string txToAddress')
41
40
  assert(isValidTxType(txType), 'expected valid txType')
42
41
  assert(txValue instanceof NumberUnit, 'expected NumberUnit txValue')
43
42
 
43
+ if (txType === TX_TYPE_CREATE_CONTRACT) {
44
+ assert(toAddress === null, 'expected null toAddress')
45
+ assert(txToAddress === null, 'expected null txToAddress')
46
+ assert(txInput !== '0x', 'expected non-empty txInput for contract creation')
47
+ } else {
48
+ assert(typeof toAddress === 'string', 'expected string toAddress')
49
+ assert(typeof txToAddress === 'string', 'expected string txToAddress')
50
+ }
51
+
44
52
  return criticalTxAttributes
45
53
  }
46
54
 
@@ -91,7 +99,8 @@ const createResolvedTxAttributes = async ({
91
99
  txToAddress,
92
100
  txValue,
93
101
  txType,
94
- isContractTxToAddress: await isContractAddressCached({ asset, address: txToAddress }),
102
+ isContractTxToAddress:
103
+ Boolean(txToAddress) && (await isContractAddressCached({ asset, address: txToAddress })),
95
104
  })
96
105
 
97
106
  export const resolveTxFromAddress = async ({
@@ -147,6 +156,22 @@ export const resolveCriticalTxAttributes = ({
147
156
 
148
157
  const amount = providedAmount ?? asset.currency.ZERO
149
158
  assert(amount instanceof NumberUnit, 'expected providedAmount')
159
+
160
+ if (txType === TX_TYPE_CREATE_CONTRACT) {
161
+ assert(asset.name === asset.baseAsset.name, 'must use baseAsset for contract deployments')
162
+ assert(!providedToAddress, 'toAddress must be falsy when creating a contract')
163
+ assert(!providedTxToAddress, 'txToAddress must be falsy when creating a contract')
164
+
165
+ return assertCriticalTxAttributes({
166
+ amount,
167
+ toAddress: null,
168
+ txInput: providedTxInput,
169
+ txToAddress: null,
170
+ txType,
171
+ txValue: amount,
172
+ })
173
+ }
174
+
150
175
  assert(txType === TX_TYPE_TRANSFER, 'expected TX_TYPE_TRANSFER')
151
176
 
152
177
  // HACK: If a `toAddress` hasn't been defined, then we