Add Exponent TVL (#13339)

Co-authored-by: g1nt0ki <99907941+g1nt0ki@users.noreply.github.com>
This commit is contained in:
Valentin Madrid
2025-02-03 20:47:08 +04:00
committed by GitHub
parent 9b045b302a
commit 045855a144
3 changed files with 156 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
{
"address": "ExponentnaRg3CQbW6dqQNZKXp7gtZ9DGMp1cwC4HAS7",
"metadata": {"name": "exponent_core", "version": "0.1.0", "spec": "0.1.0", "description": "Created with Anchor"},
"instructions": [],
"accounts": [{"name": "Vault", "discriminator": [211, 8, 232, 43, 2, 152, 117, 119]}],
"events": [],
"errors": [],
"types": [
{
"name": "Vault",
"type": {
"kind": "struct",
"fields": [
{"name": "sy_program", "docs": ["Link to SY program"], "type": "pubkey"},
{"name": "mint_sy", "docs": ["Mint for SY token"], "type": "pubkey"},
{"name": "mint_yt", "docs": ["Mint for the vault-specific YT token"], "type": "pubkey"},
{"name": "mint_pt", "docs": ["Mint for the vault-specific PT token"], "type": "pubkey"},
{"name": "escrow_yt", "docs": ["Escrow account for holding deposited YT"], "type": "pubkey"},
{
"name": "escrow_sy",
"docs": ["Escrow account that holds temporary SY tokens", "As an interchange between users and the SY program"],
"type": "pubkey"
},
{
"name": "yield_position",
"docs": ["Link to a vault-owned YT position", "This account collects yield from all unstaked YT"],
"type": "pubkey"
},
{"name": "address_lookup_table", "docs": ["Address lookup table key for vault"], "type": "pubkey"},
{"name": "start_ts", "docs": ["start timestamp"], "type": "u32"},
{"name": "duration", "docs": ["seconds duration"], "type": "u32"},
{"name": "signer_seed", "docs": ["Seed for CPI signing"], "type": "pubkey"},
{"name": "authority", "docs": ["Authority for CPI signing"], "type": "pubkey"},
{"name": "signer_bump", "docs": ["bump for signer authority PDA"], "type": {"array": ["u8", 1]}},
{
"name": "last_seen_sy_exchange_rate",
"docs": [
"Last seen SY exchange rate",
"Not needed for live use, but only when the vault has matured, and we need to freeze earnings for YT holders",
"This will not get updated after vault is mautured"
],
"type": {"defined": {"name": "Number"}}
},
{
"name": "all_time_high_sy_exchange_rate",
"docs": ["This is the all time high exchange rate for SY"],
"type": {"defined": {"name": "Number"}}
},
{
"name": "final_sy_exchange_rate",
"docs": ["This is the exchange rate for SY when the vault expires"],
"type": {"defined": {"name": "Number"}}
},
{"name": "total_sy_in_escrow", "docs": ["How much SY is held in escrow"], "type": "u64"},
{
"name": "sy_for_pt",
"docs": [
"The total SY set aside to back the PT holders",
"This value is updated on every operation that touches the PT supply or the last seen exchange rate"
],
"type": "u64"
},
{"name": "pt_supply", "docs": ["Total supply of PT"], "type": "u64"},
{"name": "treasury_sy", "docs": ["Amount of SY staged for the treasury"], "type": "u64"},
{"name": "uncollected_sy", "docs": ["SY that has been earned by YT, but not yet collected"], "type": "u64"},
{
"name": "treasury_sy_token_account",
"docs": [
"SY that has been staged for collection, but not yet collected",
"It is strictly greater-than-or-equal to the treasury_sy",
"And strictly less than or equal to the total_sy_in_escrow"
],
"type": "pubkey"
},
{"name": "interest_bps_fee", "type": "u16"},
{"name": "min_op_size_strip", "type": "u64"},
{"name": "min_op_size_merge", "type": "u64"},
{"name": "status", "type": "u8"}
]
}
},
{
"name": "Number",
"docs": ["High precision number, stored as 4 u64 words in little endian"],
"type": {"kind": "struct", "fields": [{"array": ["u64", 4]}]}
}
]
}

View File

@@ -0,0 +1,62 @@
const { getConnection, getProvider } = require("../helper/solana");
const { PublicKey } = require("@solana/web3.js");
const { decodeAccount } = require("../helper/utils/solana/layout");
const { Program } = require("@coral-xyz/anchor");
const { getConfig } = require('../helper/cache')
const idl = require('./idl.json')
async function tvl(api) {
const provider = getProvider()
const connection = getConnection()
const program = new Program(idl, provider)
const vaults = await program.account.vault.all()
const mintRateMap = {}
const mintAccountMap = {}
vaults.forEach(v => {
const rate = v.account.lastSeenSyExchangeRate[0][0].toString() / 1e12
if (rate > 0)
mintRateMap[v.account.mintSy.toString()] = v.account.lastSeenSyExchangeRate[0][0].toString() / 1e12
})
// Fetch mint accounts
const mintPubkeys = Object.keys(mintRateMap).map(k => new PublicKey(k))
const mintAccounts = await connection.getMultipleAccountsInfo(mintPubkeys);
mintAccounts.forEach((a, i) => {
mintAccountMap[mintPubkeys[i].toString()] = a
})
// Fetch Exponent wrapped mints from Exponent API
const { data: mints } = await getConfig('exponent', 'https://xpon-json-api-prod-650968662509.europe-west3.run.app/api/lyt-growth/standard-yield-tokens');
for (let i = 0; i < mints.length; i++) {
const { mintSy, mintUnderlying} = mints[i]
const mintAccount = mintAccountMap[mintSy]
const mintRate = mintRateMap[mintSy]
if (!mintAccount || !mintRate) continue;
// Decode mint data
const decodedMint = decodeAccount('mint', mintAccount);
const supply = decodedMint.supply;
// As all of the Exponent wrapped tokens are yield bearing tokens, mutiply their supply by their redemption rate to get the base asset amount
const amount = supply * mintRate;
// Add to balances using the base asset price * the converted amount of base tokens
api.add(mintUnderlying, amount);
}
}
module.exports = {
timetravel: false,
methodology: "TVL is calculated by summing the total supply of each Exponent wrapped Yield bearing token and multiplying their base asset amount by the price of the underlying token",
solana: { tvl },
};

View File

@@ -34,6 +34,12 @@ function checkType(typeObj) {
if (typeObj.type.kind !== 'struct') return;
typeObj.type.fields.forEach(f => {
const isVec = f.type?.vec?.defined?.name
if (isVec) {
checkType(typeMap[isVec])
return;
}
if (typeof f.type === 'object') {
const tName = f.type.defined?.name
if (tName && typeMap[tName]) checkType(typeMap[tName])