@exodus/solana-api 3.30.8 → 3.30.9
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 +10 -0
- package/package.json +4 -4
- package/src/create-unsigned-tx-for-send.js +32 -5
- package/src/fee-payer.js +3 -3
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
|
+
## [3.30.9](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.30.8...@exodus/solana-api@3.30.9) (2026-04-04)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: sponsored Solana token sends when CU simulation fails (#7707)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
6
16
|
## [3.30.8](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.30.7...@exodus/solana-api@3.30.8) (2026-04-02)
|
|
7
17
|
|
|
8
18
|
**Note:** Version bump only for package @exodus/solana-api
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "3.30.
|
|
3
|
+
"version": "3.30.9",
|
|
4
4
|
"description": "Transaction monitors, fee monitors, RPC with the blockchain node, and other networking code for Solana",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"@exodus/fetch": "^1.7.3",
|
|
34
34
|
"@exodus/models": "^13.0.0",
|
|
35
35
|
"@exodus/simple-retry": "^0.0.6",
|
|
36
|
-
"@exodus/solana-lib": "^3.22.
|
|
37
|
-
"@exodus/solana-meta": "^2.0
|
|
36
|
+
"@exodus/solana-lib": "^3.22.5",
|
|
37
|
+
"@exodus/solana-meta": "^2.9.0",
|
|
38
38
|
"@exodus/timer": "^1.1.1",
|
|
39
39
|
"debug": "^4.1.1",
|
|
40
40
|
"delay": "^4.0.1",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@exodus/assets-testing": "^1.0.0",
|
|
50
50
|
"@exodus/solana-web3.js": "^1.63.1-exodus.9-rc3"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "a2cd3fbc02d07f1c3dc127be4d7896292d2dc967",
|
|
53
53
|
"bugs": {
|
|
54
54
|
"url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Asolana-api"
|
|
55
55
|
},
|
|
@@ -10,7 +10,9 @@ import assert from 'minimalistic-assert'
|
|
|
10
10
|
|
|
11
11
|
import { maybeAddFeePayerWithAuth } from './fee-payer.js'
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const COMPUTE_BUDGET_INSTRUCTIONS_CU = 300
|
|
14
|
+
const SOL_TRANSFER_CU = 150 + COMPUTE_BUDGET_INSTRUCTIONS_CU
|
|
15
|
+
const DEFAULT_COMPUTE_UNIT_LIMIT = 200_000
|
|
14
16
|
const TOKEN_ACCOUNT_CREATION_SIZE = 165 // size of the token account
|
|
15
17
|
|
|
16
18
|
export const createTxFactory = ({ assetClientInterface, api, feePayerClient }) => {
|
|
@@ -65,6 +67,7 @@ export const createTxFactory = ({ assetClientInterface, api, feePayerClient }) =
|
|
|
65
67
|
|
|
66
68
|
const feeData =
|
|
67
69
|
providedFeeData ?? (await assetClientInterface.getFeeConfig({ assetName: baseAssetName }))
|
|
70
|
+
const shouldTryFeePayer = feeData.enableFeePayer && useFeePayer
|
|
68
71
|
|
|
69
72
|
const fromAddress =
|
|
70
73
|
providedFromAddress ??
|
|
@@ -211,18 +214,22 @@ export const createTxFactory = ({ assetClientInterface, api, feePayerClient }) =
|
|
|
211
214
|
reference,
|
|
212
215
|
memo,
|
|
213
216
|
// Effective: platform enable AND per-tx intent
|
|
214
|
-
useFeePayer,
|
|
217
|
+
useFeePayer: shouldTryFeePayer,
|
|
215
218
|
...tokenParams,
|
|
216
219
|
...stakingParams,
|
|
217
220
|
...magicEdenParams,
|
|
218
221
|
})
|
|
219
222
|
|
|
220
223
|
unsignedTx.txMeta.stakingParams = stakingParams
|
|
224
|
+
const isFeeSponsoredTokenTransfer = isToken && unsignedTx.txMeta.useFeePayer && !nft && !method
|
|
225
|
+
const shouldUseSafeComputeUnitLimit =
|
|
226
|
+
isFeeSponsoredTokenTransfer &&
|
|
227
|
+
(!unsignedTx.txData.isAssociatedTokenAccountActive || isExchange)
|
|
221
228
|
|
|
222
229
|
const resolveUnitConsumed = async () => {
|
|
223
230
|
// this avoids unnecessary simulations. Also the simulation fails with InsufficientFundsForRent when sending all.
|
|
224
231
|
if (asset.name === asset.baseAsset.name && amount && !nft && !method) {
|
|
225
|
-
return
|
|
232
|
+
return SOL_TRANSFER_CU
|
|
226
233
|
}
|
|
227
234
|
|
|
228
235
|
// Simulate with unsigned transaction. The fee payer service is deterministic -
|
|
@@ -237,10 +244,31 @@ export const createTxFactory = ({ assetClientInterface, api, feePayerClient }) =
|
|
|
237
244
|
// we use this method to compute unitsConsumed
|
|
238
245
|
// we can throw error here and fallback to ~0.025 SOL or estimate fee based on the method
|
|
239
246
|
console.log('error getting units consumed:', err)
|
|
247
|
+
const serializedError = typeof err === 'string' ? err : JSON.stringify(err)
|
|
248
|
+
const isRentOrBalanceError = /insufficientfunds|rent/i.test(serializedError)
|
|
249
|
+
const isAccountNotFoundError = /accountnotfound/i.test(serializedError)
|
|
250
|
+
|
|
251
|
+
// Fee sponsorship is injected after this simulation step. Overestimate CU to
|
|
252
|
+
// avoid on-chain failures; the fee payer absorbs the cost.
|
|
253
|
+
if (!unitsConsumed && isFeeSponsoredTokenTransfer && isRentOrBalanceError) {
|
|
254
|
+
return DEFAULT_COMPUTE_UNIT_LIMIT
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!unitsConsumed && isFeeSponsoredTokenTransfer && isAccountNotFoundError) {
|
|
258
|
+
const senderBaseBalanceLamports = BigInt(await api.getBalance(fromAddress))
|
|
259
|
+
if (senderBaseBalanceLamports === BigInt(0)) return DEFAULT_COMPUTE_UNIT_LIMIT
|
|
260
|
+
}
|
|
261
|
+
|
|
240
262
|
if (!unitsConsumed) throw new Error(err)
|
|
241
263
|
}
|
|
242
264
|
|
|
243
|
-
|
|
265
|
+
const estimatedComputeUnitLimit = unitsConsumed + COMPUTE_BUDGET_INSTRUCTIONS_CU
|
|
266
|
+
|
|
267
|
+
if (shouldUseSafeComputeUnitLimit && estimatedComputeUnitLimit < DEFAULT_COMPUTE_UNIT_LIMIT) {
|
|
268
|
+
return DEFAULT_COMPUTE_UNIT_LIMIT
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return estimatedComputeUnitLimit
|
|
244
272
|
}
|
|
245
273
|
|
|
246
274
|
const priorityFee = feeData.priorityFee
|
|
@@ -272,7 +300,6 @@ export const createTxFactory = ({ assetClientInterface, api, feePayerClient }) =
|
|
|
272
300
|
const tx = await maybeAddFeePayerWithAuth({
|
|
273
301
|
unsignedTx,
|
|
274
302
|
feePayerClient,
|
|
275
|
-
enableFeePayer: feeData.enableFeePayer,
|
|
276
303
|
})
|
|
277
304
|
|
|
278
305
|
const fee = tx.txMeta.usedFeePayer ? asset.feeAsset.currency.ZERO : calculatedFee
|
package/src/fee-payer.js
CHANGED
|
@@ -145,11 +145,11 @@ export const feePayerClientFactory = ({
|
|
|
145
145
|
* @param {Object} params.unsignedTx - The unsigned transaction
|
|
146
146
|
* @param {Object} params.feePayerClient - The fee payer client instance
|
|
147
147
|
*/
|
|
148
|
-
export const maybeAddFeePayerWithAuth = async ({ unsignedTx, feePayerClient
|
|
148
|
+
export const maybeAddFeePayerWithAuth = async ({ unsignedTx, feePayerClient }) => {
|
|
149
149
|
let unsignedTxWithFeePayer = unsignedTx
|
|
150
150
|
|
|
151
|
-
//
|
|
152
|
-
if (!feePayerClient || !
|
|
151
|
+
// `txMeta.useFeePayer` already combines platform-level and per-tx intent.
|
|
152
|
+
if (!feePayerClient || !unsignedTx.txMeta.useFeePayer) {
|
|
153
153
|
unsignedTxWithFeePayer.txMeta.usedFeePayer = false
|
|
154
154
|
return unsignedTxWithFeePayer
|
|
155
155
|
}
|