1
+ const { Program } = require ( "@coral-xyz/anchor" ) ;
2
+ const { PublicKey } = require ( "@solana/web3.js" ) ;
3
+ const {
4
+ getConnection,
5
+ decodeAccount,
6
+ TOKEN_PROGRAM_ID ,
7
+ TOKEN_2022_PROGRAM_ID ,
8
+ } = require ( "../helper/solana" ) ;
9
+ const idl = require ( "./idl/krystal_auto_vault.json" ) ;
10
+ const { addUniV3LikePosition } = require ( "../helper/unwrapLPs.js" ) ;
11
+ const { getUniqueAddresses } = require ( "../helper/tokenMapping.js" ) ;
12
+ const { get } = require ( "../helper/http.js" ) ;
13
+
14
+ const CLMM_PROGRAM_ID = new PublicKey (
15
+ "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK"
16
+ ) ;
17
+ const POSITION_SEED = Buffer . from ( "position" , "utf8" ) ;
18
+
19
+ async function tvl ( api ) {
20
+ const connection = getConnection ( ) ;
21
+
22
+ const program = new Program ( idl , { connection } ) ;
23
+ const pools = new Map ( ) ;
24
+ const pdaPersonalPositionAddressesAll = [ ]
25
+
26
+ // Load all the vaults in the program
27
+ const vaults = await program . account . userVault . all ( ) ;
28
+
29
+ const positions = [ ] ;
30
+ for ( const account of vaults ) {
31
+ const vault = account . publicKey ;
32
+ await findClmmPositionsByOwner ( connection , vault ) ;
33
+ }
34
+
35
+ const positionAccountInfos = await connection . getMultipleAccountsInfo ( pdaPersonalPositionAddressesAll ) ;
36
+
37
+ positionAccountInfos . map ( ( account ) => {
38
+ if ( ! account ) return ;
39
+
40
+ positions . push ( decodeAccount ( "raydiumPositionInfo" , account ) ) ;
41
+ } ) ;
42
+
43
+ const poolIds = getUniqueAddresses ( positions . map ( ( position ) => position . poolId . toBase58 ( ) ) , "solana" ) ;
44
+ const poolAccounts = await connection . getMultipleAccountsInfo ( poolIds . map ( i => new PublicKey ( i ) ) ) ;
45
+
46
+ for ( let i = 0 ; i < poolIds . length ; i ++ ) {
47
+ const poolId = poolIds [ i ] ;
48
+ const poolAccount = poolAccounts [ i ] ;
49
+ const poolInfo = decodeAccount ( "raydiumCLMM" , poolAccount ) ;
50
+ pools . set ( poolId , poolInfo ) ;
51
+ }
52
+
53
+ for ( const position of positions ) {
54
+ const poolId = position . poolId ;
55
+ const poolKey = poolId . toBase58 ( ) ;
56
+
57
+ let poolInfo = pools . get ( poolKey ) ;
58
+
59
+ addUniV3LikePosition ( {
60
+ api,
61
+ token0 : poolInfo . mintA . toBase58 ( ) ,
62
+ token1 : poolInfo . mintB . toBase58 ( ) ,
63
+ liquidity : position . liquidity . toNumber ( ) ,
64
+ tickLower : position . tickLower ,
65
+ tickUpper : position . tickUpper ,
66
+ tick : poolInfo . tickCurrent ,
67
+ } ) ;
68
+ }
69
+
70
+
71
+ async function findClmmPositionsByOwner ( connection , owner ) {
72
+ const [ tokenAccounts , token2022Accounts ] = await Promise . all ( [
73
+ connection . getParsedTokenAccountsByOwner ( owner , {
74
+ programId : TOKEN_PROGRAM_ID ,
75
+ } ) ,
76
+ connection . getParsedTokenAccountsByOwner ( owner , {
77
+ programId : TOKEN_2022_PROGRAM_ID ,
78
+ } ) ,
79
+ ] ) ;
80
+
81
+ const allTokenAccounts = [ ] ;
82
+ if ( tokenAccounts ?. value ) {
83
+ allTokenAccounts . push ( ...tokenAccounts . value ) ;
84
+ }
85
+ if ( token2022Accounts ?. value ) {
86
+ allTokenAccounts . push ( ...token2022Accounts . value ) ;
87
+ }
88
+
89
+ const tokenNftMints = [ ] ;
90
+ allTokenAccounts . forEach ( ( tokenAccount ) => {
91
+ const info = tokenAccount . account . data . parsed . info ;
92
+ if ( info . tokenAmount . amount == "1" && info . tokenAmount . decimals == 0 ) {
93
+ tokenNftMints . push ( new PublicKey ( info . mint ) ) ;
94
+ } else {
95
+ api . add ( info . mint , info . tokenAmount . amount )
96
+ }
97
+ } ) ;
98
+
99
+ const pdaPersonalPositionAddresses = tokenNftMints . map ( getPdaPersonalPositionAddress )
100
+ pdaPersonalPositionAddressesAll . push ( ...pdaPersonalPositionAddresses )
101
+ }
102
+ }
103
+
104
+
105
+ function getPdaPersonalPositionAddress ( nftMint ) {
106
+ const [ pda ] = PublicKey . findProgramAddressSync (
107
+ [ POSITION_SEED , nftMint . toBuffer ( ) ] ,
108
+ CLMM_PROGRAM_ID
109
+ ) ;
110
+
111
+ return pda ;
112
+ }
113
+
114
+ async function tvlApi ( api ) {
115
+ const res = await get ( 'https://api.krystal.app/solana/v1/lp/tvl' )
116
+ api . addUSDValue ( + res . tvl )
117
+ }
118
+
119
+ module . exports = { tvl : tvlApi } ;
0 commit comments