1+ const { TonClient } = require ( '@ton/ton' ) ;
2+ const { Address, Cell, Slice, Dictionary, beginCell } = require ( '@ton/core' ) ;
3+ const utils = require ( '../utils' ) ;
4+ const PROTOCOL_FEE_BITS = 16 ;
5+ const PROTOCOL_FEE_BASE = 1000 ;
6+
7+ function parseAssetConfig ( assetConfigCell ) {
8+ const assetConfigSlice = assetConfigCell . beginParse ( ) ;
9+
10+ return {
11+ supplyAmountMax : assetConfigSlice . loadCoins ( ) ,
12+ protocolFee : assetConfigSlice . loadUint ( PROTOCOL_FEE_BITS ) / PROTOCOL_FEE_BASE ,
13+ }
14+ }
15+
16+ function parsePoolData ( dataBOC ) {
17+ const dataSlice = Cell . fromBase64 ( dataBOC ) . beginParse ( ) ;
18+
19+ dataSlice . loadRef ( )
20+ const { protocolFee : protocolFeeRate , supplyAmountMax } = parseAssetConfig ( dataSlice . loadRef ( ) ) ;
21+ const halted = dataSlice . loadBit ( ) ;
22+ const balance = dataSlice . loadCoins ( ) ;
23+ const borrowed = dataSlice . loadCoins ( ) ;
24+ const lpJettonSupply = dataSlice . loadCoins ( ) ;
25+ return {
26+ halted,
27+ balance,
28+ borrowed,
29+ lpJettonSupply,
30+ protocolFeeRate,
31+ supplyAmountMax,
32+ }
33+ }
34+
35+ async function getContractStateWithRetry ( client , address , maxRetries = 3 , initialDelay = 500 ) {
36+ let attempts = 0 ;
37+
38+ while ( attempts < maxRetries ) {
39+ try {
40+ return await client . getContractState ( address ) ;
41+ } catch ( err ) {
42+ if ( err . message ?. includes ( '429' ) || err . code === 429 ) {
43+ attempts ++ ;
44+ const delay = initialDelay * 2 ** ( attempts - 1 ) ;
45+ console . warn (
46+ `Rate limit (429) encountered. Retrying in ${ delay } ms... (attempt ${ attempts } of ${ maxRetries } )`
47+ ) ;
48+ await new Promise ( ( resolve ) => setTimeout ( resolve , delay ) ) ;
49+ } else {
50+ throw err ;
51+ }
52+ }
53+ }
54+
55+ throw new Error ( `Max retries (${ maxRetries } ) exceeded while getting contract state for address ${ address } .` ) ;
56+ }
57+
58+ async function getPoolData (
59+ client ,
60+ poolAddress ,
61+ token ,
62+ tokenSymbol ,
63+ price ,
64+ scale ,
65+ poolName ,
66+ borrowRate
67+ ) {
68+ let data ;
69+ try {
70+ const result = await getContractStateWithRetry (
71+ client ,
72+ Address . parse ( poolAddress ) ,
73+ 5 , // maxRetries
74+ 500 // initialDelay in ms
75+ ) ;
76+ if ( ! result ?. data ) {
77+ throw new Error ( 'Master data not found' ) ;
78+ }
79+
80+ data = parsePoolData ( result . data . toString ( 'base64' ) ) ;
81+ } catch ( error ) {
82+ console . error ( 'getPoolData error:' , error ) ;
83+ return ;
84+ }
85+
86+ const totalSupply = Number ( data . balance + data . borrowed ) / scale ;
87+ const totalBorrow = Number ( data . borrowed ) / scale ;
88+ const totalSupplyUsd = ( totalSupply * price ) ;
89+ const totalBorrowUsd = ( totalBorrow * price ) ;
90+ const utilization = totalSupply > 0 ? totalBorrow / totalSupply : 0 ;
91+ const supplyRate = borrowRate * utilization * ( 1 - data . protocolFeeRate ) ;
92+ const supplyApy = ( 1 + supplyRate ) ** 365 - 1 ;
93+ const borrowApy = ( 1 + borrowRate ) ** 365 - 1 ;
94+
95+ console . log ( poolName , tokenSymbol , 'totalSupplyInUsd' , totalSupplyUsd ) ;
96+ console . log ( poolName , tokenSymbol , 'totalBorrowInUsd' , totalBorrowUsd ) ;
97+ console . log ( poolName , tokenSymbol , 'supplyApy' , supplyApy * 100 ) ;
98+ console . log ( poolName , tokenSymbol , 'borrowApy' , borrowApy * 100 ) ;
99+
100+ return {
101+ pool : `daolama-${ poolAddress } -${ poolName } -ton` . toLowerCase ( ) ,
102+ chain : 'Ton' ,
103+ project : 'daolama' ,
104+ symbol : tokenSymbol ,
105+ tvlUsd : totalSupplyUsd - totalBorrowUsd ,
106+ apyBase : supplyApy * 100 ,
107+ apyBaseBorrow : borrowApy * 100 ,
108+ underlyingTokens : [ token ] ,
109+ totalSupplyUsd,
110+ totalBorrowUsd,
111+ poolMeta : poolName ,
112+ url : `https://app.daolama.co/yield` ,
113+ } ;
114+ }
115+
116+ async function getApy ( ) {
117+ const TON = 'ton:EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c' ;
118+ const price = async ( token ) => ( await utils . getData ( `https://coins.llama.fi/prices/current/${ token } ` ) ) . coins [ token ] . price ;
119+ const tonPrice = await price ( TON ) ;
120+ const borrowRate = ( await utils . getData ( 'https://api.daolama.co/api/v1/analytics/borrowed/rate' ) ) . value ;
121+ const client = new TonClient ( {
122+ endpoint : 'https://toncenter.com/api/v2/jsonRPC' ,
123+ } ) ;
124+
125+ const poolData = await Promise . all ( [
126+ getPoolData (
127+ client ,
128+ 'EQCkeTvOSTBwBtP06X2BX7THj_dlX67PhgYRGuKfjWtB9FVb' ,
129+ 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c' ,
130+ 'TON' ,
131+ tonPrice ,
132+ 1e9 ,
133+ 'Main' ,
134+ borrowRate ,
135+ ) ,
136+ ] ) ;
137+
138+ return poolData . filter ( ( pool ) => pool !== undefined ) ;
139+ }
140+
141+ module . exports = {
142+ timetravel : false ,
143+ apy : getApy ,
144+ url : 'https://daolama.co/' ,
145+ } ;
0 commit comments