Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
92 changes: 92 additions & 0 deletions projects/helper/kaching-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const sdk = require('@defillama/sdk');
const { function_view } = require('../helper/chain/aptos');

const MODULE_ADDRESS = "0x7d0edbf4a540fc8421e3dbabf221d291217718859814220684c378e8c69da31d";
const MICRO_UNIT = 1_000_000;

async function getTreasuryDetails() {
try {
const res = await function_view({
functionStr: `${MODULE_ADDRESS}::lotto_pots::get_treasury_details`,
type_arguments: [],
args: []
});

const vault = res?.vault_balance ?? res?.[0]?.vault_balance ?? res?.[0] ?? "0";
return BigInt(vault.toString());
} catch (e) {
sdk.log("Error fetching treasury:", e.message);
return 0n;
}
}

async function getPotListPaged(start, size) {
try {
const res = await function_view({
functionStr: `${MODULE_ADDRESS}::lotto_pots::get_pot_list_paged`,
type_arguments: [],
args: [String(start), String(size)] // ensure strings
});

const pots = Array.isArray(res) ? res : (res?.[0] || []);

return pots.map(row => ({
status: mapStatus(Number(row.status)),
prizePool: BigInt(row.prize_pool?.toString() || "0")
}));
} catch (e) {
sdk.log(`Error fetching pots (start=${start}):`, e.message);
return [];
}
}

function mapStatus(code) {
const map = {
1: 'ACTIVE',
2: 'PAUSED',
3: 'DRAWN',
4: 'CANCELLED',
5: 'COMPLETED',
6: 'CANCELLATION_IN_PROGRESS',
7: 'WINNER_ANNOUNCEMENT_IN_PROGRESS'
};
return map[code] || 'UNKNOWN';
}

async function getActivePotsTotalBalance() {
let total = 0n;
let index = 0;
const page = 50;

while (true) {
const pots = await getPotListPaged(index, page);
if (pots.length === 0) break;

for (const pot of pots) {
if (pot.status === "ACTIVE" || pot.status === "PAUSED") {
total += pot.prizePool;
}
}

if (pots.length < page) break;
index += page;
}

return total;
}

// ===== MAIN TVL FUNCTION (returns number, not object) =====
async function aptosTVL() {
try {
const treasury = await getTreasuryDetails();
const activePots = await getActivePotsTotalBalance();
const totalMicro = treasury + activePots;
const totalUSD = Number(totalMicro) / MICRO_UNIT;

return totalUSD;
} catch (err) {
return 0;
}
}

module.exports = { aptosTVL };
22 changes: 22 additions & 0 deletions projects/kaching/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const { aptosTVL } = require('../helper/kaching-helper.js');

async function tvl() {
try {
const totalUsdc = await aptosTVL();
if (isNaN(totalUsdc) || totalUsdc < 0) return {};

return {
'aptos:0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC':
Math.floor(totalUsdc * 1e6)
};
} catch (e) {
console.error('Error computing TVL:', e);
return {};
}
}

module.exports = {
methodology:
"Kaching! allows users to pay using any supported token across supported chains. Kaching! payment abstraction layer swaps and bridges these tokens into USDC on Aptos, which powers the pot size, winnings, and payouts. TVL reflects the total USDC held in the protocol's smart contracts, including active lottery pot balances and treasury reserves used for prize payouts.",
aptos: { tvl }
};
Loading