Skip to content

Commit a1cc450

Browse files
authored
Merge pull request #2154 from daolama/master
feat: add yield adapter for DAOLama protocol
2 parents 2159a7d + 5cbb3bb commit a1cc450

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

src/adaptors/daolama/index.js

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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

Comments
 (0)