Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions projects/solid/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/* SOLID Protocol (Terra, phoenix-1) — Collateral-only TVL adapter
* Now returns BALANCES ONLY (no price/exchange-rate math in adapter).
* ampLUNA / bLUNA pricing to be handled by DefiLlama coin-prices infra.
*/

const fetch = require('node-fetch')
const { sumSingleBalance } = require('@defillama/sdk/build/generalUtil')

// ----- LCD endpoint (overridable) -----
const LCD = process.env.TERRA_LCD || 'https://terra-api.cosmosrescue.dev:8443'

// ----- Addresses -----
const ADDR = {
// SOLID stablecoin contract (borrowed supply)
SOLID: {
token: 'terra10aa3zdkrc7jwuf8ekl3zq7e7m42vmzqehcmu74e4egc7xkm5kr2s0muyst',
},
// CW20 collaterals
ampLUNA: {
token: 'terra1ecgazyd0waaj3g7l9cmy5gulhxkps2gmxu9ghducvuypjq68mq2s5lvsct',
custody: 'terra18uxq2k6wpsqythpakz5n6ljnuzyehrt775zkdclrtdtv6da63gmskqn7dq',
},
bLUNA: {
token: 'terra17aj4ty4sz4yhgm08na8drc0v03v2jwr3waxcqrwhajj729zhl7zqnpc0ml',
custody: 'terra1fyfrqdf58nf4fev2amrdrytq5d63njulfa7sm75c0zu4pnr693dsqlr7p9',
},
wSOL: {
token: 'terra1ctelwayk6t2zu30a8v9kdg3u2gr0slpjdfny5pjp7m3tuquk32ysugyjdg',
custody: 'terra1e32q545j90agakl32mtkacq05990cnr54czj8wp0wv3nttkrhwlqr9spf5',
},
wBNB: {
token: 'terra1xc7ynquupyfcn43sye5pfmnlzjcw2ck9keh0l2w2a4rhjnkp64uq4pr388',
custody: 'terra1fluajm00hwu9wyy8yuyf4zag7x5pw95vdlgkhh8w03pfzqj6hapsx4673t',
},

// IBC/native denoms (bank module)
USDC: {
denom: 'ibc/2C962DAB9F57FE0921435426AE75196009FAA1981BF86991203C8411F8980FDB',
custody: 'terra1hdu4t2mrrv98rwdzps40va7me3xjme32upcw36x4cda8tx9cee9qrwdhsl',
},
wETH: {
denom: 'ibc/BC8A77AFBD872FDC32A348D3FB10CC09277C266CFE52081DE341C7EC6752E674',
custody: 'terra1lz9048tzegtspy35chwq2lmlhtwz8qq4jdvpua8yslskfnpk6yfsw06090',
},
wBTC: {
denom: 'ibc/05D299885B07905B6886F554B39346EA6761246076A1120B1950049B92B922DD',
custody: 'terra163nmjy97n7dqpdaxp6gts0xrnchn2nsg2d40wrgqnpguf0v9rvdslytfpz',
},
}

// ----- helpers -----
function b64(obj) {
return Buffer.from(JSON.stringify(obj)).toString('base64')
}

// robust smart query: path form `/smart/{b64}` works across LCDs
async function smartQuery(contract, msgObj) {
const url = `${LCD}/cosmwasm/wasm/v1/contract/${contract}/smart/${b64(msgObj)}`
const res = await fetch(url)
if (!res.ok) throw new Error(`wasm smart query failed: ${res.status}`)
const json = await res.json()
// some LCDs wrap under 'data' or 'result'
return json.data || json.result || json
}

async function bankBalances(address) {
const url = `${LCD}/cosmos/bank/v1beta1/balances/${address}?pagination.limit=1000`
const res = await fetch(url)
if (!res.ok) throw new Error(`bank balances failed: ${res.status}`)
const json = await res.json()
return json.balances || []
}

async function cw20Balance(token, address) {
const r = await smartQuery(token, { balance: { address } })
const bal = (r && r.balance) ? r.balance : (r?.data?.balance || '0')
return BigInt(bal)
}

async function cw20Decimals(token) {
const r = await smartQuery(token, { token_info: {} })
return r.decimals ?? r.token_info?.decimals ?? 6
}

async function cw20TotalSupply(token) {
const r = await smartQuery(token, { token_info: {} })
return BigInt(r.total_supply || r?.token_info?.total_supply || '0')
}

function addBig(balances, key, amount) {
if (!amount) return
const prev = BigInt(balances[key] || 0)
balances[key] = (prev + BigInt(amount)).toString()
}

// ----- TVL -----
async function tvl() {
const balances = {}

// CW20 balances (report as raw token balances)
for (const key of ['ampLUNA', 'bLUNA', 'wSOL', 'wBNB']) {
const { token, custody } = ADDR[key]
try {
const [bal, dec] = await Promise.all([cw20Balance(token, custody), cw20Decimals(token)])
// return raw amount in smallest units (string). DefiLlama will price it.
const raw = BigInt(bal) // already smallest unit from contract
addBig(balances, `terra2:${token}`, raw.toString())
} catch (e) {
// skip on error
// console.error('cw20 fetch error', key, e)
continue
}
}

// IBC/native balances (bank module)
for (const key of ['USDC', 'wETH', 'wBTC']) {
const { denom, custody } = ADDR[key]
try {
const list = await bankBalances(custody)
const row = list.find((x) => x.denom === denom)
if (row && row.amount) addBig(balances, `terra2:${denom}`, row.amount)
} catch (e) {
// console.error('bank fetch error', key, e)
continue
}
}

return balances
}

// ----- Borrowed (SOLID totalSupply) -----
async function borrowed() {
try {
const total = await cw20TotalSupply(ADDR.SOLID.token)
return { [`terra2:${ADDR.SOLID.token}`]: total.toString() }
} catch {
return {}
}
}

module.exports = {
timetravel: false,
misrepresentedTokens: false,
methodology:
'TVL = sum of custody balances for SOLID collaterals (ampLUNA, bLUNA, USDC (Noble IBC), axl.WETH, axl.WBTC, wSOL (Wormhole), wBNB (Wormhole)). ' +
'Adapter returns token balances only; pricing (including LST exchange rates) is handled by DefiLlama coin-prices infra.',
terra2: { tvl, borrowed },
}
Loading