1+ // Zealous Swap (Kasplex) — Pools adapter for DefiLlama yield-server
2+ // Fetches pool data from our API and reserves on-chain, calculating TVL using DefiLlama's price feeds.
3+ //
4+ // Endpoint used: https://kasplex.zealousswap.com/v1/pools
5+ // Notes:
6+ // - Reserves are fetched on-chain via getReserves(), with API fallback if call fails
7+ // - TVL is calculated from token reserves using DefiLlama's price API
8+ // - Falls back to API's TVL value if DefiLlama prices are unavailable
9+ // - We use `apr` from our API as `apyBase` (already annualized %)
10+ // - If `apr` is missing, we fall back to fee APR from volume * feeRate
11+ // - We include `apyReward` only if our API reports a positive `farmApr`
12+
13+ const axios = require ( "axios" ) ;
14+ const sdk = require ( "@defillama/sdk" ) ;
15+ const BigNumber = require ( "bignumber.js" ) ;
16+
17+ const CHAIN = "kasplex" ;
18+ const API = "https://kasplex.zealousswap.com/v1/pools" ;
19+
20+ function toNumber ( x ) {
21+ if ( x === null || x === undefined ) return 0 ;
22+ const n = Number ( x ) ;
23+ return Number . isFinite ( n ) ? n : 0 ;
24+ }
25+
26+ function poolSymbol ( p ) {
27+ const s0 = p . token0 ?. symbol || "T0" ;
28+ const s1 = p . token1 ?. symbol || "T1" ;
29+ return `${ s0 } -${ s1 } ` ;
30+ }
31+
32+ function calcFeeAPR ( volumeUSD , tvlUsd , feeRate ) {
33+ const vol = toNumber ( volumeUSD ) ;
34+ const tvl = toNumber ( tvlUsd ) ;
35+ const fee = toNumber ( feeRate ) ;
36+ if ( tvl <= 0 || vol <= 0 || fee <= 0 ) return 0 ;
37+ return ( vol * fee / tvl ) * 365 * 100 ;
38+ }
39+
40+ const getPrices = async ( addresses , chain ) => {
41+ const prices = (
42+ await axios . get (
43+ `https://coins.llama.fi/prices/current/${ addresses
44+ . map ( ( address ) => `${ chain } :${ address } ` )
45+ . join ( ',' )
46+ . toLowerCase ( ) } `
47+ )
48+ ) . data . coins ;
49+
50+ const pricesObj = Object . entries ( prices ) . reduce (
51+ ( acc , [ address , price ] ) => ( {
52+ ...acc ,
53+ [ address . split ( ':' ) [ 1 ] . toLowerCase ( ) ] : price . price ,
54+ } ) ,
55+ { }
56+ ) ;
57+
58+ return pricesObj ;
59+ } ;
60+
61+ const calculateReservesUSD = (
62+ reserve0 ,
63+ reserve1 ,
64+ token0Address ,
65+ token1Address ,
66+ decimals0 ,
67+ decimals1 ,
68+ tokenPrices
69+ ) => {
70+ const token0Price = tokenPrices [ token0Address . toLowerCase ( ) ] ;
71+ const token1Price = tokenPrices [ token1Address . toLowerCase ( ) ] ;
72+
73+ const reserve0Adjusted = new BigNumber ( reserve0 ) . div ( 10 ** decimals0 ) ;
74+ const reserve1Adjusted = new BigNumber ( reserve1 ) . div ( 10 ** decimals1 ) ;
75+
76+ if ( token0Price ) return reserve0Adjusted . times ( token0Price ) . times ( 2 ) ;
77+ if ( token1Price ) return reserve1Adjusted . times ( token1Price ) . times ( 2 ) ;
78+
79+ return null ;
80+ } ;
81+
82+ async function apy ( ) {
83+ const { data } = await axios . get ( API ) ;
84+ const poolsObj = data ?. pools || { } ;
85+
86+ const poolAddresses = Object . keys ( poolsObj ) ;
87+ if ( poolAddresses . length === 0 ) return [ ] ;
88+
89+ const reservesResults = await sdk . api . abi . multiCall ( {
90+ abi : {
91+ inputs : [ ] ,
92+ name : "getReserves" ,
93+ outputs : [
94+ { internalType : "uint112" , name : "_reserve0" , type : "uint112" } ,
95+ { internalType : "uint112" , name : "_reserve1" , type : "uint112" } ,
96+ { internalType : "uint32" , name : "_blockTimestampLast" , type : "uint32" }
97+ ] ,
98+ stateMutability : "view" ,
99+ type : "function"
100+ } ,
101+ calls : poolAddresses . map ( ( address ) => ( {
102+ target : address ,
103+ } ) ) ,
104+ chain : CHAIN ,
105+ permitFailure : true ,
106+ } ) ;
107+
108+ const tokenAddresses = new Set ( ) ;
109+ for ( const p of Object . values ( poolsObj ) ) {
110+ if ( p . token0 ?. address ) tokenAddresses . add ( p . token0 . address . toLowerCase ( ) ) ;
111+ if ( p . token1 ?. address ) tokenAddresses . add ( p . token1 . address . toLowerCase ( ) ) ;
112+ }
113+
114+ const tokenPrices = await getPrices ( Array . from ( tokenAddresses ) , CHAIN ) ;
115+
116+ const results = [ ] ;
117+
118+ for ( let i = 0 ; i < poolAddresses . length ; i ++ ) {
119+ const address = poolAddresses [ i ] ;
120+ const p = poolsObj [ address ] ;
121+
122+ if ( ! p . token0 ?. address || ! p . token1 ?. address ) continue ;
123+
124+ const reserveData = reservesResults . output [ i ] ;
125+ let reserve0 , reserve1 ;
126+
127+ if ( reserveData && reserveData . success && reserveData . output ) {
128+ reserve0 = reserveData . output . _reserve0 || reserveData . output [ 0 ] ;
129+ reserve1 = reserveData . output . _reserve1 || reserveData . output [ 1 ] ;
130+ } else {
131+ reserve0 = p . token0Reserves ;
132+ reserve1 = p . token1Reserves ;
133+ }
134+
135+ if ( ! reserve0 || ! reserve1 ) continue ;
136+
137+ const tvlFromReserves = calculateReservesUSD (
138+ reserve0 ,
139+ reserve1 ,
140+ p . token0 . address ,
141+ p . token1 . address ,
142+ p . token0 . decimals ,
143+ p . token1 . decimals ,
144+ tokenPrices
145+ ) ;
146+
147+ const tvlUsd = tvlFromReserves
148+ ? Number ( tvlFromReserves . toString ( ) )
149+ : toNumber ( p . tvl ) ;
150+
151+ if ( ! ( tvlUsd > 0 ) ) continue ;
152+
153+ let apyBase = toNumber ( p . apr ) ;
154+
155+ if ( ! ( apyBase > 0 ) ) {
156+ const feeRate = p . regularFeeRate ?? p . discountedFeeRate ?? 0.003 ;
157+ apyBase = calcFeeAPR ( p . volumeUSD , tvlUsd , feeRate ) ;
158+ }
159+
160+ const apyReward = toNumber ( p . farmApr ) > 0 ? toNumber ( p . farmApr ) : null ;
161+
162+ results . push ( {
163+ pool : `${ address } -${ CHAIN } ` ,
164+ chain : CHAIN ,
165+ project : "zealousswap" ,
166+ symbol : poolSymbol ( p ) ,
167+ tvlUsd,
168+ apyBase,
169+ apyReward,
170+ rewardTokens : p . hasActiveFarm
171+ ? [ "0xb7a95035618354D9ADFC49Eca49F38586B624040" ]
172+ : [ ] ,
173+ underlyingTokens : [ p . token0 . address , p . token1 . address ] ,
174+ url : "https://app.zealousswap.com/liquidity" ,
175+ volumeUsd1d : toNumber ( p . volumeUSD ) ,
176+ } ) ;
177+ }
178+
179+ return results . filter ( x => Number . isFinite ( x . tvlUsd ) && x . tvlUsd > 0 ) ;
180+ }
181+
182+ module . exports = {
183+ timetravel : false ,
184+ apy,
185+ url : API ,
186+ } ;
0 commit comments