Skip to content

Commit 9325c1d

Browse files
authored
feat(adaptors/silo-v2): support for Silo V2 (#1695)
* feat(adaptors/silo-v2): support for Silo V2 * feat(adaptors/silo-v2): fix variable refactor * feat(adaptors/silo-v2): adjust returned datatypes
1 parent c56bc14 commit 9325c1d

File tree

3 files changed

+309
-5
lines changed

3 files changed

+309
-5
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"license": "ISC",
1616
"dependencies": {
1717
"@blend-capital/blend-sdk": "^2.2.0",
18-
"@defillama/sdk": "^5.0.60",
18+
"@defillama/sdk": "^5.0.112",
1919
"@stacks/network": "^6.13.0",
2020
"@stacks/transactions": "^6.15.0",
2121
"@ton/ton": "14.0.0",

src/adaptors/silo-v2/index.js

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
const sdk = require('@defillama/sdk');
2+
const { request, gql } = require('graphql-request');
3+
const BigNumber = require('bignumber.js');
4+
const ethers = require('ethers');
5+
6+
const utils = require('../utils');
7+
8+
BigNumber.config({ EXPONENTIAL_AT: [-1e9, 1e9] });
9+
10+
const XAI = '0xd7c9f0e536dc865ae858b0c0453fe76d13c3beac'
11+
const blacklistedSilos = ["0x6543ee07cf5dd7ad17aeecf22ba75860ef3bbaaa",];
12+
13+
const getAssetAbiV2 = "address:asset";
14+
const getSiloConfigMarketId = "uint256:SILO_ID";
15+
const getAssetBalanceAbi = "function balanceOf(address account) external view returns (uint256)";
16+
const getAssetSymbolAbi = "function symbol() public view returns (string memory)";
17+
const getAssetDecimalsAbi = "function decimals() public view returns (uint256)";
18+
const getSiloStorageAbi = "function getSiloStorage() external view returns (uint192 daoAndDeployerRevenue, uint64 interestRateTimestamp, uint256 protectedAssets, uint256 collateralAssets, uint256 debtAssets)";
19+
const getSiloAssetBorrowAprAbi = "function getBorrowAPR(address _silo) external view returns (uint256 borrowAPR)";
20+
const getSiloAssetDepositAprAbi = "function getDepositAPR(address _silo) external view returns (uint256 depositAPR)";
21+
const getSiloAssetMaxLtvAbi = "function getMaxLtv(address _silo) external view returns (uint256 maxLtv)";
22+
const getAssetStateAbiV2 = 'function getTotalAssetsStorage(uint8 _assetType) external view returns (uint256 totalAssetsByType)';
23+
24+
const configV2 = {
25+
sonic: {
26+
chainName: "Sonic",
27+
deployments: [
28+
{
29+
START_BLOCK: 2672166,
30+
SILO_FACTORY: '0xa42001d6d2237d2c74108fe360403c4b796b7170', // Silo V2 Sonic (Main)
31+
SILO_LENS: "0xB6AdBb29f2D8ae731C7C72036A7FD5A7E970B198",
32+
}
33+
]
34+
},
35+
// arbitrum: {
36+
// chainName: "Arbitrum",
37+
// factories: [
38+
// {
39+
// START_BLOCK: 291201890,
40+
// SILO_FACTORY: '0xf7dc975C96B434D436b9bF45E7a45c95F0521442', // Silo V2 Arbitrum (Main)
41+
// }
42+
// ]
43+
// }
44+
}
45+
46+
async function getSiloData(api, deploymentData) {
47+
48+
// Handle V2 silos
49+
let siloData = [];
50+
let assetAddressToSymbol = {};
51+
let assetAddressToDecimals = {};
52+
let siloAddressToMarketId = {};
53+
let siloAddressToConfigAddress = {};
54+
if(configV2[api.chain]) {
55+
const {
56+
siloAddresses: siloArrayV2,
57+
siloAddressesToSiloConfigAddress,
58+
} = await getSilosV2(api, deploymentData);
59+
const assetsV2 = await api.multiCall({
60+
abi: getAssetAbiV2,
61+
calls: siloArrayV2.map(i => ({ target: i })),
62+
});
63+
const assetBalancesV2 = await api.multiCall({
64+
abi: getAssetBalanceAbi,
65+
calls: assetsV2.map((asset, i) => ({ target: asset, params: [siloArrayV2[i]] })),
66+
});
67+
const assetBorrowAPR = await api.multiCall({
68+
abi: getSiloAssetBorrowAprAbi,
69+
calls: siloArrayV2.map((siloAddress, i) => ({ target: deploymentData.SILO_LENS, params: [siloAddress] })),
70+
});
71+
const assetDepositAPR = await api.multiCall({
72+
abi: getSiloAssetDepositAprAbi,
73+
calls: siloArrayV2.map((siloAddress, i) => ({ target: deploymentData.SILO_LENS, params: [siloAddress] })),
74+
});
75+
const assetMaxLTV = await api.multiCall({
76+
abi: getSiloAssetMaxLtvAbi,
77+
calls: siloArrayV2.map((siloAddress, i) => ({ target: deploymentData.SILO_LENS, params: [siloAddress] })),
78+
});
79+
const siloStorage = await api.multiCall({
80+
abi: getSiloStorageAbi,
81+
calls: siloArrayV2.map((siloAddress, i) => ({ target: siloAddress, params: [] })),
82+
});
83+
siloData = assetsV2.map((asset, i) => [
84+
asset,
85+
siloArrayV2[i],
86+
assetBalancesV2[i],
87+
assetBorrowAPR[i],
88+
assetDepositAPR[i],
89+
assetMaxLTV[i],
90+
siloStorage[i].protectedAssets,
91+
siloStorage[i].collateralAssets,
92+
siloStorage[i].debtAssets,
93+
]);
94+
let uniqueAssetAddresses = [...new Set(assetsV2)];
95+
const assetSymbols = await api.multiCall({
96+
abi: getAssetSymbolAbi,
97+
calls: uniqueAssetAddresses.map((asset, i) => ({ target: asset })),
98+
});
99+
const assetDecimals = await api.multiCall({
100+
abi: getAssetDecimalsAbi,
101+
calls: uniqueAssetAddresses.map((asset, i) => ({ target: asset })),
102+
});
103+
for(let [index, assetAddress] of uniqueAssetAddresses.entries()) {
104+
assetAddressToSymbol[assetAddress] = assetSymbols[index];
105+
assetAddressToDecimals[assetAddress] = assetDecimals[index];
106+
}
107+
let uniqueSiloConfigAddresses = [...new Set(Object.values(siloAddressesToSiloConfigAddress))];
108+
const siloConfigMarketIds = await api.multiCall({
109+
abi: getSiloConfigMarketId,
110+
calls: uniqueSiloConfigAddresses.map((siloConfig, i) => ({ target: siloConfig })),
111+
});
112+
let siloConfigAddressToMarketId = {};
113+
for(let [index, siloConfigAddress] of uniqueSiloConfigAddresses.entries()) {
114+
siloConfigAddressToMarketId[siloConfigAddress] = siloConfigMarketIds[index];
115+
}
116+
for(let [siloAddress, siloConfigAddress] of Object.entries(siloAddressesToSiloConfigAddress)) {
117+
siloAddressToConfigAddress[siloAddress] = siloConfigAddress;
118+
siloAddressToMarketId[siloAddress] = siloConfigAddressToMarketId[siloConfigAddress];
119+
}
120+
}
121+
122+
let assetPrices = await utils.getPrices(siloData.map(entry => entry[0]), api.chain);
123+
124+
let assetDataBySilo = {};
125+
for(
126+
let [
127+
assetAddress,
128+
siloAddress,
129+
assetBalance,
130+
assetBorrowAPR,
131+
assetDepositAPR,
132+
assetMaxLTV,
133+
protectedAssetBalance,
134+
collateralAssetBalance,
135+
debtAssetBalance
136+
] of siloData
137+
) {
138+
139+
let assetBalanceFormatted = new BigNumber(
140+
ethers.utils.formatUnits(
141+
assetBalance,
142+
assetAddressToDecimals[assetAddress]
143+
)
144+
).toString();
145+
146+
let assetBalanceValueUSD = new BigNumber(
147+
ethers.utils.formatUnits(
148+
assetBalance,
149+
assetAddressToDecimals[assetAddress]
150+
)
151+
)
152+
.multipliedBy(assetPrices.pricesByAddress[assetAddress.toLowerCase()])
153+
.toString();
154+
155+
let assetBorrowAprFormatted = new BigNumber(
156+
ethers.utils.formatUnits(
157+
assetBorrowAPR,
158+
16
159+
)
160+
).toString();
161+
162+
let assetMaxLtvFormatted = new BigNumber(
163+
ethers.utils.formatUnits(
164+
assetMaxLTV,
165+
18
166+
)
167+
).toString();
168+
169+
let assetDepositAprFormatted = new BigNumber(
170+
ethers.utils.formatUnits(
171+
assetDepositAPR,
172+
16
173+
)
174+
).toString();
175+
176+
let totalBorrowValueUSD = new BigNumber(
177+
ethers.utils.formatUnits(
178+
debtAssetBalance,
179+
assetAddressToDecimals[assetAddress]
180+
)
181+
)
182+
.multipliedBy(assetPrices.pricesByAddress[assetAddress.toLowerCase()])
183+
.toString();
184+
185+
let totalSupplyRaw = new BigNumber(collateralAssetBalance).toString();
186+
let totalSupplyValueUSD = new BigNumber(
187+
ethers.utils.formatUnits(
188+
totalSupplyRaw,
189+
assetAddressToDecimals[assetAddress]
190+
)
191+
)
192+
.multipliedBy(assetPrices.pricesByAddress[assetAddress.toLowerCase()])
193+
.toString();
194+
195+
assetDataBySilo[siloAddress] = {
196+
assetAddress: assetAddress,
197+
assetSymbol: assetAddressToSymbol[assetAddress],
198+
assetDecimals: assetAddressToDecimals[assetAddress],
199+
assetBalanceRaw: assetBalance,
200+
assetBalanceFormatted: assetBalanceFormatted,
201+
assetBalanceValueUSD: assetBalanceValueUSD,
202+
assetPrice: assetPrices.pricesByAddress[assetAddress.toLowerCase()],
203+
assetBorrowAprRaw: assetBorrowAPR,
204+
assetDepositAprRaw: assetDepositAPR,
205+
assetBorrowAprFormatted: assetBorrowAprFormatted,
206+
assetDepositAprFormatted: assetDepositAprFormatted,
207+
marketId: siloAddressToMarketId[siloAddress],
208+
siloConfig: siloAddressToConfigAddress[siloAddress],
209+
totalSupplyRaw: totalSupplyRaw,
210+
totalSupplyValueUSD: totalSupplyValueUSD,
211+
totalBorrowRaw: debtAssetBalance,
212+
totalBorrowValueUSD: totalBorrowValueUSD,
213+
assetMaxLtvRaw: assetMaxLTV,
214+
assetMaxLtvFormatted: assetMaxLtvFormatted,
215+
}
216+
}
217+
218+
return assetDataBySilo;
219+
}
220+
221+
async function getSilosV2(chainApi, deploymentData) {
222+
const chain = chainApi.chain;
223+
let logs = [];
224+
let siloAddresses = [];
225+
let siloAddressesToSiloConfigAddress = {};
226+
if(configV2[chain]) {
227+
let latestBlock = await sdk.api.util.getLatestBlock(chain);
228+
const iface = new ethers.utils.Interface([
229+
'event NewSilo(address indexed implementation, address indexed token0, address indexed token1, address silo0, address silo1, address siloConfig)',
230+
]);
231+
const { SILO_FACTORY, START_BLOCK } = deploymentData;
232+
let logChunk = await sdk.api2.util.getLogs({
233+
target: SILO_FACTORY,
234+
topics: ['0x3d6b896c73b628ec6ba0bdfe3cdee1356ea2af31af2a97bbd6b532ca6fa00acb'],
235+
keys: [],
236+
fromBlock: START_BLOCK,
237+
toBlock: latestBlock.block,
238+
chain: chain,
239+
});
240+
logs = [...logs, ...logChunk.output.map((event) => iface.parseLog(event))];
241+
242+
siloAddresses = logs.flatMap((log) => {
243+
244+
let silo0 = log.args[3];
245+
let silo1 = log.args[4];
246+
let siloConfig = log.args[5];
247+
248+
siloAddressesToSiloConfigAddress[silo0] = siloConfig;
249+
siloAddressesToSiloConfigAddress[silo1] = siloConfig;
250+
251+
return [silo0, silo1].filter(
252+
(address) => blacklistedSilos.indexOf(address.toLowerCase()) === -1
253+
);
254+
});
255+
256+
}
257+
258+
return { siloAddresses, siloAddressesToSiloConfigAddress };
259+
}
260+
261+
const main = async () => {
262+
263+
const markets = [];
264+
265+
for(let [chain, config] of Object.entries(configV2)) {
266+
267+
const api = new sdk.ChainApi({ chain });
268+
269+
for(let deploymentData of config.deployments) {
270+
271+
let siloData = await getSiloData(api, deploymentData);
272+
273+
for(let [siloAddress, siloInfo] of Object.entries(siloData)) {
274+
275+
let marketData = {
276+
pool: `${siloInfo.marketId}-${siloAddress}-${chain}`,
277+
chain: config.chainName,
278+
project: 'silo-v2',
279+
symbol: utils.formatSymbol(siloInfo.assetSymbol),
280+
tvlUsd: new BigNumber(siloInfo.assetBalanceValueUSD).toNumber(),
281+
apyBase: new BigNumber(siloInfo.assetDepositAprFormatted).toNumber(),
282+
apyBaseBorrow: new BigNumber(siloInfo.assetBorrowAprFormatted).toNumber(),
283+
url: `https://v2.silo.finance/markets/${chain}/${siloInfo.marketId}`,
284+
underlyingTokens: [siloInfo.assetAddress],
285+
ltv: Number(siloInfo.assetMaxLtvFormatted),
286+
totalBorrowUsd: Number(Number(siloInfo.totalBorrowValueUSD).toFixed(2)),
287+
totalSupplyUsd: Number(Number(siloInfo.totalSupplyValueUSD).toFixed(2)),
288+
poolMeta: `${siloInfo.marketId}`,
289+
};
290+
291+
markets.push(marketData);
292+
}
293+
294+
}
295+
296+
}
297+
298+
return markets;
299+
};
300+
301+
module.exports = {
302+
timetravel: false,
303+
apy: main,
304+
};

0 commit comments

Comments
 (0)