@exodus/solana-api 3.14.7 → 3.15.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 +10 -0
- package/package.json +3 -3
- package/src/create-unsigned-tx-for-send.js +74 -1
- package/src/get-fees.js +1 -0
- package/src/tx-send.js +26 -10
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.15.0](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.14.7...@exodus/solana-api@3.15.0) (2025-04-03)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* feat(solana): add optional addExternalFeePayerToTransaction (#5345)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
6
16
|
## [3.14.7](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.14.6...@exodus/solana-api@3.14.7) (2025-04-03)
|
|
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.
|
|
3
|
+
"version": "3.15.0",
|
|
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",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@exodus/fetch": "^1.7.3",
|
|
31
31
|
"@exodus/models": "^12.0.1",
|
|
32
32
|
"@exodus/simple-retry": "^0.0.6",
|
|
33
|
-
"@exodus/solana-lib": "^3.
|
|
33
|
+
"@exodus/solana-lib": "^3.10.0",
|
|
34
34
|
"@exodus/solana-meta": "^2.0.2",
|
|
35
35
|
"@exodus/timer": "^1.1.1",
|
|
36
36
|
"bn.js": "^4.11.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@exodus/assets-testing": "^1.0.0",
|
|
47
47
|
"@exodus/solana-web3.js": "^1.63.1-exodus.9-rc3"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "59c4d4a4a7404eb915e4fa722a2afe01d1556046",
|
|
50
50
|
"bugs": {
|
|
51
51
|
"url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Asolana-api"
|
|
52
52
|
},
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createUnsignedTx,
|
|
3
|
+
deserializeTransaction,
|
|
3
4
|
findAssociatedTokenAddress,
|
|
5
|
+
parseTxBuffer,
|
|
4
6
|
prepareForSigning,
|
|
5
7
|
TOKEN_2022_PROGRAM_ID,
|
|
6
8
|
TOKEN_PROGRAM_ID,
|
|
9
|
+
verifyOnlyFeePayerChanged,
|
|
7
10
|
} from '@exodus/solana-lib'
|
|
8
11
|
|
|
9
12
|
const CU_FOR_COMPUTE_BUDGET_INSTRUCTIONS = 300
|
|
@@ -18,6 +21,8 @@ export const createUnsignedTxForSend = async ({
|
|
|
18
21
|
reference,
|
|
19
22
|
memo,
|
|
20
23
|
nft,
|
|
24
|
+
feePayerApiUrl,
|
|
25
|
+
useFeePayer = true,
|
|
21
26
|
// token related
|
|
22
27
|
tokenStandard,
|
|
23
28
|
customMintAddress,
|
|
@@ -142,6 +147,7 @@ export const createUnsignedTxForSend = async ({
|
|
|
142
147
|
recentBlockhash,
|
|
143
148
|
reference,
|
|
144
149
|
memo,
|
|
150
|
+
useFeePayer,
|
|
145
151
|
...tokenParams,
|
|
146
152
|
...stakingParams,
|
|
147
153
|
...magicEdenParams,
|
|
@@ -205,5 +211,72 @@ export const createUnsignedTxForSend = async ({
|
|
|
205
211
|
throw err
|
|
206
212
|
}
|
|
207
213
|
|
|
208
|
-
return
|
|
214
|
+
return maybeAddFeePayer({
|
|
215
|
+
unsignedTx,
|
|
216
|
+
feePayerApiUrl,
|
|
217
|
+
assetName: asset.name,
|
|
218
|
+
useFeePayer,
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export const extractTxLogData = async ({ unsignedTx, api }) => {
|
|
223
|
+
if (!unsignedTx.txData.transactionBuffer)
|
|
224
|
+
return {
|
|
225
|
+
method: unsignedTx.txData.method,
|
|
226
|
+
from: unsignedTx.txData.from,
|
|
227
|
+
to: unsignedTx.txData.to,
|
|
228
|
+
amount: unsignedTx.txData.amount,
|
|
229
|
+
stakingParams: unsignedTx.txMeta.stakingParams,
|
|
230
|
+
usedFeePayer: unsignedTx.txMeta.usedFeePayer,
|
|
231
|
+
fee: unsignedTx.txMeta.fee,
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const txData = await parseTxBuffer(unsignedTx.txData.transactionBuffer, api)
|
|
235
|
+
return {
|
|
236
|
+
...txData,
|
|
237
|
+
stakingParams: unsignedTx.txMeta.stakingParams,
|
|
238
|
+
usedFeePayer: unsignedTx.txMeta.usedFeePayer,
|
|
239
|
+
fee: unsignedTx.txMeta.fee,
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export const maybeAddFeePayer = async ({ unsignedTx, feePayerApiUrl, assetName }) => {
|
|
244
|
+
let unsignedTxWithFeePayer = unsignedTx
|
|
245
|
+
let newFeePayer = false
|
|
246
|
+
if (feePayerApiUrl && unsignedTx.txMeta.useFeePayer !== false) {
|
|
247
|
+
try {
|
|
248
|
+
const unsignedTxVersionedTransaction = prepareForSigning(unsignedTx)
|
|
249
|
+
|
|
250
|
+
const newTransactionResponse = await fetch(new URL(feePayerApiUrl).toString(), {
|
|
251
|
+
method: 'POST',
|
|
252
|
+
headers: {
|
|
253
|
+
'Content-Type': 'application/json',
|
|
254
|
+
},
|
|
255
|
+
body: JSON.stringify({
|
|
256
|
+
assetName,
|
|
257
|
+
transaction: Buffer.from(unsignedTxVersionedTransaction.serialize()).toString('base64'),
|
|
258
|
+
}),
|
|
259
|
+
})
|
|
260
|
+
const { transaction: newTransactionString } = await newTransactionResponse.json()
|
|
261
|
+
|
|
262
|
+
const newTransactionBuffer = Buffer.from(newTransactionString, 'base64')
|
|
263
|
+
const newTransaction = deserializeTransaction(newTransactionBuffer)
|
|
264
|
+
|
|
265
|
+
verifyOnlyFeePayerChanged(unsignedTxVersionedTransaction, newTransaction)
|
|
266
|
+
|
|
267
|
+
unsignedTxWithFeePayer = {
|
|
268
|
+
txData: {
|
|
269
|
+
transactionBuffer: newTransactionBuffer,
|
|
270
|
+
},
|
|
271
|
+
txMeta: unsignedTx.txMeta,
|
|
272
|
+
}
|
|
273
|
+
newFeePayer = true
|
|
274
|
+
} catch (err) {
|
|
275
|
+
console.log('error adding a new fee payer, sending original transaction', err)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
unsignedTxWithFeePayer.txMeta.usedFeePayer = newFeePayer
|
|
280
|
+
|
|
281
|
+
return unsignedTxWithFeePayer
|
|
209
282
|
}
|
package/src/get-fees.js
CHANGED
package/src/tx-send.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import assert from 'minimalistic-assert'
|
|
2
2
|
|
|
3
|
-
import { createUnsignedTxForSend } from './create-unsigned-tx-for-send.js'
|
|
3
|
+
import { createUnsignedTxForSend, extractTxLogData } from './create-unsigned-tx-for-send.js'
|
|
4
4
|
|
|
5
5
|
export const createAndBroadcastTXFactory =
|
|
6
|
-
({ api, assetClientInterface }) =>
|
|
6
|
+
({ api, assetClientInterface, feePayerApiUrl }) =>
|
|
7
7
|
async ({ asset, walletAccount, unsignedTx: predefinedUnsignedTx, ...legacyParams }) => {
|
|
8
8
|
const assetName = asset.name
|
|
9
9
|
assert(assetClientInterface, `assetClientInterface must be supplied in sendTx for ${assetName}`)
|
|
@@ -15,6 +15,7 @@ export const createAndBroadcastTXFactory =
|
|
|
15
15
|
return predefinedUnsignedTx
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
// handle legacy mode
|
|
18
19
|
const feeData = await assetClientInterface.getFeeData({ assetName })
|
|
19
20
|
const fromAddress = await assetClientInterface.getReceiveAddress({
|
|
20
21
|
assetName: baseAsset.name,
|
|
@@ -26,6 +27,7 @@ export const createAndBroadcastTXFactory =
|
|
|
26
27
|
asset,
|
|
27
28
|
feeData,
|
|
28
29
|
fromAddress,
|
|
30
|
+
feePayerApiUrl,
|
|
29
31
|
amount: legacyParams.amount,
|
|
30
32
|
toAddress: legacyParams.address,
|
|
31
33
|
...legacyParams.options,
|
|
@@ -48,12 +50,16 @@ export const createAndBroadcastTXFactory =
|
|
|
48
50
|
|
|
49
51
|
try {
|
|
50
52
|
// collecting data from unsignedTx, it should be sufficient
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
const
|
|
53
|
+
const txLogData = await extractTxLogData({ unsignedTx, api })
|
|
54
|
+
|
|
55
|
+
const method = txLogData.method
|
|
56
|
+
const fromAddress = txLogData.from
|
|
57
|
+
const toAddress = txLogData.to
|
|
54
58
|
const selfSend = fromAddress === toAddress
|
|
55
|
-
const amount = asset.currency.baseUnit(
|
|
56
|
-
const feeAmount =
|
|
59
|
+
const amount = asset.currency.baseUnit(txLogData.amount)
|
|
60
|
+
const feeAmount = txLogData.usedFeePayer
|
|
61
|
+
? asset.feeAsset.currency.ZERO
|
|
62
|
+
: asset.feeAsset.currency.baseUnit(txLogData.fee)
|
|
57
63
|
|
|
58
64
|
const isStakingTx = ['delegate', 'undelegate', 'withdraw'].includes(method)
|
|
59
65
|
const coinAmount =
|
|
@@ -62,7 +68,10 @@ export const createAndBroadcastTXFactory =
|
|
|
62
68
|
|
|
63
69
|
let data
|
|
64
70
|
if (isStakingTx) {
|
|
65
|
-
data = {
|
|
71
|
+
data = {
|
|
72
|
+
...txLogData.stakingParams,
|
|
73
|
+
stake: coinAmount.toBaseNumber(),
|
|
74
|
+
}
|
|
66
75
|
} else {
|
|
67
76
|
data = Object.create(null)
|
|
68
77
|
}
|
|
@@ -77,9 +86,16 @@ export const createAndBroadcastTXFactory =
|
|
|
77
86
|
selfSend,
|
|
78
87
|
to: toAddress,
|
|
79
88
|
data,
|
|
80
|
-
currencies: {
|
|
89
|
+
currencies: {
|
|
90
|
+
[assetName]: asset.currency,
|
|
91
|
+
[asset.feeAsset.name]: asset.feeAsset.currency,
|
|
92
|
+
},
|
|
81
93
|
}
|
|
82
|
-
await assetClientInterface.updateTxLogAndNotify({
|
|
94
|
+
await assetClientInterface.updateTxLogAndNotify({
|
|
95
|
+
assetName,
|
|
96
|
+
walletAccount,
|
|
97
|
+
txs: [tx],
|
|
98
|
+
})
|
|
83
99
|
|
|
84
100
|
if (isToken) {
|
|
85
101
|
// write tx entry in solana for token fee
|