diff --git a/fees/pyth-express/index.ts b/fees/pyth-express/index.ts new file mode 100644 index 0000000000..1161457771 --- /dev/null +++ b/fees/pyth-express/index.ts @@ -0,0 +1,35 @@ +import { Dependencies, FetchOptions, SimpleAdapter } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; +import { getSolanaReceivedDune } from "../../helpers/token"; + +// Express Relay DAO fee collection address +// Collects both SOL and USDC from MEV auctions +const EXPRESS_RELAY_DAO_ADDRESS = "69ib85nGQS2Hzr4tQ8twbkGh76gKFUfWJFeJfQ37R3hW"; + +const fetch = async (_a: any, _b: any, options: FetchOptions) => { + // Track all tokens (SOL and USDC) received by the DAO address + const dailyFees = await getSolanaReceivedDune({ + options, + target: EXPRESS_RELAY_DAO_ADDRESS, + }); + + return { + dailyFees, + dailyRevenue: dailyFees, // All fees go to DAO as revenue + }; +}; + +const adapter: SimpleAdapter = { + version: 1, + fetch, + chains: [CHAIN.SOLANA], + start: "2025-01-01", + dependencies: [Dependencies.DUNE], + isExpensiveAdapter: true, + methodology: { + Fees: "Fees collected from Express Relay MEV auctions (SOL and USDC)", + Revenue: "All auction fees accrue to the Pyth DAO", + }, +}; + +export default adapter; diff --git a/fees/pyth-network/index.ts b/fees/pyth-network/index.ts new file mode 100644 index 0000000000..24afa81dd1 --- /dev/null +++ b/fees/pyth-network/index.ts @@ -0,0 +1,459 @@ +import { CHAIN } from "../../helpers/chains"; +import { + Dependencies, + FetchOptions, + SimpleAdapter, + FetchResult, +} from "../../adapters/types"; +import { getSolanaReceivedDune } from "../../helpers/token"; +import { queryAllium } from "../../helpers/allium"; + +// ============ EVM Chain Config ============ +const evmChainConfig: Record = { + [CHAIN.OG]: { + start: "2024-06-01", + contract: "0x2880ab155794e7179c9ee2e38200202908c17b43", + }, + [CHAIN.ETHEREUM]: { + start: "2023-07-01", + contract: "0x4305FB66699C3B2702D4d05CF36551390A4c69C6", + }, + [CHAIN.AVAX]: { + start: "2023-07-01", + contract: "0x4305FB66699C3B2702D4d05CF36551390A4c69C6", + }, + [CHAIN.BSC]: { + start: "2023-07-01", + contract: "0x4D7E825f80bDf85e913E0DD2A2D54927e9dE1594", + }, + [CHAIN.POLYGON]: { + start: "2023-07-01", + contract: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C", + }, + [CHAIN.CELO]: { + start: "2023-07-01", + contract: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C", + }, + [CHAIN.XDAI]: { + start: "2023-07-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.AURORA]: { + start: "2023-07-01", + contract: "0xF89C7b475821EC3fDC2dC8099032c05c6c0c9AB9", + }, + [CHAIN.KAVA]: { + start: "2023-07-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.CRONOS]: { + start: "2023-07-01", + contract: "0xE0d0e68297772Dd5a1f1D99897c581E2082dbA5B", + }, + [CHAIN.CONFLUX]: { + start: "2023-07-01", + contract: "0xe9d69CdD6Fe41e7B621B4A688C5D1a68cB5c8ADc", + }, + [CHAIN.METER]: { + start: "2023-07-01", + contract: "0xbFe3f445653f2136b2FD1e6DdDb5676392E3AF16", + }, + [CHAIN.WEMIX]: { + start: "2023-07-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.KLAYTN]: { + start: "2023-07-01", + contract: "0x2880ab155794e7179c9ee2e38200202908c17b43", + }, + [CHAIN.HEDERA]: { + start: "2023-07-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.BITTORRENT]: { + start: "2023-07-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.CORE]: { + start: "2023-07-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.KCC]: { + start: "2023-07-01", + contract: "0xE0d0e68297772Dd5a1f1D99897c581E2082dbA5B", + }, + [CHAIN.FLOW]: { + start: "2023-10-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.FILECOIN]: { + start: "2024-03-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.ARBITRUM]: { + start: "2023-07-01", + contract: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C", + }, + [CHAIN.OPTIMISM]: { + start: "2023-07-01", + contract: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C", + }, + [CHAIN.BASE]: { + start: "2023-08-01", + contract: "0x8250f4aF4B972684F7b336503E2D6dFeDeB1487a", + }, + [CHAIN.BLAST]: { + start: "2024-02-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.LINEA]: { + start: "2023-08-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.MANTLE]: { + start: "2023-08-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.SCROLL]: { + start: "2023-10-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.MANTA]: { + start: "2024-01-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.MODE]: { + start: "2024-01-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.ERA]: { + start: "2023-08-01", + contract: "0xf087c864AEccFb6A2Bf1Af6A0382B0d0f6c5D834", + }, + [CHAIN.POLYGON_ZKEVM]: { + start: "2023-07-01", + contract: "0xC5E56d6b40F3e3B5fbfa266bCd35C37426537c65", + }, + [CHAIN.OP_BNB]: { + start: "2023-09-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.BOBA]: { + start: "2023-07-01", + contract: "0x4374e5a8b9C22271E9EB878A2AA31DE97DF15DAF", + }, + [CHAIN.NEON]: { + start: "2023-09-01", + contract: "0x7f2dB085eFC3560AFF33865dD727225d91B4f9A5", + }, + [CHAIN.SHIMMER_EVM]: { + start: "2023-10-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.RONIN]: { + start: "2024-01-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.LIGHTLINK_PHOENIX]: { + start: "2024-01-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.ETHERLINK]: { + start: "2024-06-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.POLYNOMIAL]: { + start: "2024-01-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.ZETA]: { + start: "2024-01-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.MERLIN]: { + start: "2024-04-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.CHILIZ]: { + start: "2024-03-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.BERACHAIN]: { + start: "2025-01-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.SONIC]: { + start: "2024-12-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.ABSTRACT]: { + start: "2024-11-01", + contract: "0x8739d5024B5143278E2b15Bd9e7C26f6CEc658F1", + }, + [CHAIN.APECHAIN]: { + start: "2024-10-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.UNICHAIN]: { + start: "2024-11-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.HYPERLIQUID]: { + start: "2024-12-01", + contract: "0xe9d69CdD6Fe41e7B621B4A688C5D1a68cB5c8ADc", + }, + [CHAIN.SONEIUM]: { + start: "2025-01-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.WC]: { + start: "2024-10-01", + contract: "0xe9d69cdd6fe41e7b621b4a688c5d1a68cb5c8adc", + }, + [CHAIN.INK]: { + start: "2024-12-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.GRAVITY]: { + start: "2024-06-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.MORPH]: { + start: "2024-10-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.TAIKO]: { + start: "2024-06-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.STORY]: { + start: "2025-01-01", + contract: "0xD458261E832415CFd3BAE5E416FdF3230ce6F134", + }, + [CHAIN.HEMI]: { + start: "2024-10-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.SWELLCHAIN]: { + start: "2024-12-01", + contract: "0xDd24F84d36BF92C65F92307595335bdFab5Bbd21", + }, + [CHAIN.MEZO]: { + start: "2024-09-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.SSEED]: { + start: "2024-12-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.MONAD]: { + start: "2025-01-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.CRONOS_ZKEVM]: { + start: "2024-06-01", + contract: "0x056f829183Ec806A78c26C98961678c24faB71af", + }, + [CHAIN.ZKFAIR]: { + start: "2024-01-01", + contract: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729", + }, + [CHAIN.CAMP]: { + start: "2024-06-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.PLASMA]: { + start: "2024-06-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + [CHAIN.EVENTUM]: { + start: "2024-06-01", + contract: "0x2880aB155794e7179c9eE2e38200202908C17B43", + }, + + // bad rpcs chains + // [CHAIN.SEI]: { start: "2024-01-01", contract: "0x2880aB155794e7179c9eE2e38200202908C17B43" }, + // [CHAIN.IOTA]: { start: "2024-06-01", contract: "0x8D254a21b3C86D32F7179855531CE99164721933" }, + // [CHAIN.INJECTIVE]: { start: "2024-06-01", contract: "0x36825bf3Fbdf5a29E2d5148bfe7Dcf7B5639e320" }, +}; + +// Fee per price feed update by chain (from https://docs.pyth.network/price-feeds/core/current-fees) +const feePerUpdateByChain: Record = { + [CHAIN.AURORA]: 3000000000000n, + [CHAIN.AVAX]: 250000000000000n, + [CHAIN.CONFLUX]: 100000000000000000n, + [CHAIN.CRONOS]: 60000000000000000n, + [CHAIN.METER]: 20000000000000000n, + [CHAIN.OP_BNB]: 186000000000000n, + [CHAIN.RONIN]: 1000000000000000n, + [CHAIN.SEI]: 10000000000000000n, + [CHAIN.SHIMMER_EVM]: 1000000000000000000n, + [CHAIN.SWELLCHAIN]: 50000000000000n, + [CHAIN.WC]: 10000000000000n, +}; + +const DEFAULT_FEE = 1n; +const PRICE_FEED_UPDATE_ABI = + "event PriceFeedUpdate(bytes32 indexed id, uint64 publishTime, int64 price, uint64 conf)"; + +// ============ Non-EVM Chain Config ============ +const SOLANA_FEE_ADDRESS = "8hQfT7SVhkCrzUSgBq6u2wYEt1sH3xmofZ5ss3YaydZW"; +const SUI_FEE_RECIPIENT = + "0x9da043aa51d1c91706d1e95168d9566cd3f9335a568a0a8564750a1e3b7ab891"; +const APTOS_PYTH_CONTRACT = + "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387"; +const NEAR_PYTH_CONTRACT = "pyth-oracle.near"; + +// ============ EVM Fetch Function ============ +async function fetchEvm( + _t: number, + _cb: any, + options: FetchOptions, +): Promise { + const dailyFees = options.createBalances(); + const config = evmChainConfig[options.chain]; + + if (config) { + const updateLogs = await options.getLogs({ + target: config.contract, + eventAbi: PRICE_FEED_UPDATE_ABI, + }); + + const updateCount = updateLogs.length; + const feePerUpdate = feePerUpdateByChain[options.chain] || DEFAULT_FEE; + dailyFees.addGasToken(feePerUpdate * BigInt(updateCount)); + } + + return { + dailyFees, + dailyRevenue: dailyFees, + dailyProtocolRevenue: dailyFees, + }; +} + +// ============ Solana Fetch Function ============ +async function fetchSolana( + _t: number, + _cb: any, + options: FetchOptions, +): Promise { + const dailyFees = await getSolanaReceivedDune({ + options, + target: SOLANA_FEE_ADDRESS, + }); + return { + dailyFees, + dailyRevenue: dailyFees, + dailyProtocolRevenue: dailyFees, + }; +} + +// ============ Sui Fetch Function ============ +const SUI_COIN_TYPE = "0x2::sui::SUI"; + +async function fetchSui( + _t: number, + _cb: any, + options: FetchOptions, +): Promise { + const dailyFees = options.createBalances(); + + const query = ` + SELECT SUM(amount::DOUBLE) AS total_fees + FROM sui.raw.balance_changes + WHERE owner = '${SUI_FEE_RECIPIENT}' + AND coin_type = '${SUI_COIN_TYPE}' + AND amount > 0 + AND checkpoint_timestamp >= TO_TIMESTAMP_NTZ(${options.startTimestamp}) + AND checkpoint_timestamp < TO_TIMESTAMP_NTZ(${options.endTimestamp}) + `; + const res = await queryAllium(query); + if (res[0]?.total_fees) { + dailyFees.addCGToken("sui", res[0].total_fees / 1e9); + } + return { + dailyFees, + dailyRevenue: dailyFees, + dailyProtocolRevenue: dailyFees, + }; +} + +// ============ Aptos Fetch Function ============ +const APTOS_COIN_TYPE = "0x1::aptos_coin::AptosCoin"; + +async function fetchAptos( + _t: number, + _cb: any, + options: FetchOptions, +): Promise { + const dailyFees = options.createBalances(); + + const query = ` + SELECT SUM(amount) AS total_fees + FROM aptos.core.fungible_asset_activities + WHERE owner_address = '${APTOS_PYTH_CONTRACT}' + AND asset_type = '${APTOS_COIN_TYPE}' + AND activity_type = 'deposit' + AND block_timestamp >= TO_TIMESTAMP_NTZ(${options.startTimestamp}) + AND block_timestamp < TO_TIMESTAMP_NTZ(${options.endTimestamp}) + `; + const res = await queryAllium(query); + if (res[0]?.total_fees) { + dailyFees.addCGToken("aptos", res[0].total_fees / 1e8); + } + + return { + dailyFees, + dailyRevenue: dailyFees, + dailyProtocolRevenue: dailyFees, + }; +} + +// ============ Near Fetch Function ============ +async function fetchNear( + _t: number, + _cb: any, + options: FetchOptions, +): Promise { + const dailyFees = options.createBalances(); + const query = ` + SELECT SUM(deposit) AS total_fees + FROM near.raw.receipts + WHERE receiver_id = '${NEAR_PYTH_CONTRACT}' + AND block_timestamp >= TO_TIMESTAMP_NTZ(${options.startTimestamp}) + AND block_timestamp < TO_TIMESTAMP_NTZ(${options.endTimestamp}) + `; + const res = await queryAllium(query); + if (res[0]?.total_fees) { + dailyFees.addCGToken("near", res[0].total_fees / 1e24); + } + return { dailyFees, dailyRevenue: dailyFees }; +} + +// ============ Build Adapter ============ +const evmAdapterEntries = Object.fromEntries( + Object.entries(evmChainConfig).map(([chain, config]) => [ + chain, + { fetch: fetchEvm, start: config.start }, + ]), +); + +const adapter: SimpleAdapter = { + version: 1, + adapter: { + ...evmAdapterEntries, + [CHAIN.SOLANA]: { fetch: fetchSolana, start: "2023-01-01" }, + [CHAIN.SUI]: { fetch: fetchSui, start: "2023-06-01" }, + // [CHAIN.APTOS]: { fetch: fetchAptos, start: "2023-06-01" }, + // [CHAIN.NEAR]: { fetch: fetchNear, start: "2023-06-01" }, + }, + dependencies: [Dependencies.ALLIUM, Dependencies.DUNE], + isExpensiveAdapter: true, + methodology: { + Fees: "Fees paid by users to update Pyth price feeds on-chain", + Revenue: "All update fees accrue to the Pyth protocol", + ProtocolRevenue: "All update fees accrue to the Pyth protocol", + }, +}; + +export default adapter; diff --git a/fees/pyth-pro/index.ts b/fees/pyth-pro/index.ts new file mode 100644 index 0000000000..6960f0ad77 --- /dev/null +++ b/fees/pyth-pro/index.ts @@ -0,0 +1,59 @@ +import { + Dependencies, + FetchOptions, + SimpleAdapter, +} from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; +import ADDRESSES from "../../helpers/coreAssets.json"; +import { queryDuneSql } from "../../helpers/dune"; + +// Douro Labs is the official Pyth Pro data distributor +// They pay 60% of subscription revenue to the Pyth DAO +const DOURO_LABS_ADDRESS = "C6G3jRs1SD7GSNxvKNHJZy7aSar7eZiLioPpDRFFtKTf"; +const PYTH_DAO_ADDRESS = "5Unq3fgfSNdyeGjiq2Pu5XAQUJWo2rauKGErbUyxqUGe"; +const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; + +const fetch = async (_t: any, _a: any, options: FetchOptions) => { + const dailyFees = options.createBalances(); + + // Query USDC transfers from Douro Labs to Pyth DAO + const query = ` + SELECT + SUM(amount) as total_amount + FROM tokens_solana.transfers + WHERE block_time BETWEEN FROM_UNIXTIME(${options.startTimestamp}) AND FROM_UNIXTIME(${options.endTimestamp}) + AND token_mint_address = '${USDC_MINT}' + AND from_owner = '${DOURO_LABS_ADDRESS}' + AND to_owner = '${PYTH_DAO_ADDRESS}' + `; + + const res = await queryDuneSql(options, query); + const amount = res[0]?.total_amount || 0; + + if (amount > 0) { + // USDC has 6 decimals + dailyFees.add(ADDRESSES.solana.USDC, amount); + } + + // Total fees = revenue / 0.6 (since Douro keeps 40%) + // But we only track what reaches the DAO as revenue + return { + dailyFees: dailyFees, // We report received amount as fees + dailyRevenue: dailyFees, + }; +}; + +const adapter: SimpleAdapter = { + version: 1, + fetch, + chains: [CHAIN.SOLANA], + start: "2025-01-01", + dependencies: [Dependencies.DUNE], + methodology: { + Fees: "USDC payments from Douro Labs (Pyth Pro data distributor) to Pyth DAO", + Revenue: + "Pyth DAO receives 60% of Pyth Pro subscription revenue from Douro Labs", + }, +}; + +export default adapter;