Skip to content

Commit 83328f3

Browse files
authored
smartcredit: fix TVL, add borrowed & staking based on fixed income funds (#17250)
1 parent d256e9f commit 83328f3

File tree

1 file changed

+100
-74
lines changed

1 file changed

+100
-74
lines changed

projects/smartcredit.js

Lines changed: 100 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,54 @@
1-
const ADDRESSES = require('./helper/coreAssets.json')
2-
const { cachedGraphQuery } = require('./helper/cache')
31
const { getLogs } = require('./helper/cache/getLogs')
42

5-
const endPoint = 'https://d2c7awq32ho327.cloudfront.net/graphql'
63
const SMART_CREDIT = '0x72e9D9038cE484EE986FEa183f8d8Df93f9aDA13'.toLowerCase()
74
const factory = '0x31ba589072278D82207212702De9A1C2B9D42c28'
85
const fromBlock = 14575305
96
const factoryAbi = {
107
"FixedIncomeFundCreationComplete": "event FixedIncomeFundCreationComplete(address indexed fixedIncomeFund, bytes32 indexed salt)",
118
"LoanContractCreated": "event LoanContractCreated(address indexed creditLine, address indexed borrower, bytes32 salt, bytes32 _type)",
12-
"createCreditLine": "function createCreditLine(bytes32 _type, bytes32 _salt) returns (address _creditLine)",
13-
"createNFTLoan": "function createNFTLoan(bytes32 _type, bytes32 _salt, tuple(address assetAddress, uint256 loanAmount, uint256 loanTerm, uint256 interestRate, address collateralAddress, uint256 collateralId) _loanRequest) returns (address _loanContract)",
14-
"createFixedIncomeFund": "function createFixedIncomeFund(bytes32 _type, bytes32 _salt, uint256[4] _ratios) returns (address _fixedIncomeFund)",
15-
"investFixedIncomeFundToCompound": "function investFixedIncomeFundToCompound(address[] _fixedIncomeFunds)"
16-
}
17-
18-
const loanAbi = {
19-
"getLoanData": "function getLoanData(bytes32 _loanId) view returns (bytes32 loanId, uint256 currentCollateralAmount, uint256 loanEnded, uint256 outstandingAmount)",
209
}
2110

2211
const fixedIncomeAbi = {
23-
"getCurrencyAddress": "address:getCurrencyAddress",
2412
"getCompoundAddress": "address:getCompoundAddress",
25-
"fixedIncomeFundBalance": "uint256:fixedIncomeFundBalance"
13+
"fixedIncomeFundBalance": "uint256:fixedIncomeFundBalance",
14+
"getFixedIncomeFundDetails": "function getFixedIncomeFundDetails() external view returns(address owner, address currency, uint256 balance, uint256 invested, uint256[4] memory buckets)"
2615
}
2716

17+
// Supported tokens (hardcoded for efficiency - verified from protocol docs)
18+
const collateralTokens = [
19+
"0x0000000000000000000000000000000000000000", // ETH (null address)
20+
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC
21+
"0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT
22+
"0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", // stETH
23+
"0x6b175474e89094c44da98b954eedeac495271d0f", // DAI
24+
"0x221657776846890989a759ba2973e427dff5c9bb", // REP
25+
"0x514910771af9ca656af840dff83e8264ecf986ca", // LINK
26+
"0x0d8775f648430679a709e98d2b0cb6250d2887ef" // BAT
27+
]
28+
const underlyingTokens = [
29+
"0x0000000000000000000000000000000000000000", // ETH
30+
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC
31+
"0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT
32+
"0x6b175474e89094c44da98b954eedeac495271d0f" // DAI
33+
]
2834

29-
const transformNull = i => i.toLowerCase() === ADDRESSES.GAS_TOKEN_2.toLowerCase() ? ADDRESSES.null : i
30-
31-
async function staking(api) {
32-
let { loanRequests } = await cachedGraphQuery('smart-credit', endPoint, `{
33-
loanRequests {
34-
id,
35-
contractAddress,
36-
loanStatus,
37-
liquidationStatus,
38-
underlying { ethAddress },
39-
collateral { ethAddress }
40-
}
41-
}`)
42-
loanRequests = loanRequests.filter(i => i)
43-
const ownerTokens = loanRequests.map(i => [[i.underlying.ethAddress, i.collateral.ethAddress].map(transformNull), i.contractAddress])
44-
return api.sumTokens({ ownerTokens, whitelistedTokens: [SMART_CREDIT] })
45-
}
46-
47-
module.exports = {
48-
timetravel: false,
49-
ethereum: {
50-
tvl,
51-
staking,
52-
borrowed,
53-
}
54-
}
5535

36+
/**
37+
* TVL: Sum of assets in Fixed Income Funds + collateral in Loan contracts
38+
* - Fixed Income: underlying tokens deposited by lenders
39+
* - Loans: collateral tokens deposited by borrowers
40+
*/
5641
async function tvl(api) {
5742
await fixedIncomeTvl(api)
58-
await loanTvl(api)
43+
await collateralTvl(api)
5944
return api.getBalances()
6045
}
6146

62-
47+
/**
48+
* Fixed Income TVL: Underlying tokens deposited in Fixed Income Funds by lenders
49+
* Excludes SMARTCREDIT protocol token to avoid double-counting with staking
50+
* @param {Object} api - DefiLlama SDK api instance
51+
*/
6352
async function fixedIncomeTvl(api) {
6453
const logs = await getLogs({
6554
api,
@@ -70,44 +59,81 @@ async function fixedIncomeTvl(api) {
7059
extraKey: 'fixedIncomeFund',
7160
})
7261
const pools = logs.map(l => l.fixedIncomeFund)
73-
const tokens = (await api.multiCall({ abi: fixedIncomeAbi.getCurrencyAddress, calls: pools })).map(transformNull)
74-
75-
await api.sumTokens({ tokensAndOwners2: [tokens, pools], blacklistedTokens: [SMART_CREDIT] })
62+
await api.sumTokens({ tokens: underlyingTokens, owners: pools, blacklistedTokens: [SMART_CREDIT] })
7663
}
7764

78-
async function loanTvl(api) {
79-
let { loanRequests } = await cachedGraphQuery('smart-credit', endPoint, `{
80-
loanRequests {
81-
id,
82-
contractAddress,
83-
loanStatus,
84-
liquidationStatus,
85-
underlying { ethAddress },
86-
collateral { ethAddress }
87-
}
88-
}`)
89-
loanRequests = loanRequests.filter(i => i)
90-
const ownerTokens = loanRequests.map(i => [[i.underlying.ethAddress, i.collateral.ethAddress].map(transformNull), i.contractAddress])
91-
return api.sumTokens({ ownerTokens, blacklistedTokens: [SMART_CREDIT] })
65+
/**
66+
* Collateral TVL: Collateral tokens in active loan contracts (creditlines)
67+
* Borrowers deposit collateral which stays locked until loans are repaid/liquidated
68+
* @param {Object} api - DefiLlama SDK api instance
69+
*/
70+
async function collateralTvl(api) {
71+
const logs = await getLogs({
72+
api,
73+
target: factory,
74+
eventAbi: factoryAbi.LoanContractCreated,
75+
onlyArgs: true,
76+
fromBlock,
77+
extraKey: 'creditLine',
78+
})
79+
const pools = logs.map(l => l.creditLine.toLowerCase())
80+
await api.sumTokens({ tokens: collateralTokens, owners: pools })
9281
}
9382

83+
84+
85+
/**
86+
* Borrowed: Total outstanding loan principal across all Fixed Income Funds
87+
* All borrows originate from Fixed Income Funds → invested amount = total borrowed
88+
* Excludes SMARTCREDIT token loans (protocol-internal operations)
89+
* @param {Object} api - DefiLlama SDK api instance
90+
* @returns {Object} Balances object with borrowed amounts by token
91+
*/
9492
async function borrowed(api) {
95-
let { loanRequests } = await cachedGraphQuery('smart-credit', endPoint, `{
96-
loanRequests {
97-
id,
98-
contractAddress,
99-
loanStatus,
100-
liquidationStatus,
101-
underlying { ethAddress },
102-
collateral { ethAddress }
103-
}
104-
}`)
105-
loanRequests = loanRequests.filter(i => i)
106-
const calls = loanRequests.map(i => ({ target: i.contractAddress, params: [i.id] }))
107-
const loanInfos = await api.multiCall({ abi: loanAbi.getLoanData, calls})
108-
loanInfos.forEach((i, idx) => {
109-
if (i.outstandingAmount === '0') return
110-
api.add(loanRequests[idx].underlying.ethAddress, i.outstandingAmount)
93+
const logs = await getLogs({
94+
api,
95+
target: factory,
96+
eventAbi: factoryAbi.FixedIncomeFundCreationComplete,
97+
onlyArgs: true,
98+
fromBlock,
99+
extraKey: 'fixedIncomeFund',
100+
})
101+
102+
const pools = logs.map(l => l.fixedIncomeFund)
103+
const poolInfos = await api.multiCall({ abi: fixedIncomeAbi.getFixedIncomeFundDetails, calls: pools })
104+
105+
poolInfos.forEach((i, idx) => {
106+
if (i.currency.toLowerCase() === SMART_CREDIT) return
107+
const token = i.currency === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' ? '0x0000000000000000000000000000000000000000' : i.currency;
108+
api.add(token, i.invested)
111109
})
112110
return api.getBalances()
111+
}
112+
113+
114+
/**
115+
* Staking: SMARTCREDIT protocol tokens staked in Fixed Income Funds
116+
* @param {Object} api - DefiLlama SDK api instance
117+
*/
118+
async function staking(api) {
119+
const logs = await getLogs({
120+
api,
121+
target: factory,
122+
eventAbi: factoryAbi.FixedIncomeFundCreationComplete,
123+
onlyArgs: true,
124+
fromBlock,
125+
extraKey: 'fixedIncomeFund',
126+
})
127+
const pools = logs.map(l => l.fixedIncomeFund)
128+
return api.sumTokens({ owners: pools, tokens: [SMART_CREDIT] })
129+
}
130+
131+
132+
module.exports = {
133+
timetravel: false,
134+
ethereum: {
135+
tvl,
136+
staking,
137+
borrowed,
138+
}
113139
}

0 commit comments

Comments
 (0)