Skip to content

Commit 64031f3

Browse files
Merge branch 'DefiLlama:master' into feat/add-parallel-protocol-sUSDp
2 parents 0c49fff + 534494e commit 64031f3

File tree

18 files changed

+3554
-15
lines changed

18 files changed

+3554
-15
lines changed

src/adaptors/balancer-v3/index.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,33 @@ const getV3Pools = async (backendChain, chainString) => {
7878
};
7979

8080
const poolsFunction = async () => {
81-
const [mainnetPools, gnosisPools] = await Promise.all([
81+
const [
82+
mainnetPools,
83+
gnosisPools,
84+
arbitrumPools,
85+
optimismPools,
86+
avalanchePools,
87+
basePools,
88+
hyperliquidPools,
89+
] = await Promise.all([
8290
getV3Pools('MAINNET', 'ethereum'),
8391
getV3Pools('GNOSIS', 'xdai'),
92+
getV3Pools('ARBITRUM', 'arbitrum'),
93+
getV3Pools('OPTIMISM', 'optimism'),
94+
getV3Pools('AVALANCHE', 'avax'),
95+
getV3Pools('BASE', 'base'),
96+
getV3Pools('HYPEREVM', 'hyperliquid'),
8497
]);
8598

86-
return [...mainnetPools, ...gnosisPools];
99+
return [
100+
...mainnetPools,
101+
...gnosisPools,
102+
...arbitrumPools,
103+
...optimismPools,
104+
...avalanchePools,
105+
...basePools,
106+
...hyperliquidPools,
107+
];
87108
};
88109

89110
module.exports = {

src/adaptors/garden/index.js

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
const sdk = require('@defillama/sdk');
2+
const axios = require('axios');
3+
const utils = require('../utils');
4+
const { ethers } = require('ethers');
5+
6+
const GARDEN_STAKING_CONTRACT = '0xe2239938Ce088148b3Ab398b2b77Eedfcd9d1AfC'
7+
const SEED_TOKEN = '0x86f65121804D2Cdbef79F9f072D4e0c2eEbABC08'
8+
const chain = 'arbitrum'
9+
10+
// Event topics for staking events
11+
const STAKED_EVENT_TOPIC = '0xa1fdccfe567643a44425efdd141171e8d992854a81e5c819c1432b0de47c9a11';
12+
const STAKE_REFUNDED_EVENT_TOPIC = '0xba33cc6a4502f7f80bfe643ffa925ba7ab5e0af61c061a9aceabef0349c9dce4';
13+
const MAX_UINT256 = ethers.constants.MaxUint256;
14+
15+
// ABI for the events we need
16+
const eventAbi = [
17+
{
18+
"anonymous": false,
19+
"inputs": [
20+
{
21+
"indexed": true,
22+
"internalType": "bytes32",
23+
"name": "stakeID",
24+
"type": "bytes32"
25+
},
26+
{
27+
"indexed": true,
28+
"internalType": "address",
29+
"name": "owner",
30+
"type": "address"
31+
},
32+
{
33+
"indexed": false,
34+
"internalType": "uint256",
35+
"name": "stake",
36+
"type": "uint256"
37+
},
38+
{
39+
"indexed": false,
40+
"internalType": "uint256",
41+
"name": "expiry",
42+
"type": "uint256"
43+
}
44+
],
45+
"name": "Staked",
46+
"type": "event"
47+
},
48+
{
49+
"anonymous": false,
50+
"inputs": [
51+
{
52+
"indexed": true,
53+
"internalType": "bytes32",
54+
"name": "stakeID",
55+
"type": "bytes32"
56+
}
57+
],
58+
"name": "StakeRefunded",
59+
"type": "event"
60+
},
61+
];
62+
63+
// TVL Calculator class (simplified for adapter use)
64+
class TVLCalculator {
65+
constructor() {
66+
this.stakes = new Map(); // stakeID -> stake amount
67+
}
68+
69+
async fetchEvents() {
70+
71+
try {
72+
// Get current block number
73+
const currentBlock = await sdk.api.util.getLatestBlock(chain);
74+
const toBlock = currentBlock.number;
75+
const fromBlock = 192080606; // Contract deployment block
76+
77+
// Fetch Staked events
78+
const stakedLogs = (
79+
await sdk.api.util.getLogs({
80+
target: GARDEN_STAKING_CONTRACT,
81+
topic: '',
82+
toBlock,
83+
fromBlock,
84+
keys: [],
85+
topics: [STAKED_EVENT_TOPIC],
86+
chain: chain,
87+
})
88+
).output;
89+
90+
// Fetch StakeRefunded events
91+
const refundedLogs = (
92+
await sdk.api.util.getLogs({
93+
target: GARDEN_STAKING_CONTRACT,
94+
topic: '',
95+
toBlock,
96+
fromBlock,
97+
keys: [],
98+
topics: [STAKE_REFUNDED_EVENT_TOPIC],
99+
chain: chain,
100+
})
101+
).output;
102+
103+
return { stakedLogs, refundedLogs, currentBlock: currentBlock.number };
104+
105+
} catch (error) {
106+
console.error('Error fetching events:', error);
107+
throw error;
108+
}
109+
}
110+
111+
async processEvents(stakedLogs, refundedLogs) {
112+
113+
try {
114+
115+
const abiInterface = new ethers.utils.Interface(eventAbi);
116+
const refundedStakeIDs = new Set(); // Track refunded stake IDs
117+
118+
// Process staked events first
119+
for (const log of stakedLogs) {
120+
try {
121+
const formattedLog = {
122+
address: log.address,
123+
topics: log.topics,
124+
data: log.data,
125+
blockNumber: typeof log.blockNumber === 'string' ? parseInt(log.blockNumber, 16) : log.blockNumber,
126+
transactionHash: log.transactionHash,
127+
logIndex: log.logIndex
128+
};
129+
130+
const decoded = abiInterface.parseLog(formattedLog);
131+
const stakeID = decoded.args.stakeID;
132+
const stakeAmount = decoded.args.stake;
133+
const owner = decoded.args.owner;
134+
const expiry = decoded.args.expiry;
135+
136+
this.stakes.set(stakeID, {
137+
amount: stakeAmount.toString(),
138+
owner: owner,
139+
expiry: expiry.toString(),
140+
blockNumber: formattedLog.blockNumber,
141+
transactionHash: log.transactionHash
142+
});
143+
144+
} catch (error) {
145+
console.warn('Failed to decode staked event:', error.message);
146+
}
147+
}
148+
149+
// Process refunded events to remove stakes
150+
for (const log of refundedLogs) {
151+
try {
152+
const formattedLog = {
153+
address: log.address,
154+
topics: log.topics,
155+
data: log.data,
156+
blockNumber: typeof log.blockNumber === 'string' ? parseInt(log.blockNumber, 16) : log.blockNumber,
157+
transactionHash: log.transactionHash,
158+
logIndex: log.logIndex
159+
};
160+
161+
const decoded = abiInterface.parseLog(formattedLog);
162+
const stakeID = decoded.args.stakeID;
163+
164+
refundedStakeIDs.add(stakeID);
165+
this.stakes.delete(stakeID);
166+
167+
} catch (error) {
168+
console.warn('Failed to decode refunded event:', error.message);
169+
}
170+
}
171+
172+
} catch (error) {
173+
console.error('Error processing events:', error);
174+
throw error;
175+
}
176+
}
177+
178+
calculateTVL() {
179+
try {
180+
let totalTVLWei = BigInt(0);
181+
182+
for (const [stakeID, stakeInfo] of this.stakes.entries()) {
183+
totalTVLWei += BigInt(stakeInfo.amount);
184+
}
185+
186+
const totalTVLEther = ethers.utils.formatEther(totalTVLWei);
187+
188+
return {
189+
tvl: totalTVLEther,
190+
};
191+
192+
} catch (error) {
193+
console.error('Error calculating TVL:', error);
194+
throw error;
195+
}
196+
}
197+
}
198+
199+
const getTvl = async () => {
200+
try {
201+
// Get APY data
202+
const apyData = await utils.getData('https://stakingv2.garden.finance/apy');
203+
204+
// Calculate TVL using event-based method
205+
const calculator = new TVLCalculator();
206+
207+
// Fetch and process events
208+
const { stakedLogs, refundedLogs } = await calculator.fetchEvents();
209+
await calculator.processEvents(stakedLogs, refundedLogs);
210+
211+
// Calculate TVL from events
212+
const tvlResult = calculator.calculateTVL();
213+
const tvl = parseFloat(tvlResult.tvl);
214+
215+
216+
// Get SEED price
217+
const priceData = await axios.get(
218+
'https://coins.llama.fi/prices/current/arbitrum:0x86f65121804D2Cdbef79F9f072D4e0c2eEbABC08'
219+
);
220+
221+
const seedPrice = priceData.data.coins[`${chain}:${SEED_TOKEN}`]?.price || 0;
222+
223+
// Calculate TVL in USD
224+
const tvlUsd = tvl * seedPrice;
225+
226+
return [{
227+
pool: '0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf-base',
228+
chain: utils.formatChain(chain),
229+
project: 'garden',
230+
symbol: utils.formatSymbol('SEED'),
231+
tvlUsd: tvlUsd,
232+
apy: apyData.data,
233+
}];
234+
235+
} catch (error) {
236+
console.error('Error in getTvl:', error);
237+
return [];
238+
}
239+
};
240+
241+
module.exports = {
242+
timetravel: false,
243+
apy: getTvl,
244+
url: 'https://app.garden.finance/stake',
245+
};

0 commit comments

Comments
 (0)