@exodus/solana-api 3.20.4 → 3.20.6
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 +20 -0
- package/package.json +2 -2
- package/src/api.js +48 -3
- package/src/tx-log/solana-monitor.js +10 -4
- package/src/txs-utils.js +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
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.20.6](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.20.5...@exodus/solana-api@3.20.6) (2025-07-18)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: SOL parse mint transaction (#6045)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [3.20.5](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.20.4...@exodus/solana-api@3.20.5) (2025-07-11)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
* fix: catch SOL rewards endpoint error (#6055)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
## [3.20.4](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.20.3...@exodus/solana-api@3.20.4) (2025-07-01)
|
|
7
27
|
|
|
8
28
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "3.20.
|
|
3
|
+
"version": "3.20.6",
|
|
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",
|
|
@@ -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": "a7ce3c50e11f41e17cdf980d9ec0756c756beb93",
|
|
50
50
|
"bugs": {
|
|
51
51
|
"url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Asolana-api"
|
|
52
52
|
},
|
package/src/api.js
CHANGED
|
@@ -22,7 +22,11 @@ import urljoin from 'url-join'
|
|
|
22
22
|
|
|
23
23
|
import { Connection } from './connection.js'
|
|
24
24
|
import { getStakeActivation } from './get-stake-activation/index.js'
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
isSolTransferInstruction,
|
|
27
|
+
isSplMintInstruction,
|
|
28
|
+
isSplTransferInstruction,
|
|
29
|
+
} from './txs-utils.js'
|
|
26
30
|
|
|
27
31
|
const createApi = createApiCJS.default || createApiCJS
|
|
28
32
|
|
|
@@ -473,12 +477,15 @@ export class Api {
|
|
|
473
477
|
(ix) =>
|
|
474
478
|
ix.parsed &&
|
|
475
479
|
(isSplTransferInstruction({ program: ix.program, type: ix.parsed.type }) ||
|
|
480
|
+
isSplMintInstruction({ program: ix.program, type: ix.parsed.type }) ||
|
|
476
481
|
(!includeUnparsed &&
|
|
477
482
|
isSolTransferInstruction({ program: ix.program, type: ix.parsed.type })))
|
|
478
483
|
)
|
|
479
484
|
.map((ix) => {
|
|
480
|
-
|
|
481
|
-
const destination =
|
|
485
|
+
let source = lodash.get(ix, 'parsed.info.source')
|
|
486
|
+
const destination = isSplMintInstruction({ program: ix.program, type: ix.parsed.type })
|
|
487
|
+
? lodash.get(ix, 'parsed.info.account') // only for minting
|
|
488
|
+
: lodash.get(ix, 'parsed.info.destination')
|
|
482
489
|
const amount = Number(
|
|
483
490
|
lodash.get(ix, 'parsed.info.amount', 0) ||
|
|
484
491
|
lodash.get(ix, 'parsed.info.tokenAmount.amount', 0)
|
|
@@ -545,6 +552,10 @@ export class Api {
|
|
|
545
552
|
})
|
|
546
553
|
if (!tokenAccount) return
|
|
547
554
|
|
|
555
|
+
if (isSplMintInstruction({ program: ix.program, type: ix.parsed.type })) {
|
|
556
|
+
source = lodash.get(ix, 'parsed.info.mintAuthority')
|
|
557
|
+
}
|
|
558
|
+
|
|
548
559
|
const isSending = tokenAccountsByOwner.some(({ tokenAccountAddress }) => {
|
|
549
560
|
return [source].includes(tokenAccountAddress)
|
|
550
561
|
})
|
|
@@ -552,6 +563,8 @@ export class Api {
|
|
|
552
563
|
// owner if it's a send tx
|
|
553
564
|
return {
|
|
554
565
|
id: txId,
|
|
566
|
+
program: ix.program,
|
|
567
|
+
type: ix.parsed.type,
|
|
555
568
|
slot: txDetails.slot,
|
|
556
569
|
owner: isSending ? ownerAddress : null,
|
|
557
570
|
from: isSending ? ownerAddress : source,
|
|
@@ -679,6 +692,7 @@ export class Api {
|
|
|
679
692
|
// Parse Token txs
|
|
680
693
|
const tokenTxs = this._parseTokenTransfers({
|
|
681
694
|
instructions,
|
|
695
|
+
innerInstructions,
|
|
682
696
|
tokenAccountsByOwner,
|
|
683
697
|
ownerAddress,
|
|
684
698
|
fee,
|
|
@@ -769,6 +783,7 @@ export class Api {
|
|
|
769
783
|
|
|
770
784
|
_parseTokenTransfers({
|
|
771
785
|
instructions,
|
|
786
|
+
innerInstructions = [],
|
|
772
787
|
tokenAccountsByOwner,
|
|
773
788
|
ownerAddress,
|
|
774
789
|
fee,
|
|
@@ -829,6 +844,36 @@ export class Api {
|
|
|
829
844
|
}
|
|
830
845
|
})
|
|
831
846
|
|
|
847
|
+
innerInstructions.forEach((parsedIx) => {
|
|
848
|
+
const { type, program, amount, from, to } = parsedIx
|
|
849
|
+
|
|
850
|
+
// Handle token minting (mintTo, mintToChecked)
|
|
851
|
+
if (isSplMintInstruction({ program, type })) {
|
|
852
|
+
const {
|
|
853
|
+
token: { tokenAccountAddress },
|
|
854
|
+
} = parsedIx
|
|
855
|
+
|
|
856
|
+
// Check if the destination token account belongs to our owner
|
|
857
|
+
const tokenAccount = lodash.find(tokenAccountsByOwner, {
|
|
858
|
+
tokenAccountAddress,
|
|
859
|
+
})
|
|
860
|
+
|
|
861
|
+
if (!tokenAccount) return // not our token account
|
|
862
|
+
|
|
863
|
+
delete tokenAccount.balance
|
|
864
|
+
delete tokenAccount.owner
|
|
865
|
+
|
|
866
|
+
tokenTxs.push({
|
|
867
|
+
owner: null, // no owner for minting (it's created from thin air)
|
|
868
|
+
token: tokenAccount,
|
|
869
|
+
from, // mint address as the source
|
|
870
|
+
to, // our address as recipient
|
|
871
|
+
amount: Number(amount || 0),
|
|
872
|
+
fee: 0, // no fee for receiving minted tokens
|
|
873
|
+
})
|
|
874
|
+
}
|
|
875
|
+
})
|
|
876
|
+
|
|
832
877
|
return tokenTxs
|
|
833
878
|
}
|
|
834
879
|
|
|
@@ -325,7 +325,7 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
325
325
|
|
|
326
326
|
const staking =
|
|
327
327
|
this.isStakingEnabled() && fetchStakingInfo
|
|
328
|
-
? await this.getStakingInfo({ address, walletAccount })
|
|
328
|
+
? await this.getStakingInfo({ address, accountState, walletAccount })
|
|
329
329
|
: { ...accountState.stakingInfo, staking: this.staking }
|
|
330
330
|
|
|
331
331
|
const stakedBalance = this.asset.currency.baseUnit(staking.locked)
|
|
@@ -366,9 +366,15 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
366
366
|
return this.updateAccountState({ newData, walletAccount })
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
-
async getStakingInfo({ address, walletAccount }) {
|
|
369
|
+
async getStakingInfo({ address, accountState, walletAccount }) {
|
|
370
370
|
const stakingInfo = await this.api.getStakeAccountsInfo(address)
|
|
371
|
-
|
|
371
|
+
let earned = accountState.stakingInfo.earned.toBaseString()
|
|
372
|
+
try {
|
|
373
|
+
const rewards = await this.api.getRewards(address)
|
|
374
|
+
earned = rewards
|
|
375
|
+
} catch (error) {
|
|
376
|
+
console.warn(error)
|
|
377
|
+
}
|
|
372
378
|
|
|
373
379
|
return {
|
|
374
380
|
loaded: true,
|
|
@@ -380,7 +386,7 @@ export class SolanaMonitor extends BaseMonitor {
|
|
|
380
386
|
activating: this.asset.currency.baseUnit(stakingInfo.activating),
|
|
381
387
|
withdrawable: this.asset.currency.baseUnit(stakingInfo.withdrawable),
|
|
382
388
|
pending: this.asset.currency.baseUnit(stakingInfo.pending), // still undelegating (not yet available for withdraw)
|
|
383
|
-
earned: this.asset.currency.baseUnit(
|
|
389
|
+
earned: this.asset.currency.baseUnit(earned),
|
|
384
390
|
accounts: stakingInfo.accounts, // Obj
|
|
385
391
|
}
|
|
386
392
|
}
|
package/src/txs-utils.js
CHANGED
|
@@ -4,6 +4,8 @@ const TRANSFER_INSTRUCTION_TYPES = new Set([
|
|
|
4
4
|
'transferCheckedWithFee',
|
|
5
5
|
])
|
|
6
6
|
|
|
7
|
+
const MINT_INSTRUCTION_TYPES = new Set(['mintTo', 'mintToChecked'])
|
|
8
|
+
|
|
7
9
|
const isSolanaTx = (tx) => tx.coinName === 'solana'
|
|
8
10
|
export const isSolanaStaking = (tx) =>
|
|
9
11
|
isSolanaTx(tx) && ['createAccountWithSeed', 'delegate'].includes(tx?.data?.staking?.method)
|
|
@@ -18,3 +20,6 @@ export const isSplTransferInstruction = ({ program, type }) =>
|
|
|
18
20
|
|
|
19
21
|
export const isSolTransferInstruction = ({ program, type }) =>
|
|
20
22
|
program === 'system' && TRANSFER_INSTRUCTION_TYPES.has(type)
|
|
23
|
+
|
|
24
|
+
export const isSplMintInstruction = ({ program, type }) =>
|
|
25
|
+
program === 'spl-token' && MINT_INSTRUCTION_TYPES.has(type)
|