Repository: DefiLlama/dimension-adapters Branch: master Commit: 920104dcbd5a Files: 2538 Total size: 7.6 MB Directory structure: gitextract__lkgpfkp/ ├── .coderabbit.yaml ├── .github/ │ ├── CODEOWNERS │ └── workflows/ │ ├── build-modules-and-alert.yml │ ├── comment.yml │ ├── commentResult.js │ ├── getFileList.js │ ├── test-adapter.yml │ └── ts-check.yml ├── .gitignore ├── GUIDELINES.md ├── README.md ├── active-users/ │ ├── aptos.ts │ ├── kyan.ts │ └── sui.ts ├── adapters/ │ ├── types.ts │ └── utils/ │ ├── importAdapter.ts │ └── runAdapter.ts ├── aggregator-derivatives/ │ ├── .gitkeep │ ├── GUIDELINES.md │ ├── defiapp/ │ │ └── index.ts │ ├── flat-money/ │ │ ├── helper.ts │ │ └── index.ts │ ├── flat-money-v1/ │ │ └── index.ts │ ├── flat-money-v2/ │ │ └── index.ts │ ├── kwenta/ │ │ └── index.ts │ ├── mux-protocol-agge.ts │ └── vooi/ │ └── index.ts ├── aggregator-options/ │ ├── GUIDELINES.md │ ├── example.ts │ └── grix/ │ └── index.ts ├── aggregators/ │ ├── 1delta/ │ │ └── index.ts │ ├── 1inch-agg/ │ │ └── index.ts │ ├── 3route/ │ │ └── index.ts │ ├── 8dx-aggregator/ │ │ └── index.ts │ ├── GUIDELINES.md │ ├── aftermath-aggregator/ │ │ └── index.ts │ ├── aggre/ │ │ └── index.ts │ ├── akka/ │ │ └── index.ts │ ├── allox/ │ │ └── index.ts │ ├── anqa/ │ │ └── index.ts │ ├── apstation/ │ │ └── index.ts │ ├── arbitrage-inc/ │ │ └── index.ts │ ├── atmos-aggregator.ts │ ├── aura-agg/ │ │ └── index.ts │ ├── avnu/ │ │ └── index.ts │ ├── barter/ │ │ └── index.ts │ ├── bebop/ │ │ ├── index.ts │ │ └── jamAbi.ts │ ├── bim/ │ │ ├── config.ts │ │ └── index.ts │ ├── binancewallet/ │ │ └── index.ts │ ├── bitgetwallet/ │ │ └── index.ts │ ├── bluefin7k-aggregator/ │ │ └── index.ts │ ├── bountive/ │ │ └── index.ts │ ├── bungee-dex.ts │ ├── bytzz/ │ │ └── index.ts │ ├── carina-aggregator/ │ │ └── index.ts │ ├── cetus-aggregator/ │ │ └── index.ts │ ├── chainspot/ │ │ └── index.ts │ ├── chimpx/ │ │ └── index.ts │ ├── conveyor/ │ │ └── index.ts │ ├── cowswap/ │ │ └── index.ts │ ├── cro-ag/ │ │ └── index.ts │ ├── dedust/ │ │ └── index.ts │ ├── defiapp/ │ │ └── index.ts │ ├── deluthium/ │ │ └── index.ts │ ├── dexhunter/ │ │ └── index.ts │ ├── dexr/ │ │ └── index.ts │ ├── dflow/ │ │ └── index.ts │ ├── dirol/ │ │ └── index.ts │ ├── dodo-agg/ │ │ └── index.ts │ ├── durianfun/ │ │ └── index.ts │ ├── dzap/ │ │ └── index.ts │ ├── eisen/ │ │ └── index.ts │ ├── enso/ │ │ └── index.ts │ ├── erc-burner/ │ │ └── index.ts │ ├── etaswap/ │ │ └── index.ts │ ├── fibrous-finance/ │ │ └── index.ts │ ├── flowx-aggregator/ │ │ └── index.ts │ ├── fluxa/ │ │ └── index.ts │ ├── gluex-protocol/ │ │ └── index.ts │ ├── grelfswap/ │ │ └── index.ts │ ├── groypfi/ │ │ └── index.ts │ ├── haiku/ │ │ └── index.ts │ ├── hallswap/ │ │ └── index.ts │ ├── hinkal/ │ │ └── index.ts │ ├── holdstation-agg/ │ │ └── index.ts │ ├── houdiniswap/ │ │ └── index.ts │ ├── hyperbloom/ │ │ └── index.ts │ ├── hyperflow/ │ │ └── index.ts │ ├── injex/ │ │ └── index.ts │ ├── inoswap/ │ │ └── index.ts │ ├── jeton/ │ │ └── index.ts │ ├── joe-agg/ │ │ └── index.ts │ ├── jumper-exchange/ │ │ └── index.ts │ ├── jupiter-aggregator/ │ │ └── index.ts │ ├── kame-aggregator/ │ │ └── index.ts │ ├── kanalabs/ │ │ └── index.ts │ ├── kuru/ │ │ └── index.ts │ ├── kyberswap/ │ │ └── index.ts │ ├── kyoag/ │ │ └── index.ts │ ├── lamboo/ │ │ └── index.ts │ ├── lifi/ │ │ └── index.ts │ ├── lilswap/ │ │ └── index.ts │ ├── liquidmesh/ │ │ └── index.ts │ ├── liquidswap/ │ │ └── index.ts │ ├── llamaswap/ │ │ └── index.ts │ ├── lunar-finance/ │ │ └── index.ts │ ├── madhouse/ │ │ └── index.ts │ ├── magpie/ │ │ └── index.ts │ ├── metamask.ts │ ├── mimboku-aggregator/ │ │ └── index.ts │ ├── minswap/ │ │ └── index.ts │ ├── monbridgedex/ │ │ └── index.ts │ ├── monorail.ts │ ├── mosaic/ │ │ └── index.ts │ ├── nanoport/ │ │ └── index.ts │ ├── navi/ │ │ └── index.ts │ ├── neptune-swap/ │ │ └── index.ts │ ├── nordstern-finance/ │ │ └── index.ts │ ├── obsidian/ │ │ └── index.ts │ ├── odos/ │ │ └── index.ts │ ├── okx/ │ │ └── index.ts │ ├── oogabooga/ │ │ └── index.ts │ ├── ooia/ │ │ └── index.ts │ ├── openocean/ │ │ └── index.ts │ ├── opensea/ │ │ └── index.ts │ ├── opt-agg/ │ │ └── index.ts │ ├── orbiter-finance/ │ │ └── index.ts │ ├── paraswap/ │ │ └── index.ts │ ├── rainbow-swap/ │ │ └── index.ts │ ├── rango/ │ │ └── index.ts │ ├── rheon/ │ │ └── index.ts │ ├── rubic/ │ │ └── index.ts │ ├── scallop/ │ │ └── index.ts │ ├── stackit/ │ │ └── index.ts │ ├── superboring/ │ │ └── index.ts │ ├── superswap/ │ │ └── index.ts │ ├── sushiswap-agg.ts │ ├── swap-coffee/ │ │ └── index.ts │ ├── swapgpt/ │ │ └── index.ts │ ├── swing/ │ │ └── index.ts │ ├── symphony/ │ │ └── index.ts │ ├── tephra/ │ │ └── index.ts │ ├── tideswap/ │ │ └── index.ts │ ├── titan/ │ │ └── index.ts │ ├── titan-exchange/ │ │ └── index.ts │ ├── tondiamonds/ │ │ └── index.ts │ ├── udex-agg/ │ │ └── index.ts │ ├── unizen/ │ │ └── index.ts │ ├── venum/ │ │ └── index.ts │ ├── vetrade/ │ │ └── index.ts │ ├── virtus/ │ │ └── index.ts │ ├── wolfswap/ │ │ └── index.ts │ ├── wowmax/ │ │ └── index.ts │ ├── yield-yak/ │ │ └── index.ts │ └── zrx/ │ └── index.ts ├── bridge-aggregators/ │ ├── GUIDELINES.md │ ├── babydoge-bridge/ │ │ └── index.ts │ ├── bim/ │ │ └── index.ts │ ├── bitgetwallet/ │ │ └── index.ts │ ├── brotocol/ │ │ └── index.ts │ ├── bungee-bridge/ │ │ └── index.ts │ ├── dzap/ │ │ └── index.ts │ ├── garden/ │ │ └── index.ts │ ├── jumper.exchange/ │ │ └── index.ts │ ├── lifi/ │ │ └── index.ts │ ├── lunar-finance-bridge/ │ │ └── index.ts │ ├── mynth/ │ │ └── index.ts │ ├── okx/ │ │ └── index.ts │ ├── opensea/ │ │ └── index.ts │ ├── orbiter-finance/ │ │ └── index.ts │ ├── rango/ │ │ └── index.ts │ ├── rubic/ │ │ └── index.ts │ ├── sharpe-bridge/ │ │ └── index.ts │ ├── socket/ │ │ ├── contracts.ts │ │ └── index.ts │ ├── stableflow/ │ │ └── index.ts │ ├── swing/ │ │ └── index.ts │ ├── virtus/ │ │ └── index.ts │ └── xy-finance/ │ └── index.ts ├── cli/ │ ├── buildModules.ts │ ├── compareModules.js │ ├── interactive.js │ ├── migrateDeadProjects.ts │ ├── moduleStats.js │ ├── testAdapter.ts │ └── utils.ts ├── dexs/ │ ├── 0x-limit.ts │ ├── 0x-otc.ts │ ├── 0x-rfq.ts │ ├── 10kswap/ │ │ └── index.ts │ ├── 1776meme/ │ │ └── index.ts │ ├── 1dex/ │ │ └── index.ts │ ├── 4swap/ │ │ └── index.ts │ ├── ArbitrumExchange-v2.ts │ ├── ArbitrumExchange-v3.ts │ ├── FeeFree/ │ │ └── index.ts │ ├── GUIDELINES.md │ ├── ICDex/ │ │ └── index.ts │ ├── MantisSwap/ │ │ └── index.ts │ ├── Scopuly/ │ │ └── index.ts │ ├── SecuredFinance/ │ │ └── index.ts │ ├── SmarDex/ │ │ ├── abis.ts │ │ ├── config.ts │ │ ├── index.ts │ │ └── usdn-volume.ts │ ├── SubstanceX/ │ │ └── index.ts │ ├── aark/ │ │ └── index.ts │ ├── aborean/ │ │ ├── index.ts │ │ └── utils.ts │ ├── aborean-cl/ │ │ └── index.ts │ ├── acala-swap/ │ │ └── index.ts │ ├── adrena/ │ │ └── index.ts │ ├── aerodrome/ │ │ ├── index.ts │ │ └── utils.ts │ ├── aerodrome-slipstream/ │ │ └── index.ts │ ├── aevo/ │ │ └── index.ts │ ├── aftermath-fi-amm/ │ │ └── index.ts │ ├── aftermath-fi-perp/ │ │ └── index.ts │ ├── agdex/ │ │ └── index.ts │ ├── airswap/ │ │ └── index.ts │ ├── alex/ │ │ └── index.ts │ ├── allbridge-classic/ │ │ └── index.ts │ ├── alpha-arcade/ │ │ └── index.ts │ ├── alphaq/ │ │ └── index.ts │ ├── alphasec-spot.ts │ ├── alphix.ts │ ├── althea-dex.ts │ ├── ambient/ │ │ └── index.ts │ ├── amigo.ts │ ├── amped-derivatives.ts │ ├── amped-swap.ts │ ├── angstrom/ │ │ ├── helper/ │ │ │ ├── asset.ts │ │ │ ├── binaryDecoder.ts │ │ │ ├── index.ts │ │ │ ├── pair.ts │ │ │ ├── pool.ts │ │ │ ├── type/ │ │ │ │ └── type.ts │ │ │ └── utils.ts │ │ └── index.ts │ ├── anome/ │ │ └── index.ts │ ├── antarctic/ │ │ └── index.ts │ ├── anyhedge/ │ │ └── index.ts │ ├── ape-church/ │ │ └── index.ts │ ├── apestore/ │ │ └── index.ts │ ├── apex-omni/ │ │ └── index.ts │ ├── apollox/ │ │ └── index.ts │ ├── aptos-caliber-prop-amm/ │ │ └── index.ts │ ├── aqua-network/ │ │ └── index.ts │ ├── arctic/ │ │ └── index.ts │ ├── arena-launch.ts │ ├── ash-perp/ │ │ └── index.ts │ ├── ashswap/ │ │ └── index.ts │ ├── aster-spot.ts │ ├── astro-perp.ts │ ├── astrolescent/ │ │ └── index.ts │ ├── astroport-v2/ │ │ └── index.ts │ ├── atmos-dex/ │ │ └── index.ts │ ├── atmos-studio.ts │ ├── aux-exchange/ │ │ └── index.ts │ ├── avantis/ │ │ └── index.ts │ ├── axial/ │ │ └── index.ts │ ├── b402/ │ │ └── index.ts │ ├── babydoge-algebra.ts │ ├── balanced/ │ │ └── index.ts │ ├── balancer-v1.ts │ ├── balancer-v2.ts │ ├── balancer-v3/ │ │ └── index.ts │ ├── bancor-v2_1.ts │ ├── bancor-v3.ts │ ├── barterswap/ │ │ └── index.ts │ ├── baryon/ │ │ └── index.ts │ ├── baseswap-v2.ts │ ├── baseswap-v3.ts │ ├── basin/ │ │ ├── helper.ts │ │ └── index.ts │ ├── beamex-beamex-perps.ts │ ├── beamex-beamex-swap.ts │ ├── beamswap-classic.ts │ ├── beamswap-stable-amm.ts │ ├── bean-exchange/ │ │ └── index.ts │ ├── beethoven-x/ │ │ └── index.ts │ ├── beets-v3/ │ │ └── index.ts │ ├── beezie.ts │ ├── believe/ │ │ └── index.ts │ ├── betterswap/ │ │ └── index.ts │ ├── bifrost-dex.ts │ ├── bigpump/ │ │ └── index.ts │ ├── bisonfi/ │ │ └── index.ts │ ├── bisq/ │ │ └── index.ts │ ├── bitcoin-bridge/ │ │ └── index.ts │ ├── bitflow-fi.ts │ ├── bitflux/ │ │ └── index.ts │ ├── bitget-wallet-card.ts │ ├── bitkeep/ │ │ └── index.ts │ ├── blackhole-CL.ts │ ├── blackhole.ts │ ├── bladeswap-v2.ts │ ├── blastfutures/ │ │ └── index.ts │ ├── blex-derivatives.ts │ ├── blex-volume.ts │ ├── bluefin/ │ │ └── index.ts │ ├── bluefin-amm/ │ │ └── index.ts │ ├── bluefin-pro/ │ │ └── index.ts │ ├── bluemove.ts │ ├── blum/ │ │ └── index.ts │ ├── blur.ts │ ├── bmx-derivatives.ts │ ├── bmx-freestyle/ │ │ └── index.ts │ ├── bmx-swap.ts │ ├── bogged-finance/ │ │ └── index.ts │ ├── boop-fun/ │ │ └── index.ts │ ├── boros/ │ │ └── index.ts │ ├── bounce-tech.ts │ ├── brine/ │ │ └── index.ts │ ├── brownfi/ │ │ └── index.ts │ ├── bsx/ │ │ └── index.ts │ ├── bulbaswap-v2.ts │ ├── bulbaswap-v3.ts │ ├── bullaexchange/ │ │ └── index.ts │ ├── bullbit-ai/ │ │ └── index.ts │ ├── bullbit-perp-dex/ │ │ └── index.ts │ ├── bullet-perp/ │ │ └── index.ts │ ├── bunni-v2.ts │ ├── byreal/ │ │ └── index.ts │ ├── c3-exchange/ │ │ └── index.ts │ ├── cables/ │ │ └── index.ts │ ├── camelot-v3/ │ │ └── index.ts │ ├── canonic/ │ │ └── index.ts │ ├── cap-finance-v4.ts │ ├── capybara-exchange/ │ │ └── index.ts │ ├── capybara-perp/ │ │ └── index.ts │ ├── carbon/ │ │ └── index.ts │ ├── carbondefi/ │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── carthage-v3.ts │ ├── catalist-dex/ │ │ └── index.ts │ ├── catton/ │ │ └── index.ts │ ├── cauldron/ │ │ └── index.ts │ ├── caviarnine-agg.ts │ ├── caviarnine-lsu-pool/ │ │ └── index.ts │ ├── caviarnine-orderbook.ts │ ├── caviarnine-simplepool.ts │ ├── cellana-finance/ │ │ └── index.ts │ ├── cetus/ │ │ └── index.ts │ ├── cetus-dlmm/ │ │ └── index.ts │ ├── chainflip/ │ │ └── index.ts │ ├── chainge-finance/ │ │ └── index.ts │ ├── challenge4trading-perp.ts │ ├── chapool.ts │ ├── cherryswap/ │ │ └── index.ts │ ├── citrex-markets/ │ │ └── index.ts │ ├── claimswap/ │ │ └── index.ts │ ├── clipper/ │ │ └── index.ts │ ├── clob/ │ │ └── index.ts │ ├── clober-v2/ │ │ └── index.ts │ ├── cobaltx.ts │ ├── coinhain/ │ │ └── index.ts │ ├── colorpool.ts │ ├── concordex-io/ │ │ └── index.ts │ ├── contango/ │ │ └── index.ts │ ├── copump.ts │ ├── core-markets/ │ │ └── index.ts │ ├── corex/ │ │ └── index.ts │ ├── crema-finance/ │ │ └── index.ts │ ├── cube/ │ │ └── index.ts │ ├── curve/ │ │ ├── api.ts │ │ └── index.ts │ ├── cvex/ │ │ └── index.ts │ ├── cyberperp/ │ │ ├── cyberperp.ts │ │ └── index.ts │ ├── d8x/ │ │ └── index.ts │ ├── dackieswap/ │ │ └── index.ts │ ├── dango/ │ │ └── index.ts │ ├── danogo/ │ │ ├── index.ts │ │ └── types.ts │ ├── dappos-intentEx/ │ │ └── index.ts │ ├── decibel/ │ │ └── index.ts │ ├── dedust/ │ │ └── index.ts │ ├── deepbookv3-sui/ │ │ └── index.ts │ ├── deeptrade/ │ │ └── index.ts │ ├── defibox/ │ │ └── index.ts │ ├── defichain-dex/ │ │ └── index.ts │ ├── defiplaza/ │ │ └── index.ts │ ├── degen-launchpad/ │ │ └── index.ts │ ├── delphi/ │ │ └── index.ts │ ├── delta-trade/ │ │ └── index.ts │ ├── deltadefi/ │ │ └── index.ts │ ├── demex-demex-perp.ts │ ├── demex-demex.ts │ ├── denaria.ts │ ├── derivio-derivatives.ts │ ├── derivio-swap.ts │ ├── desk/ │ │ └── index.ts │ ├── dexalot/ │ │ └── index.ts │ ├── dexswap/ │ │ └── index.ts │ ├── dexter/ │ │ ├── constants.ts │ │ ├── dimensions.ts │ │ └── index.ts │ ├── dexter-tezos/ │ │ └── index.ts │ ├── dextrabot.ts │ ├── dflow-prediction/ │ │ └── index.ts │ ├── dinari/ │ │ └── index.ts │ ├── dipcoin-perps/ │ │ └── index.ts │ ├── dipcoin-spot/ │ │ └── index.ts │ ├── dodo/ │ │ ├── dailyVolumePayload.ts │ │ ├── index.ts │ │ └── totalVolumePayload.ts │ ├── dpex/ │ │ └── index.ts │ ├── dragonswap-sei/ │ │ └── index.ts │ ├── dragonswap-sei-v3/ │ │ └── index.ts │ ├── dragonswap-v2.ts │ ├── dragonswap-v3.ts │ ├── drift-protocol-derivatives.ts │ ├── drift-protocol-swap.ts │ ├── drip-trade.ts │ ├── duality/ │ │ └── index.ts │ ├── durian-amm/ │ │ └── index.ts │ ├── durianfun-launchpad/ │ │ └── index.ts │ ├── dusa/ │ │ └── index.ts │ ├── dx25/ │ │ └── index.ts │ ├── dydx-v4/ │ │ └── index.ts │ ├── dyorswap-launchpad/ │ │ └── index.ts │ ├── e3/ │ │ └── index.ts │ ├── eaglefi.ts │ ├── earnium/ │ │ └── index.ts │ ├── econia/ │ │ └── index.ts │ ├── edgeX/ │ │ └── index.ts │ ├── egas-swap/ │ │ └── index.ts │ ├── ekubo/ │ │ └── index.ts │ ├── ekubo-evm.ts │ ├── electra/ │ │ └── index.ts │ ├── elektrik/ │ │ └── index.ts │ ├── elexium/ │ │ └── index.ts │ ├── elfi/ │ │ └── index.ts │ ├── elfomofi/ │ │ └── index.ts │ ├── elix-fi/ │ │ └── index.ts │ ├── elys-dex.ts │ ├── elys-perp.ts │ ├── emdx/ │ │ └── index.ts │ ├── equity-spot/ │ │ └── index.ts │ ├── ethereal-dex/ │ │ └── index.ts │ ├── etherex-legacy.ts │ ├── etherex.ts │ ├── eulerswap/ │ │ └── index.ts │ ├── evedex/ │ │ └── index.ts │ ├── evently/ │ │ └── index.ts │ ├── exa-card.ts │ ├── exinswap/ │ │ └── index.ts │ ├── extended/ │ │ └── index.ts │ ├── farmcats-market/ │ │ └── index.ts │ ├── fastjpeg/ │ │ └── index.ts │ ├── fermi-dex/ │ │ └── index.ts │ ├── ferra-clmm/ │ │ └── index.ts │ ├── ferra-dlmm/ │ │ └── index.ts │ ├── ferro/ │ │ └── index.ts │ ├── figure-markets/ │ │ └── index.ts │ ├── fjord-foundry-v1.ts │ ├── fjord-foundry-v2.ts │ ├── flamingo-finance/ │ │ └── index.ts │ ├── flashnet/ │ │ └── index.ts │ ├── flashtrade/ │ │ └── index.ts │ ├── flexperp/ │ │ └── index.ts │ ├── flowbot-perps.ts │ ├── flowx-finance/ │ │ └── index.ts │ ├── flowx-perps/ │ │ └── index.ts │ ├── flowx-v3/ │ │ └── index.ts │ ├── fluid-dex/ │ │ └── index.ts │ ├── fluid-dex-lite/ │ │ └── index.ts │ ├── four-meme/ │ │ └── index.ts │ ├── foxify/ │ │ └── index.ts │ ├── frax-swap/ │ │ └── index.ts │ ├── friend-tech.ts │ ├── fulcrom-finance-derivatives.ts │ ├── fulcrom-finance-swap.ts │ ├── fullsail-finance/ │ │ └── index.ts │ ├── futarchy-amm/ │ │ └── index.ts │ ├── fvm-exchange/ │ │ └── index.ts │ ├── fwogfun/ │ │ └── index.ts │ ├── fwx/ │ │ └── index.ts │ ├── gains-network/ │ │ └── index.ts │ ├── galaswap-v3.ts │ ├── gambit/ │ │ └── index.ts │ ├── garuda-defi/ │ │ └── index.ts │ ├── gaspump/ │ │ └── index.ts │ ├── gate-perps.ts │ ├── gatefun/ │ │ └── index.ts │ ├── genius-protocol/ │ │ └── index.ts │ ├── glowswap/ │ │ └── index.ts │ ├── glyph-exchange/ │ │ └── index.ts │ ├── gmx-derivatives.ts │ ├── gmx-sol.ts │ ├── gmx-v2-gmx-v2-swap.ts │ ├── gmx-v2-gmx-v2-trade.ts │ ├── gnosispay.ts │ ├── goosefx/ │ │ └── index.ts │ ├── goosefx_v2/ │ │ └── index.ts │ ├── grafun.ts │ ├── grizzly-trade-derivatives-v2/ │ │ └── index.ts │ ├── grvt-perps/ │ │ └── index.ts │ ├── haedal/ │ │ └── index.ts │ ├── hanji/ │ │ └── index.ts │ ├── hashflow/ │ │ └── index.ts │ ├── hashlock-markets/ │ │ ├── ethereum.ts │ │ ├── index.ts │ │ ├── shared.ts │ │ └── sui.ts │ ├── haven1-hswap/ │ │ └── index.ts │ ├── hbarsuite-dex/ │ │ └── index.ts │ ├── heaven-dex/ │ │ └── index.ts │ ├── heliswap/ │ │ └── index.ts │ ├── helix-helix-perp.ts │ ├── helix-helix.ts │ ├── helix-markets/ │ │ └── index.ts │ ├── hibachi/ │ │ └── index.ts │ ├── hitone/ │ │ └── index.ts │ ├── hmx/ │ │ └── index.ts │ ├── holdr/ │ │ └── index.ts │ ├── holoworld/ │ │ └── index.ts │ ├── honeypop-dex.ts │ ├── horizondex/ │ │ └── index.ts │ ├── hotstuff/ │ │ └── index.ts │ ├── humanfi/ │ │ └── index.ts │ ├── humidifi/ │ │ └── index.ts │ ├── hummus/ │ │ └── index.ts │ ├── hybra-v4.ts │ ├── hydration-dex/ │ │ └── index.ts │ ├── hyperion/ │ │ └── index.ts │ ├── hyperliquid-perp/ │ │ └── index.ts │ ├── hyperliquid-spot/ │ │ └── index.ts │ ├── hyperpie-launchpad.ts │ ├── hyperpie-v2-dex.ts │ ├── hypersignals.ts │ ├── hyperstitions/ │ │ └── index.ts │ ├── hyperswap-v3/ │ │ └── index.ts │ ├── hyperunit/ │ │ └── index.ts │ ├── icpswap/ │ │ └── index.ts │ ├── immortalx/ │ │ └── index.ts │ ├── increment-protocol/ │ │ └── index.ts │ ├── increment-swap/ │ │ └── index.ts │ ├── infinityPools/ │ │ ├── index.ts │ │ ├── quadHelper.ts │ │ └── swapEventABI.ts │ ├── initia-dex.ts │ ├── injective-derivatives.ts │ ├── injective-spot.ts │ ├── integral/ │ │ └── index.ts │ ├── intent-x/ │ │ └── index.ts │ ├── interest-movement-curve/ │ │ └── index.ts │ ├── interest-protocol/ │ │ └── index.ts │ ├── interest-protocol-stable-swap/ │ │ └── index.ts │ ├── invariant/ │ │ └── index.ts │ ├── ipor/ │ │ └── index.ts │ ├── iziswap/ │ │ └── index.ts │ ├── javsphere/ │ │ └── index.ts │ ├── jediswap/ │ │ └── index.ts │ ├── jediswap-v2/ │ │ └── index.ts │ ├── jellyverse/ │ │ └── index.ts │ ├── jojo/ │ │ └── index.ts │ ├── jup-ape/ │ │ └── index.ts │ ├── jupiter-perpetual/ │ │ └── index.ts │ ├── jupiter-prediction/ │ │ └── index.ts │ ├── justbet/ │ │ ├── abis.ts │ │ ├── constants.ts │ │ ├── helpers.ts │ │ └── index.ts │ ├── k-bit/ │ │ └── index.ts │ ├── kalshi.ts │ ├── kanalabs-perp/ │ │ └── index.ts │ ├── karura-swap/ │ │ └── index.ts │ ├── kaspacom-dex/ │ │ └── index.ts │ ├── kast-card.ts │ ├── katana-perps.ts │ ├── katana-v3/ │ │ └── index.ts │ ├── kava-swap/ │ │ └── index.ts │ ├── kensei/ │ │ └── index.ts │ ├── kiloex/ │ │ └── index.ts │ ├── kinetiq-markets.ts │ ├── kinetix-v3/ │ │ └── index.ts │ ├── kittenswap/ │ │ └── index.ts │ ├── kittenswap-algebra/ │ │ └── index.ts │ ├── kittenswap-cl/ │ │ └── index.ts │ ├── kittypunch-stable.ts │ ├── klayswap/ │ │ └── index.ts │ ├── kodiak-v3.ts │ ├── kokonut-swap/ │ │ └── index.ts │ ├── kongswap/ │ │ └── index.ts │ ├── kriya-clmm/ │ │ └── index.ts │ ├── kriya-dex/ │ │ └── index.ts │ ├── ktx-derivatives.ts │ ├── ktx-swap.ts │ ├── kuma-v1/ │ │ └── index.ts │ ├── kuru-clob.ts │ ├── kyan.ts │ ├── kyex/ │ │ └── index.ts │ ├── kyo-fi-v3.ts │ ├── landbid.ts │ ├── legion.ts │ ├── levana/ │ │ ├── fetch.ts │ │ └── index.ts │ ├── level-finance-level-finance-derivative.ts │ ├── level-finance-level-finance.ts │ ├── leverup/ │ │ └── index.ts │ ├── lexer-derivatives.ts │ ├── lexer-swap.ts │ ├── lighter-spot/ │ │ └── index.ts │ ├── lighterv2/ │ │ └── index.ts │ ├── limitless-exchange/ │ │ └── index.ts │ ├── linehub-perps/ │ │ └── index.ts │ ├── liquidcore.ts │ ├── liquidswap/ │ │ └── index.ts │ ├── lista-dex/ │ │ └── index.ts │ ├── lithos/ │ │ └── index.ts │ ├── lnexchange-perp/ │ │ └── index.ts │ ├── lnexchange-spot/ │ │ └── index.ts │ ├── lotto-run/ │ │ └── index.ts │ ├── lotus-finance/ │ │ └── index.ts │ ├── loxodrome-amm/ │ │ └── index.ts │ ├── lumenswap/ │ │ └── index.ts │ ├── luna-fun.ts │ ├── lunarbase/ │ │ └── index.ts │ ├── lyra/ │ │ └── index.ts │ ├── macaron-xyz/ │ │ └── index.ts │ ├── mach/ │ │ ├── deployments.ts │ │ └── index.ts │ ├── machinex-cl.ts │ ├── machinex-legacy.ts │ ├── magicsea-lb/ │ │ └── index.ts │ ├── magma-finance/ │ │ └── index.ts │ ├── mangrove/ │ │ └── index.ts │ ├── manifest-trade/ │ │ └── index.ts │ ├── mars-perp/ │ │ └── index.ts │ ├── maverick/ │ │ ├── index.ts │ │ └── maverick-v1.ts │ ├── maverick-v2/ │ │ └── index.ts │ ├── mcdex/ │ │ └── index.ts │ ├── mdex/ │ │ └── index.ts │ ├── megaton-finance/ │ │ └── index.ts │ ├── mento/ │ │ └── index.ts │ ├── mento-v3/ │ │ └── index.ts │ ├── meridian-trade-derivatives.ts │ ├── meridian-trade-swap.ts │ ├── merkle-trade/ │ │ └── index.ts │ ├── merlinswap/ │ │ └── index.ts │ ├── meshswap/ │ │ └── index.ts │ ├── metamask-card.ts │ ├── metastable-musd/ │ │ └── index.ts │ ├── metavault-derivatives-v2/ │ │ └── index.ts │ ├── metavault_trade-metavault-derivative.ts │ ├── metavault_trade-metavault_trade.ts │ ├── meteora/ │ │ └── index.ts │ ├── meteora-damm-v2/ │ │ └── index.ts │ ├── meteora-dbc/ │ │ └── index.ts │ ├── meteora-dlmm.ts │ ├── metric/ │ │ └── index.ts │ ├── metropolis-amm/ │ │ └── index.ts │ ├── metropolis-dlmm/ │ │ └── index.ts │ ├── minswap/ │ │ └── index.ts │ ├── mintiq-market/ │ │ └── index.ts │ ├── mira-ly/ │ │ └── index.ts │ ├── miracletrade.ts │ ├── mitte/ │ │ └── index.ts │ ├── mobius-money/ │ │ └── index.ts │ ├── momentum.ts │ ├── monday-trade-perp/ │ │ └── index.ts │ ├── moneyx-pro/ │ │ └── index.ts │ ├── monster/ │ │ └── index.ts │ ├── moon-swap/ │ │ └── index.ts │ ├── mooniswap/ │ │ └── index.ts │ ├── moonlander/ │ │ └── index.ts │ ├── mosaic-amm/ │ │ └── index.ts │ ├── mu-exchange/ │ │ └── index.ts │ ├── muesliswap/ │ │ └── index.ts │ ├── multiswap/ │ │ └── index.ts │ ├── mummy-finance/ │ │ └── index.ts │ ├── mux-protocol-perps.ts │ ├── myswap/ │ │ └── index.ts │ ├── myswap-cl/ │ │ └── index.ts │ ├── myx-finance/ │ │ ├── helpers..ts │ │ └── index.ts │ ├── nabla/ │ │ └── index.ts │ ├── nad-fun.ts │ ├── nado-perp/ │ │ └── index.ts │ ├── nado-spot/ │ │ └── index.ts │ ├── napier/ │ │ └── index.ts │ ├── narbet.ts │ ├── narwhal-finance.ts │ ├── native/ │ │ └── index.ts │ ├── near-intents/ │ │ └── index.ts │ ├── neony-perp/ │ │ └── index.ts │ ├── neony-spot/ │ │ └── index.ts │ ├── nest/ │ │ └── index.ts │ ├── ninjablaze/ │ │ └── index.ts │ ├── nlx-nlx-swap.ts │ ├── nlx-nlx-trade.ts │ ├── noah-swap/ │ │ └── index.ts │ ├── nomiswap/ │ │ └── index.ts │ ├── nostra-pools/ │ │ └── index.ts │ ├── o1-exchange/ │ │ └── index.ts │ ├── o2/ │ │ └── index.ts │ ├── ocelex/ │ │ └── index.ts │ ├── ociswap-basic.ts │ ├── ociswap-precision.ts │ ├── okie-launch.ts │ ├── okie-stableswap.ts │ ├── okieswap-v2.ts │ ├── okieswap-v3.ts │ ├── olab/ │ │ └── index.ts │ ├── omni-exchange-flux/ │ │ └── index.ts │ ├── omni-exchange-v2/ │ │ └── index.ts │ ├── omnipair/ │ │ └── index.ts │ ├── ondo-global-markets/ │ │ └── index.ts │ ├── openleverage/ │ │ └── index.ts │ ├── opinion/ │ │ └── index.ts │ ├── optim-finance/ │ │ └── index.ts │ ├── opx-finance/ │ │ └── index.ts │ ├── oraidex/ │ │ └── index.ts │ ├── oraidex-v3/ │ │ └── index.ts │ ├── orbit-finance.ts │ ├── orca/ │ │ └── index.ts │ ├── orca-wavebreak.ts │ ├── orderly-network-orderly-network-derivatives.ts │ ├── orderly-network-orderly-network.ts │ ├── orderly-perps-new.ts │ ├── osmosis/ │ │ └── index.ts │ ├── ostium/ │ │ └── index.ts │ ├── ostrich/ │ │ └── index.ts │ ├── oswap/ │ │ └── index.ts │ ├── otomate.ts │ ├── oxium/ │ │ ├── config.ts │ │ ├── fetch.ts │ │ └── index.ts │ ├── pacaswap.ts │ ├── pacifica/ │ │ └── index.ts │ ├── pact/ │ │ └── index.ts │ ├── paint-swap/ │ │ └── index.ts │ ├── palmswap/ │ │ └── index.ts │ ├── panacakeswap-perp/ │ │ └── index.ts │ ├── pancakeswap-infinity.ts │ ├── pancakeswap-prediction/ │ │ └── index.ts │ ├── pancakeswap-v2.ts │ ├── pancakeswap-v3.ts │ ├── pandora-speed-trading/ │ │ └── index.ts │ ├── pangea-swap/ │ │ └── index.ts │ ├── pangolin-v3/ │ │ └── index.ts │ ├── paradex/ │ │ └── index.ts │ ├── paradex-spot/ │ │ └── index.ts │ ├── paycash/ │ │ └── index.ts │ ├── pear-protocol/ │ │ └── index.ts │ ├── pegasys-v3/ │ │ └── index.ts │ ├── pendle/ │ │ └── index.ts │ ├── penumbra-dex.ts │ ├── pepe-dex/ │ │ └── index.ts │ ├── perennial-v2/ │ │ └── index.ts │ ├── perpl/ │ │ └── index.ts │ ├── pharaoh-v3-legacy.ts │ ├── pharaoh-v3.ts │ ├── pheasantswap/ │ │ └── index.ts │ ├── phoenix/ │ │ └── index.ts │ ├── phoenix-trade/ │ │ └── index.ts │ ├── photon.ts │ ├── pigeonhouse/ │ │ └── index.ts │ ├── pika-protocol/ │ │ └── index.ts │ ├── pika-protocol-v4/ │ │ └── index.ts │ ├── pingu/ │ │ └── index.ts │ ├── pinnako-derivatives.ts │ ├── pinnako-swap.ts │ ├── pinto/ │ │ └── index.ts │ ├── piperx-v2/ │ │ └── index.ts │ ├── piperx-v3/ │ │ └── index.ts │ ├── pixelswap/ │ │ └── index.ts │ ├── pixiechess/ │ │ └── index.ts │ ├── planemo-trading.ts │ ├── platypus/ │ │ └── index.ts │ ├── plenty/ │ │ └── index.ts │ ├── plunderswap/ │ │ └── index.ts │ ├── polkadex/ │ │ └── index.ts │ ├── polkaswap/ │ │ └── index.ts │ ├── polymarket/ │ │ └── index.ts │ ├── polymarket-us/ │ │ └── index.ts │ ├── ponytaswap/ │ │ └── index.ts │ ├── pool-party/ │ │ └── index.ts │ ├── potatoswap-v3.ts │ ├── potatoswap.ts │ ├── predict-fun/ │ │ └── index.ts │ ├── primex-finance/ │ │ ├── index.ts │ │ └── utils.ts │ ├── printr-protocol/ │ │ └── index.ts │ ├── priority-trade/ │ │ └── index.ts │ ├── privex/ │ │ └── index.ts │ ├── probable.ts │ ├── prophet-fun/ │ │ └── index.ts │ ├── proton-dex/ │ │ └── index.ts │ ├── pump-swap/ │ │ └── index.ts │ ├── pumpfun.ts │ ├── pumpspace-v2/ │ │ └── index.ts │ ├── pumpspace-v3/ │ │ └── index.ts │ ├── punk.coffee/ │ │ └── index.ts │ ├── puppyfun/ │ │ └── index.ts │ ├── quenta/ │ │ └── index.ts │ ├── quickswap-hydra/ │ │ └── index.ts │ ├── quickswap-liquidityHub.ts │ ├── quickswap-perps/ │ │ └── index.ts │ ├── quickswap-v2.ts │ ├── quickswap-v3.ts │ ├── quickswap-v4.ts │ ├── quipuswap/ │ │ └── index.ts │ ├── rabbitswap-v3/ │ │ └── index.ts │ ├── rain-one/ │ │ └── index.ts │ ├── raindex/ │ │ └── index.ts │ ├── ramses-hl-cl.ts │ ├── ramses-hl-legacy.ts │ ├── ramsesx-arb-cl.ts │ ├── ramsesx-arb-legacy.ts │ ├── ramsesx-poly-cl.ts │ ├── ramsesx-poly-legacy.ts │ ├── rarible/ │ │ ├── helper.ts │ │ └── index.ts │ ├── rate-x/ │ │ └── index.ts │ ├── raydium/ │ │ └── index.ts │ ├── reactor-exchange/ │ │ └── index.ts │ ├── ready-card.ts │ ├── ref-finance/ │ │ └── index.ts │ ├── renegade-fi/ │ │ └── index.ts │ ├── reya-dex.ts │ ├── rfx-rfx-swap.ts │ ├── rfx-rfx-trade.ts │ ├── rhea-cross-chain/ │ │ └── index.ts │ ├── rho-protocol/ │ │ └── index.ts │ ├── rho-x/ │ │ └── index.ts │ ├── ring-dex.ts │ ├── rise-launchpad.ts │ ├── risex-perps/ │ │ └── index.ts │ ├── rocket/ │ │ └── index.ts │ ├── rollie-finance/ │ │ └── index.ts │ ├── rollx/ │ │ └── index.ts │ ├── rooster/ │ │ └── index.ts │ ├── rubicon/ │ │ └── index.ts │ ├── rush/ │ │ └── index.ts │ ├── ryze/ │ │ └── index.ts │ ├── saber/ │ │ └── index.ts │ ├── saddle-finance/ │ │ └── index.ts │ ├── sai-perps/ │ │ └── index.ts │ ├── sailor-finance.ts │ ├── sanctum/ │ │ └── index.ts │ ├── sanctum-infinity/ │ │ └── index.ts │ ├── sandglass/ │ │ └── index.ts │ ├── saphyre-rfq/ │ │ └── index.ts │ ├── saros/ │ │ └── index.ts │ ├── saros-dlmm.ts │ ├── satori/ │ │ └── index.ts │ ├── saturnswap/ │ │ └── index.ts │ ├── saucerswap/ │ │ └── index.ts │ ├── saucerswap-v2/ │ │ └── index.ts │ ├── secondswap/ │ │ └── index.ts │ ├── sectorone-dlmm-v2/ │ │ └── index.ts │ ├── seer/ │ │ └── index.ts │ ├── seiyan-fun/ │ │ └── index.ts │ ├── shadow-exchange.ts │ ├── shadow-legacy.ts │ ├── sharpe-dex/ │ │ └── index.ts │ ├── shell-protocol/ │ │ ├── constants.ts │ │ ├── helpers.ts │ │ └── index.ts │ ├── shiny/ │ │ └── index.ts │ ├── shroomy-protocol/ │ │ └── index.ts │ ├── silverswap/ │ │ └── index.ts │ ├── simpledex/ │ │ └── index.ts │ ├── sithswap/ │ │ └── index.ts │ ├── skate-amm/ │ │ └── index.ts │ ├── slingshot/ │ │ └── index.ts │ ├── smardex-usdn/ │ │ └── index.ts │ ├── smbswap-v2.ts │ ├── sodex-perps/ │ │ └── index.ts │ ├── sodex-spot/ │ │ └── index.ts │ ├── solar-studios/ │ │ └── index.ts │ ├── solayer-card.ts │ ├── solfi-v2/ │ │ └── index.ts │ ├── solidly-v3/ │ │ └── index.ts │ ├── sologenic/ │ │ └── index.ts │ ├── someswap/ │ │ └── index.ts │ ├── somnex-perps.ts │ ├── somnex-v3.ts │ ├── somnex-xyz.ts │ ├── somnia-exchange.ts │ ├── sonic-market-orderbook/ │ │ └── index.ts │ ├── sour/ │ │ └── index.ts │ ├── spacedex-derivatives.ts │ ├── spacedex-swap.ts │ ├── spacewhale/ │ │ └── index.ts │ ├── spark/ │ │ └── index.ts │ ├── sparkdex-perps/ │ │ └── index.ts │ ├── spartan/ │ │ └── index.ts │ ├── spectra-v2.ts │ ├── spectrum/ │ │ └── index.ts │ ├── spicyswap/ │ │ └── index.ts │ ├── spritz-card.ts │ ├── squaretower.ts │ ├── stabble/ │ │ └── index.ts │ ├── stabble-clmm/ │ │ └── index.ts │ ├── stabull/ │ │ └── index.ts │ ├── standard-mode/ │ │ └── index.ts │ ├── standard-spot/ │ │ └── index.ts │ ├── standx/ │ │ └── index.ts │ ├── starkdefi/ │ │ └── index.ts │ ├── steamm.ts │ ├── stellarx/ │ │ └── index.ts │ ├── stellaswap-v4/ │ │ └── index.ts │ ├── ston/ │ │ └── index.ts │ ├── stormtrade/ │ │ └── index.ts │ ├── storyhunt-v3.ts │ ├── strike-finance/ │ │ └── index.ts │ ├── sudofinance/ │ │ └── index.ts │ ├── sudoswap-v2/ │ │ └── index.ts │ ├── sundaeswap/ │ │ └── index.ts │ ├── sunperp/ │ │ └── index.ts │ ├── sunswap/ │ │ └── index.ts │ ├── sunswap-v2/ │ │ └── index.ts │ ├── sunswap-v3/ │ │ └── index.ts │ ├── supernova-CL.ts │ ├── supernova.ts │ ├── surfswap-classic.ts │ ├── surge-trade/ │ │ └── index.ts │ ├── sushi-aptos/ │ │ └── index.ts │ ├── sushiswap-trident.ts │ ├── sushiswap-v3.ts │ ├── swaap-v1.ts │ ├── swaap-v2.ts │ ├── swap-coffee/ │ │ └── index.ts │ ├── swapbased-perps.ts │ ├── swapbased-v2.ts │ ├── swapbased-v3.ts │ ├── swapline/ │ │ └── index.ts │ ├── swapr-v3/ │ │ └── index.ts │ ├── swaps-io/ │ │ └── index.ts │ ├── swop/ │ │ └── index.ts │ ├── sxbet/ │ │ └── index.ts │ ├── symmetric/ │ │ └── index.ts │ ├── symmio/ │ │ └── index.ts │ ├── syncswap/ │ │ └── index.ts │ ├── synfutures-v1/ │ │ └── index.ts │ ├── synfutures-v2/ │ │ └── index.ts │ ├── synfutures-v3/ │ │ └── index.ts │ ├── synthetify/ │ │ └── index.ts │ ├── synthetix/ │ │ └── index.ts │ ├── synthetix-v3/ │ │ └── index.ts │ ├── synthetix-v4/ │ │ └── index.ts │ ├── taiko-swap.ts │ ├── tangleswap/ │ │ └── index.ts │ ├── tapp-exchange/ │ │ └── index.ts │ ├── tea-fi.ts │ ├── tealswap/ │ │ └── index.ts │ ├── tearex/ │ │ └── index.ts │ ├── teleswap/ │ │ └── index.ts │ ├── tempo-fee-amm.ts │ ├── tempo-stable-dex/ │ │ └── index.ts │ ├── tessera/ │ │ └── index.ts │ ├── testing-please-ignore-2/ │ │ └── index.ts │ ├── thalaswap/ │ │ └── index.ts │ ├── thalaswap-v2/ │ │ └── index.ts │ ├── thalaswap-v3.ts │ ├── thales/ │ │ ├── abis.ts │ │ ├── config.ts │ │ ├── eventArgs.ts │ │ ├── index.ts │ │ └── parsers.ts │ ├── thaw.ts │ ├── thirdfy.ts │ ├── thorchain-dex.ts │ ├── thorswap/ │ │ └── index.ts │ ├── thorwallet/ │ │ └── index.ts │ ├── tigris/ │ │ └── index.ts │ ├── tinyman/ │ │ └── index.ts │ ├── titan/ │ │ └── index.ts │ ├── tlx-finance/ │ │ └── index.ts │ ├── tokenlon-agg.ts │ ├── tokenlon-dex.ts │ ├── tonco/ │ │ └── index.ts │ ├── tonpump/ │ │ └── index.ts │ ├── topstrike/ │ │ └── index.ts │ ├── torch/ │ │ └── index.ts │ ├── toros/ │ │ └── index.ts │ ├── trado/ │ │ └── index.ts │ ├── trado-spot/ │ │ └── index.ts │ ├── tradoor/ │ │ └── index.ts │ ├── treadfi-perps.ts │ ├── tristero/ │ │ └── index.ts │ ├── truemarkets.ts │ ├── ttswap/ │ │ └── index.ts │ ├── turbolev/ │ │ └── index.ts │ ├── turbos/ │ │ └── index.ts │ ├── txflow-perps/ │ │ └── index.ts │ ├── typus-perp/ │ │ └── index.ts │ ├── umbra/ │ │ └── index.ts │ ├── uniderp/ │ │ └── index.ts │ ├── unidex-unidex-dexs-agg.ts │ ├── unidex-unidex.ts │ ├── uniswap-v1.ts │ ├── uniswap-v2.ts │ ├── uniswap-v3.ts │ ├── uniswap-v4.ts │ ├── updown/ │ │ └── index.ts │ ├── upheaval-v3/ │ │ └── index.ts │ ├── upscale/ │ │ └── index.ts │ ├── urdex/ │ │ └── index.ts │ ├── utyabswap/ │ │ └── index.ts │ ├── valantis-stex/ │ │ └── index.ts │ ├── valiant-trade/ │ │ └── index.ts │ ├── vanilla-finance-perps/ │ │ └── index.ts │ ├── vanswap/ │ │ └── index.ts │ ├── vapordex-v1.ts │ ├── vapordex-v2.ts │ ├── variational-omni/ │ │ └── index.ts │ ├── veax/ │ │ └── index.ts │ ├── velar.ts │ ├── velocore-v2/ │ │ └── index.ts │ ├── velodrome-slipstream/ │ │ └── index.ts │ ├── verus.ts │ ├── vest/ │ │ └── index.ts │ ├── vexchange/ │ │ └── index.ts │ ├── vinunft/ │ │ └── index.ts │ ├── vinuswap/ │ │ └── index.ts │ ├── volmex/ │ │ └── index.ts │ ├── volta-markets/ │ │ └── index.ts │ ├── voltswap-v1.ts │ ├── voltswap-v2.ts │ ├── voodoo-trade-derivatives.ts │ ├── voodoo-trade-swap.ts │ ├── w-dex/ │ │ └── index.ts │ ├── wasabi-prop-amm/ │ │ └── index.ts │ ├── wavex-derivatives.ts │ ├── wavex-swap.ts │ ├── web3world/ │ │ └── index.ts │ ├── wefi/ │ │ └── index.ts │ ├── wemix.fi/ │ │ └── index.ts │ ├── wingriders/ │ │ └── index.ts │ ├── wombat-exchange/ │ │ └── index.ts │ ├── woofi/ │ │ └── index.ts │ ├── worldinc-perps/ │ │ ├── index.ts │ │ └── worldinc.ts │ ├── worldinc-spot/ │ │ └── index.ts │ ├── worm-wtf/ │ │ └── index.ts │ ├── wx.network/ │ │ └── index.ts │ ├── x3x.ts │ ├── x402/ │ │ ├── facilitators.ts │ │ └── index.ts │ ├── xei/ │ │ └── index.ts │ ├── xena-finance/ │ │ └── index.ts │ ├── xena-finance-derivative/ │ │ └── index.ts │ ├── xexchange/ │ │ └── index.ts │ ├── xfai/ │ │ └── index.ts │ ├── xpress/ │ │ └── index.ts │ ├── xrpl-dex/ │ │ └── index.ts │ ├── y2k-v1.ts │ ├── y2k-v2.ts │ ├── yakafinance/ │ │ └── index.ts │ ├── yakafinance-v3/ │ │ └── index.ts │ ├── yei-swap.ts │ ├── yfx-v3/ │ │ └── index.ts │ ├── yfx-v4/ │ │ └── index.ts │ ├── yield-basis.ts │ ├── zeno/ │ │ └── index.ts │ ├── zeta/ │ │ └── index.ts │ ├── zilswap/ │ │ └── index.ts │ ├── zkera-finance/ │ │ ├── index.ts │ │ └── zkera.ts │ ├── zkswap-stable/ │ │ └── index.ts │ ├── zkswap-v3/ │ │ └── index.ts │ ├── zo/ │ │ └── index.ts │ ├── zora-sofi/ │ │ └── index.ts │ ├── zyberswap-v2.ts │ └── zyberswap-v3.ts ├── factory/ │ ├── alliumSolanaDex.ts │ ├── blockscout.ts │ ├── chainTxFees.ts │ ├── compoundV2.ts │ ├── curators.ts │ ├── curve.ts │ ├── deadAdapters.json │ ├── duneSolanaDex.ts │ ├── gmxV1.ts │ ├── hyperliquid.ts │ ├── joeLiquidityBook.ts │ ├── nftVolume.ts │ ├── normalizedVolume.ts │ ├── orderly.ts │ ├── polymarket.ts │ ├── registry.ts │ ├── saddle.ts │ ├── solLst.ts │ ├── subscan.ts │ ├── symmio.ts │ ├── uniSubgraph.ts │ ├── uniV2.ts │ └── uniV3.ts ├── fees/ │ ├── 0x0dex.ts │ ├── 1776meme/ │ │ └── index.ts │ ├── 1dex/ │ │ └── index.ts │ ├── 3jane-lending.ts │ ├── 40acres/ │ │ └── index.ts │ ├── ArbitrumExchange-v2.ts │ ├── ArbitrumExchange-v3.ts │ ├── GUIDELINES.md │ ├── LeadFi-leadBTC/ │ │ └── index.ts │ ├── LiquidOps/ │ │ └── index.ts │ ├── SmarDex/ │ │ └── index.ts │ ├── aark/ │ │ └── index.ts │ ├── aave-labs.ts │ ├── aave-v3.ts │ ├── aave-v4.ts │ ├── aavechan.ts │ ├── abracadabra.ts │ ├── acred/ │ │ └── index.ts │ ├── across.ts │ ├── aden/ │ │ └── index.ts │ ├── aegis-jusd/ │ │ └── index.ts │ ├── aegis-yusd/ │ │ └── index.ts │ ├── aera-v2/ │ │ └── index.ts │ ├── aera-v3.ts │ ├── aethir/ │ │ └── index.ts │ ├── affluent/ │ │ └── index.ts │ ├── afiprotocol/ │ │ └── index.ts │ ├── aftermath-fi-amm.ts │ ├── aimbot.ts │ ├── airnft/ │ │ └── index.ts │ ├── airswap.ts │ ├── ajna-v1/ │ │ └── index.ts │ ├── ajna-v2/ │ │ └── index.ts │ ├── akash-network/ │ │ └── index.ts │ ├── aktionariat/ │ │ └── index.ts │ ├── alchemix.ts │ ├── algorand.ts │ ├── alkimi/ │ │ └── index.ts │ ├── allbridge-classic.ts │ ├── allbridge-core.ts │ ├── allox/ │ │ └── index.ts │ ├── almanak/ │ │ └── index.ts │ ├── alpha-arcade/ │ │ └── index.ts │ ├── alphafi/ │ │ └── index.ts │ ├── alphix.ts │ ├── amnis-finance/ │ │ └── index.ts │ ├── amped/ │ │ └── index.ts │ ├── amphor/ │ │ └── index.ts │ ├── angle/ │ │ ├── index.ts │ │ └── types.ts │ ├── ankr-lst.ts │ ├── anoncoin/ │ │ └── index.ts │ ├── antfun.ts │ ├── aori/ │ │ └── index.ts │ ├── apebot/ │ │ └── index.ts │ ├── apestore/ │ │ └── index.ts │ ├── apex-omni.ts │ ├── apexdefi/ │ │ ├── burst.ts │ │ ├── dex.ts │ │ └── index.ts │ ├── apollox/ │ │ └── index.ts │ ├── apricot/ │ │ └── index.ts │ ├── apriori.ts │ ├── aptos.ts │ ├── apyx-protocol.ts │ ├── aquabank.ts │ ├── arbitrum-nova.ts │ ├── arbitrum-timeboost/ │ │ └── index.ts │ ├── aries-markets/ │ │ └── index.ts │ ├── arkada/ │ │ └── index.ts │ ├── arrakis-v2/ │ │ └── index.ts │ ├── arweave/ │ │ └── index.ts │ ├── ash-perp/ │ │ └── index.ts │ ├── aspecta.ts │ ├── assetchain.ts │ ├── aster-spot/ │ │ └── index.ts │ ├── asymmetry-usdaf.ts │ ├── auki/ │ │ └── index.ts │ ├── aur/ │ │ └── index.ts │ ├── aura.ts │ ├── autofinance/ │ │ └── index.ts │ ├── autopilot/ │ │ └── index.ts │ ├── avalanche.ts │ ├── avalon-usda.ts │ ├── avalon_old/ │ │ └── index.ts │ ├── avant-avbtc/ │ │ └── index.ts │ ├── avant-aveth/ │ │ └── index.ts │ ├── avant-avusd/ │ │ └── index.ts │ ├── avantis/ │ │ └── index.ts │ ├── aveai/ │ │ └── index.ts │ ├── aveforge/ │ │ └── index.ts │ ├── axelar/ │ │ └── index.ts │ ├── axie-infinity/ │ │ └── index.ts │ ├── axiom.ts │ ├── azuro/ │ │ └── index.ts │ ├── b14g/ │ │ └── index.ts │ ├── b402.ts │ ├── babydoge-bridge/ │ │ └── index.ts │ ├── babylon-genesis/ │ │ └── index.ts │ ├── backedfi.ts │ ├── badger-dao/ │ │ └── index.ts │ ├── baker-dao/ │ │ └── index.ts │ ├── balancer-v1.ts │ ├── banana-gun-trading.ts │ ├── bancor-v2.ts │ ├── bankr.ts │ ├── basecamp/ │ │ └── index.ts │ ├── basepaint.ts │ ├── baseswap-v2.ts │ ├── baseswap-v3.ts │ ├── basisos/ │ │ └── index.ts │ ├── bcraft.ts │ ├── beam-dex-v3.ts │ ├── beamable-network/ │ │ └── index.ts │ ├── beamex.ts │ ├── bedrock-unibtc/ │ │ └── index.ts │ ├── bedrock-unieth/ │ │ └── index.ts │ ├── bedrock-uniiotx/ │ │ └── index.ts │ ├── beefy/ │ │ └── index.ts │ ├── beets-staked-sonic/ │ │ └── index.ts │ ├── beezie.ts │ ├── believe/ │ │ └── index.ts │ ├── bellumexchange.ts │ ├── bend/ │ │ └── index.ts │ ├── benddao-lending-v1.ts │ ├── benddao-lending-v2.ts │ ├── benqi-staked-avax.ts │ ├── beraborrow/ │ │ └── index.ts │ ├── berachain-bribes/ │ │ └── index.ts │ ├── beradrome/ │ │ └── index.ts │ ├── betmode.ts │ ├── betswirl/ │ │ └── index.ts │ ├── bifrost-chain.ts │ ├── bifrost-liquid-staking/ │ │ └── index.ts │ ├── bim/ │ │ └── index.ts │ ├── binance-alpha.ts │ ├── binance-staked-eth.ts │ ├── bitcoin-bridge/ │ │ └── index.ts │ ├── bitcoin.ts │ ├── bitfi-basis.ts │ ├── bitfi-btc.ts │ ├── bitflow-fi.ts │ ├── bitlayer/ │ │ └── index.ts │ ├── bitlayer-ybtc-family/ │ │ └── index.ts │ ├── bitway-earn.ts │ ├── blastapi.ts │ ├── blazingbot.ts │ ├── blend-backstop-v2/ │ │ └── index.ts │ ├── blend-pools/ │ │ └── index.ts │ ├── blend-pools-v2/ │ │ └── index.ts │ ├── blex/ │ │ └── index.ts │ ├── blockchain-capital/ │ │ └── index.ts │ ├── blocxroute.ts │ ├── bloom.ts │ ├── bluefin-alphalend.ts │ ├── bluefin-amm.ts │ ├── bluefin-pro.ts │ ├── bluefin.ts │ ├── bluemove/ │ │ └── index.ts │ ├── blur/ │ │ └── index.ts │ ├── bmx-freestyle.ts │ ├── bmx.ts │ ├── bob.ts │ ├── bodega-market/ │ │ └── index.ts │ ├── bonk-bot/ │ │ └── index.ts │ ├── bonk-staked-sol/ │ │ └── index.ts │ ├── bonzo/ │ │ └── index.ts │ ├── boop-fun/ │ │ └── index.ts │ ├── boson/ │ │ └── index.ts │ ├── botanix-stBTC.ts │ ├── botanix.ts │ ├── botfalcon.ts │ ├── bounce-tech.ts │ ├── bouncebit-cedefi/ │ │ └── index.ts │ ├── bracket-lst/ │ │ └── index.ts │ ├── bracket-vaults/ │ │ └── index.ts │ ├── bsc.ts │ ├── bucket-protocol/ │ │ └── index.ts │ ├── bucket-protocol-v2/ │ │ └── index.ts │ ├── buffer/ │ │ └── index.ts │ ├── bulbaswap-v2.ts │ ├── bulbaswap-v3.ts │ ├── bullx.ts │ ├── bungee-bridge.ts │ ├── bungee.ts │ ├── cakepie.ts │ ├── calculus.ts │ ├── canton.ts │ ├── cap/ │ │ ├── config.ts │ │ ├── helpers.ts │ │ └── index.ts │ ├── cap-finance-v4.ts │ ├── cardano.ts │ ├── cashmere/ │ │ └── index.ts │ ├── catex/ │ │ └── index.ts │ ├── catfee/ │ │ └── index.ts │ ├── cattos.ts │ ├── caviar-tangible.ts │ ├── caviarnine-lsu-pool.ts │ ├── caviarnine-shape-liquidity.ts │ ├── cbbtc/ │ │ └── index.ts │ ├── cbeth/ │ │ └── index.ts │ ├── cctp/ │ │ └── index.ts │ ├── celestia.ts │ ├── cellula/ │ │ └── index.ts │ ├── centrifuge/ │ │ └── index.ts │ ├── cetus/ │ │ └── index.ts │ ├── cetus-dlmm/ │ │ └── index.ts │ ├── chainflip/ │ │ └── index.ts │ ├── chainlink/ │ │ └── index.ts │ ├── chainlink-ccip.ts │ ├── chainlink-keepers.ts │ ├── chainlink-requests.ts │ ├── chainlink-vrf-v1.ts │ ├── chainlink-vrf-v2.ts │ ├── charm-fi-vaults-2/ │ │ └── index.ts │ ├── chattershield/ │ │ └── index.ts │ ├── cheapgm.ts │ ├── chedda-finance/ │ │ └── index.ts │ ├── cheesepad/ │ │ └── index.ts │ ├── chopcorp/ │ │ └── index.ts │ ├── chutes-ai.ts │ ├── cian-yieldlayer/ │ │ └── index.ts │ ├── circle.ts │ ├── circuitdao.ts │ ├── clanker.ts │ ├── clawdstrategy.ts │ ├── clearpool/ │ │ └── index.ts │ ├── clearpool-rwa/ │ │ └── index.ts │ ├── cleopatra-exchange.ts │ ├── clever.ts │ ├── clusters.ts │ ├── coal-works/ │ │ └── index.ts │ ├── cobaltx.ts │ ├── coinbase-commerce.ts │ ├── coinbase-wallet.ts │ ├── collector-crypt/ │ │ └── index.ts │ ├── collex.ts │ ├── colony/ │ │ ├── airdrops.ts │ │ ├── cai.ts │ │ ├── dex.ts │ │ ├── earlystage.ts │ │ ├── index.ts │ │ ├── masterChef.ts │ │ ├── staking.ts │ │ └── validatorProgram.ts │ ├── colorpool.ts │ ├── compound-v3.ts │ ├── compound.ts │ ├── concentrator.ts │ ├── concrete/ │ │ └── index.ts │ ├── contango/ │ │ └── index.ts │ ├── convex.ts │ ├── cooler-loans.ts │ ├── core-markets/ │ │ └── index.ts │ ├── corex/ │ │ └── index.ts │ ├── cosmoshub/ │ │ └── index.ts │ ├── courtyard/ │ │ └── index.ts │ ├── covo-finance.ts │ ├── covo-v2.ts │ ├── cow-protocol.ts │ ├── creator-bid.ts │ ├── crv-usd.ts │ ├── cryptex-v2.ts │ ├── crypto-com-lst.ts │ ├── crystal-terminal/ │ │ └── index.ts │ ├── csc.ts │ ├── current/ │ │ └── index.ts │ ├── curvance.ts │ ├── curve.ts │ ├── cvex/ │ │ └── index.ts │ ├── cyberperp.ts │ ├── czt.ts │ ├── d2finance/ │ │ └── index.ts │ ├── danogo/ │ │ ├── index.ts │ │ └── types.ts │ ├── dappos-intentEx.ts │ ├── debank-cloud.ts │ ├── dedust/ │ │ └── index.ts │ ├── deepbook-v3/ │ │ └── index.ts │ ├── defi-saver.ts │ ├── definitive.ts │ ├── defiplaza/ │ │ └── index.ts │ ├── defituna-amm/ │ │ └── index.ts │ ├── defituna-liquidity/ │ │ └── index.ts │ ├── degen-launchpad.ts │ ├── deltadefi/ │ │ └── index.ts │ ├── desk/ │ │ └── index.ts │ ├── dexfi/ │ │ └── index.ts │ ├── dexhunter/ │ │ └── index.ts │ ├── dexscreener.ts │ ├── dexter/ │ │ └── index.ts │ ├── dextools.ts │ ├── dextoro/ │ │ └── index.ts │ ├── dhedge/ │ │ └── index.ts │ ├── digift/ │ │ └── index.ts │ ├── dinero-pxeth/ │ │ └── index.ts │ ├── dln/ │ │ └── index.ts │ ├── dodo-fees.ts │ ├── doge.ts │ ├── dogechain.ts │ ├── dolomite/ │ │ └── index.ts │ ├── donut/ │ │ └── index.ts │ ├── doppler-finance/ │ │ └── index.ts │ ├── doublezero/ │ │ └── index.ts │ ├── dragonswap-v2.ts │ ├── dragonswap-v3.ts │ ├── dreaming.ts │ ├── dsx/ │ │ └── index.ts │ ├── duck-chain.ts │ ├── dune-supply.ts │ ├── dydx-v4/ │ │ └── index.ts │ ├── e3.ts │ ├── easya-kickstart/ │ │ └── index.ts │ ├── echelon.ts │ ├── echo/ │ │ └── index.ts │ ├── echo-lending/ │ │ └── index.ts │ ├── echo-lsd/ │ │ └── index.ts │ ├── echo-strategy/ │ │ └── index.ts │ ├── edebase.ts │ ├── edgex/ │ │ └── index.ts │ ├── eesee.ts │ ├── eggs-finance/ │ │ └── index.ts │ ├── eigenlayer.ts │ ├── element/ │ │ └── index.ts │ ├── ember-protocol.ts │ ├── emdx.ts │ ├── emojicoin.ts │ ├── emporium/ │ │ └── index.ts │ ├── ens.ts │ ├── enzyme/ │ │ └── index.ts │ ├── equilibria.ts │ ├── equity/ │ │ └── index.ts │ ├── erc-burner/ │ │ └── index.ts │ ├── erinaceus/ │ │ └── index.ts │ ├── ethena.ts │ ├── ether-fi/ │ │ └── index.ts │ ├── ethereum/ │ │ └── index.ts │ ├── etherfi-cash-cards/ │ │ └── index.ts │ ├── etherfi-cash-collateral-management/ │ │ └── index.ts │ ├── ethervista.ts │ ├── euler/ │ │ ├── config.ts │ │ └── index.ts │ ├── eva/ │ │ └── index.ts │ ├── exponent/ │ │ └── index.ts │ ├── extended.ts │ ├── extra/ │ │ └── index.ts │ ├── factor/ │ │ └── index.ts │ ├── faith/ │ │ └── index.ts │ ├── falcon-finance/ │ │ └── index.ts │ ├── fantasy-top/ │ │ └── index.ts │ ├── farcaster.ts │ ├── fastjpeg/ │ │ └── index.ts │ ├── fastlane/ │ │ └── index.ts │ ├── fathom-cdp.ts │ ├── felix-usdhl/ │ │ └── index.ts │ ├── ferro.ts │ ├── fidelity-crypto-fund/ │ │ └── index.ts │ ├── fidelity-digital-interest/ │ │ └── index.ts │ ├── filecoin.ts │ ├── finder-bot/ │ │ └── index.ts │ ├── fira.ts │ ├── first-crypto-bank/ │ │ └── index.ts │ ├── fjord-foundry-v1.ts │ ├── fjord-foundry-v2.ts │ ├── flarebank/ │ │ └── index.ts │ ├── flashbot.ts │ ├── flashtrade.ts │ ├── flaunch.ts │ ├── flexperp.ts │ ├── flip/ │ │ └── index.ts │ ├── flock/ │ │ └── index.ts │ ├── flow/ │ │ └── index.ts │ ├── flowx-finance/ │ │ └── index.ts │ ├── flowx-v3/ │ │ └── index.ts │ ├── fluence/ │ │ └── index.ts │ ├── fluid/ │ │ ├── config.ts │ │ ├── fees.ts │ │ ├── index.ts │ │ └── revenue.ts │ ├── fluid-lite/ │ │ └── index.ts │ ├── fluidtokens/ │ │ └── index.ts │ ├── fluxbeam.ts │ ├── fly-trade/ │ │ └── index.ts │ ├── flying-tulip-ftusd.ts │ ├── flying-tulip-lend.ts │ ├── flying-tulip.ts │ ├── fomo/ │ │ └── index.ts │ ├── foom-cash/ │ │ └── index.ts │ ├── footballdotfun/ │ │ └── index.ts │ ├── foundation.ts │ ├── four-meme.ts │ ├── fragment/ │ │ └── index.ts │ ├── fragmetric/ │ │ └── index.ts │ ├── frankencoin/ │ │ └── index.ts │ ├── franklin-templeton/ │ │ └── index.ts │ ├── frax-amo.ts │ ├── frax-ether.ts │ ├── frax-fpi.ts │ ├── frax-swap.ts │ ├── fraxlend/ │ │ └── index.ts │ ├── frenflow.ts │ ├── friend-tech.ts │ ├── fuel-ignition.ts │ ├── fulcrom-finance.ts │ ├── fullsail-finance/ │ │ └── index.ts │ ├── furucombo/ │ │ └── index.ts │ ├── futarchy-amm/ │ │ └── index.ts │ ├── futureswap.ts │ ├── fvm-exchange.ts │ ├── fwx/ │ │ └── index.ts │ ├── fx-protocol.ts │ ├── g8keep.ts │ ├── gacha/ │ │ └── index.ts │ ├── gaib/ │ │ └── index.ts │ ├── gains-network.ts │ ├── gambit.ts │ ├── gameclub.ts │ ├── gamma.ts │ ├── garden/ │ │ └── index.ts │ ├── garuda-staking.ts │ ├── gaspump/ │ │ └── index.ts │ ├── gate-btc/ │ │ └── index.ts │ ├── gate-perps.ts │ ├── gauntlet.ts │ ├── gearbox/ │ │ ├── configs.ts │ │ └── index.ts │ ├── geckoterminal.ts │ ├── genius-protocol/ │ │ └── index.ts │ ├── geodnet.ts │ ├── get-protocol.ts │ ├── getHemiNames/ │ │ └── index.ts │ ├── gitcoin-passport/ │ │ └── index.ts │ ├── giza/ │ │ └── index.ts │ ├── gmgnai.ts │ ├── gmx-sol.ts │ ├── gmx-v2/ │ │ └── index.ts │ ├── gmx.ts │ ├── gnd-protocol.ts │ ├── goat-protocol/ │ │ └── index.ts │ ├── goblin/ │ │ └── index.ts │ ├── godl/ │ │ └── index.ts │ ├── goku-money/ │ │ └── index.ts │ ├── goldfinch.ts │ ├── gondi-v3/ │ │ └── index.ts │ ├── goplus-locker.ts │ ├── goplus.ts │ ├── graphite-protocol/ │ │ └── index.ts │ ├── graveyard-protocol/ │ │ └── index.ts │ ├── gravity/ │ │ └── index.ts │ ├── grayscale/ │ │ └── index.ts │ ├── grelfswap/ │ │ └── index.ts │ ├── grizzly-trade-derivatives-v2.ts │ ├── grove/ │ │ └── index.ts │ ├── gt3.ts │ ├── gyroscope/ │ │ └── index.ts │ ├── haedal/ │ │ └── index.ts │ ├── haedal-protocol/ │ │ └── index.ts │ ├── haedal-vault/ │ │ └── index.ts │ ├── haiku/ │ │ └── index.ts │ ├── harmonic.ts │ ├── hashnote-usyc/ │ │ └── index.ts │ ├── hashpaylink.ts │ ├── hastra/ │ │ └── index.ts │ ├── haven1-hswap/ │ │ └── index.ts │ ├── hawkfi.ts │ ├── haystack/ │ │ └── index.ts │ ├── heaven-dex/ │ │ └── index.ts │ ├── hedera.ts │ ├── hedgey.ts │ ├── hegic.ts │ ├── helio.ts │ ├── helium/ │ │ └── index.ts │ ├── helix-helix-perp.ts │ ├── helix-helix.ts │ ├── hercules-v2.ts │ ├── hercules-v3.ts │ ├── hermes-v2/ │ │ └── index.ts │ ├── hfun.ts │ ├── hikari.ts │ ├── hipo/ │ │ └── index.ts │ ├── hivemapper/ │ │ └── index.ts │ ├── hlscope/ │ │ └── index.ts │ ├── holdstation-defutures.ts │ ├── honeyplay-amm/ │ │ └── index.ts │ ├── honeyplay-liquid-staking/ │ │ └── index.ts │ ├── honeyplay-marketplace/ │ │ └── index.ts │ ├── hono.ts │ ├── hop-protocol.ts │ ├── hopr/ │ │ └── index.ts │ ├── houdini-swap.ts │ ├── human-id/ │ │ └── index.ts │ ├── humidifi.ts │ ├── hydradx.ts │ ├── hydrex/ │ │ └── index.ts │ ├── hydro-inflow/ │ │ └── index.ts │ ├── hylo-lst.ts │ ├── hylo-protocol/ │ │ └── index.ts │ ├── hyperbeat/ │ │ └── index.ts │ ├── hyperbeat-lst/ │ │ └── index.ts │ ├── hypercat.ts │ ├── hyperevm.ts │ ├── hyperlane.ts │ ├── hyperlend-isolated.ts │ ├── hyperliquid-hlp.ts │ ├── hyperswap-terminal.ts │ ├── hypertek/ │ │ └── index.ts │ ├── hyperunit/ │ │ └── index.ts │ ├── hyperwave/ │ │ ├── hwhlp.ts │ │ ├── hwhype.ts │ │ └── index.ts │ ├── hypurrfi-isolated/ │ │ ├── abi.json │ │ └── index.ts │ ├── icp.ts │ ├── idle/ │ │ └── index.ts │ ├── illuvium.ts │ ├── immortalx/ │ │ └── index.ts │ ├── imx-seaport/ │ │ ├── index.ts │ │ └── seaport.ts │ ├── index-coop/ │ │ └── index.ts │ ├── indigo/ │ │ └── index.ts │ ├── infinex-swap.ts │ ├── infinifi/ │ │ └── index.ts │ ├── infinite/ │ │ └── index.ts │ ├── infinityname/ │ │ └── index.ts │ ├── infrared-finance.ts │ ├── injective.ts │ ├── ink.ts │ ├── instadapp/ │ │ └── index.ts │ ├── interface-app.ts │ ├── inverse-finance/ │ │ └── index.ts │ ├── iotex/ │ │ └── index.ts │ ├── ipor-protocol/ │ │ └── index.ts │ ├── ironbank/ │ │ └── index.ts │ ├── ivx/ │ │ └── index.ts │ ├── jade/ │ │ └── index.ts │ ├── javsphere/ │ │ └── index.ts │ ├── jeton/ │ │ └── index.ts │ ├── jito/ │ │ └── index.ts │ ├── jito-mev-tips/ │ │ └── index.ts │ ├── jito-staked-sol/ │ │ └── index.ts │ ├── jojo/ │ │ └── index.ts │ ├── jpg-store/ │ │ └── index.ts │ ├── juice-finance/ │ │ └── index.ts │ ├── juicebox/ │ │ └── index.ts │ ├── jumper-exchange/ │ │ └── index.ts │ ├── jup-ape.ts │ ├── jup-studio/ │ │ └── index.ts │ ├── jupiter-dca.ts │ ├── jupiter-lend/ │ │ └── index.ts │ ├── jupiter-limit.ts │ ├── jupiter-perpetual/ │ │ └── index.ts │ ├── jupiter-staked-sol/ │ │ └── index.ts │ ├── jupiter.ts │ ├── justbet/ │ │ ├── constants.ts │ │ └── index.ts │ ├── justlend.ts │ ├── k-bit/ │ │ └── index.ts │ ├── kaching/ │ │ └── index.ts │ ├── kaia/ │ │ └── index.ts │ ├── kaio/ │ │ └── index.ts │ ├── kairos/ │ │ └── index.ts │ ├── kamino-lending/ │ │ └── index.ts │ ├── kamino-liquidity/ │ │ └── index.ts │ ├── kanalabs-perp/ │ │ └── index.ts │ ├── kasu.ts │ ├── keller-cl/ │ │ └── index.ts │ ├── kelp.ts │ ├── kensei.ts │ ├── keom.ts │ ├── kerberos/ │ │ ├── index.ts │ │ └── routers.ts │ ├── kgen.ts │ ├── kiloex/ │ │ └── index.ts │ ├── kinetic.ts │ ├── kinetiq-staked-hype/ │ │ └── index.ts │ ├── kinetix-v3/ │ │ └── index.ts │ ├── kintsu.ts │ ├── klaytn.ts │ ├── kleros.ts │ ├── kofi-finance/ │ │ └── index.ts │ ├── kpk.ts │ ├── kreo.ts │ ├── kromatika.ts │ ├── kumbaya/ │ │ └── index.ts │ ├── kyan.ts │ ├── kyberswap-aggregator.ts │ ├── kyros/ │ │ └── index.ts │ ├── lab-terminal.ts │ ├── lagoon/ │ │ ├── config.ts │ │ └── index.ts │ ├── lamboo.ts │ ├── launch-on-bags/ │ │ └── index.ts │ ├── launchlab/ │ │ └── index.ts │ ├── lavarage.ts │ ├── layer3/ │ │ └── index.ts │ ├── layerzero.ts │ ├── layerzerov1.ts │ ├── lazy-summer-protocol/ │ │ └── index.ts │ ├── lens-protocol.ts │ ├── letsbonk/ │ │ └── index.ts │ ├── level-finance.ts │ ├── level.ts │ ├── levvy-fi/ │ │ └── index.ts │ ├── levvy-fi-tokens/ │ │ └── index.ts │ ├── lexer/ │ │ └── index.ts │ ├── lido.ts │ ├── lifi/ │ │ └── index.ts │ ├── lighterv2/ │ │ └── index.ts │ ├── lighterv2-spot/ │ │ └── index.ts │ ├── linehub-perps/ │ │ └── index.ts │ ├── liquid-bolt.ts │ ├── liquid-collective/ │ │ └── index.ts │ ├── liquid-protocol/ │ │ └── index.ts │ ├── liquid-ron/ │ │ └── index.ts │ ├── liquidity-slicing/ │ │ └── index.ts │ ├── liquidlaunch/ │ │ └── index.ts │ ├── liquis.ts │ ├── liquity-v2.ts │ ├── lista-dex.ts │ ├── lista-lending/ │ │ └── index.ts │ ├── lista-lisusd/ │ │ └── index.ts │ ├── lista-rwa/ │ │ └── index.ts │ ├── lista-slisbnb/ │ │ └── index.ts │ ├── litecoin.ts │ ├── livepeer/ │ │ └── index.ts │ ├── llamalend-curve.ts │ ├── llamalend.ts │ ├── lnexchange-perp.ts │ ├── lobbyfi.ts │ ├── lombard-lbtc/ │ │ └── index.ts │ ├── lombard-vault/ │ │ └── index.ts │ ├── looksrare.ts │ ├── looped-hype/ │ │ └── index.ts │ ├── loopscale/ │ │ └── index.ts │ ├── looter.ts │ ├── lorenzo-susd1/ │ │ └── index.ts │ ├── luna-fun.ts │ ├── lybra-finance.ts │ ├── lybra-v2.ts │ ├── lynex.ts │ ├── lyra-v2-options.ts │ ├── lyra-v2.ts │ ├── lyra.ts │ ├── m0.ts │ ├── macaron-bid.ts │ ├── maestro.ts │ ├── magnum-trading-bot/ │ │ └── index.ts │ ├── magpie.ts │ ├── maia-dao/ │ │ └── index.ts │ ├── mainstreet/ │ │ └── index.ts │ ├── makenow-meme.ts │ ├── makerdao.ts │ ├── makina/ │ │ └── index.ts │ ├── mamo.ts │ ├── manifold.ts │ ├── manta.ts │ ├── mantle-restaking/ │ │ └── index.ts │ ├── maple-finance.ts │ ├── margin-zero.ts │ ├── marinade-liquid-staking/ │ │ └── index.ts │ ├── marinade-native/ │ │ └── index.ts │ ├── marinade-select/ │ │ └── index.ts │ ├── markit.ts │ ├── marquee/ │ │ └── index.ts │ ├── matcha-xyz.ts │ ├── maverick.ts │ ├── maxapy/ │ │ └── index.ts │ ├── maxbid/ │ │ └── index.ts │ ├── mayan.ts │ ├── megamine/ │ │ └── index.ts │ ├── mellow-lrt.ts │ ├── memecooking/ │ │ └── index.ts │ ├── memejob/ │ │ └── index.ts │ ├── mememarket/ │ │ └── index.ts │ ├── meridian-amm.ts │ ├── meridian-trade.ts │ ├── merkle-trade.ts │ ├── meso-finance.ts │ ├── meta-pool-eth/ │ │ └── index.ts │ ├── metalex/ │ │ └── index.ts │ ├── metamask-musd/ │ │ └── index.ts │ ├── metamask.ts │ ├── metaplex.ts │ ├── metavault-derivatives-v2/ │ │ └── index.ts │ ├── metavault-v3/ │ │ └── index.ts │ ├── metavault.trade/ │ │ └── index.ts │ ├── meth-protocol.ts │ ├── metronome-synth/ │ │ └── index.ts │ ├── mevx.ts │ ├── mi4/ │ │ └── index.ts │ ├── midas-rwa/ │ │ └── index.ts │ ├── migrate-fun/ │ │ └── index.ts │ ├── mimboku-aggregator.ts │ ├── minebean.ts │ ├── minebtc.ts │ ├── mineloot.ts │ ├── minswap/ │ │ └── index.ts │ ├── minswap-aggregator/ │ │ └── index.ts │ ├── mint.ts │ ├── mintpark/ │ │ └── index.ts │ ├── mixoor/ │ │ └── index.ts │ ├── moar.ts │ ├── monad/ │ │ └── index.ts │ ├── monarchpay/ │ │ └── index.ts │ ├── moneyfi/ │ │ └── index.ts │ ├── monorail.ts │ ├── moonpiefun.ts │ ├── moonriver.ts │ ├── moonshot-create.ts │ ├── moonshot-money.ts │ ├── moonshot.ts │ ├── moonwell/ │ │ └── index.ts │ ├── moonwell-apollo.ts │ ├── moonwell-artemis.ts │ ├── morph.ts │ ├── morpheus-ai.ts │ ├── morpho/ │ │ └── index.ts │ ├── mosaic-amm.ts │ ├── move-dollar.ts │ ├── move.ts │ ├── mstable-v2/ │ │ └── index.ts │ ├── mu-digital.ts │ ├── multichain/ │ │ └── index.ts │ ├── multipli-fi/ │ │ └── index.ts │ ├── multiversx/ │ │ └── index.ts │ ├── mummy-finance.ts │ ├── musical-chairs.ts │ ├── mux.ts │ ├── myriadmarkets/ │ │ └── index.ts │ ├── myx-finance/ │ │ └── index.ts │ ├── nado-perp.ts │ ├── nado-spot.ts │ ├── namoshi.ts │ ├── napier/ │ │ └── index.ts │ ├── native.ts │ ├── navi/ │ │ └── index.ts │ ├── navigator/ │ │ └── index.ts │ ├── near/ │ │ └── index.ts │ ├── near-intents/ │ │ └── index.ts │ ├── neby-dex.ts │ ├── nemo-vault/ │ │ └── index.ts │ ├── nemo-yield-trading/ │ │ └── index.ts │ ├── nest-credit.ts │ ├── nextrare/ │ │ └── index.ts │ ├── nexus-mutual.ts │ ├── nfprompt/ │ │ └── index.ts │ ├── nickel/ │ │ └── index.ts │ ├── nile-exchange/ │ │ ├── bribes.ts │ │ └── index.ts │ ├── noble.ts │ ├── node-dao/ │ │ └── index.ts │ ├── node-ops.ts │ ├── noon/ │ │ └── index.ts │ ├── nouns/ │ │ └── index.ts │ ├── nova/ │ │ └── index.ts │ ├── nozomi.ts │ ├── ntm/ │ │ └── index.ts │ ├── nuri-exchange-v2/ │ │ ├── bribes.ts │ │ └── index.ts │ ├── o2/ │ │ └── index.ts │ ├── obol/ │ │ └── index.ts │ ├── ociswap-basic.ts │ ├── ociswap-precision.ts │ ├── odyssey-finance/ │ │ └── index.ts │ ├── okx-swap.ts │ ├── olympus-dao.ts │ ├── omnihub/ │ │ └── index.ts │ ├── onchain-checkin/ │ │ └── index.ts │ ├── ondo.ts │ ├── onre/ │ │ └── index.ts │ ├── open-stablecoin-index/ │ │ └── index.ts │ ├── openchat/ │ │ └── index.ts │ ├── openeden-t-bills/ │ │ └── index.ts │ ├── openeden-usdo.ts │ ├── openledger/ │ │ └── index.ts │ ├── opensea-seaport.ts │ ├── opentrade.ts │ ├── optfun/ │ │ └── index.ts │ ├── optionBlitz/ │ │ └── index.ts │ ├── opus.ts │ ├── orb/ │ │ └── index.ts │ ├── orderly/ │ │ └── index.ts │ ├── ore/ │ │ └── index.ts │ ├── origami-finance.ts │ ├── origin-dollar/ │ │ └── index.ts │ ├── orynth.ts │ ├── osmosis.ts │ ├── ostium/ │ │ └── index.ts │ ├── oxfun.ts │ ├── p2p-lending/ │ │ └── index.ts │ ├── p2pme/ │ │ └── index.ts │ ├── paal-ai/ │ │ └── index.ts │ ├── pact.ts │ ├── padre/ │ │ └── index.ts │ ├── pagcrypto/ │ │ └── index.ts │ ├── paint-swap.ts │ ├── pancakeswap-lottery/ │ │ └── index.ts │ ├── pandora-speed-trading/ │ │ └── index.ts │ ├── paradex/ │ │ └── index.ts │ ├── parcl/ │ │ └── index.ts │ ├── parity-dex.ts │ ├── paxos/ │ │ └── index.ts │ ├── paxos-gold/ │ │ └── index.ts │ ├── paycash/ │ │ └── index.ts │ ├── peapods-finance/ │ │ └── index.ts │ ├── pear-protocol/ │ │ └── index.ts │ ├── pendle.ts │ ├── penpie.ts │ ├── pepe-swaves/ │ │ └── index.ts │ ├── pepeboost/ │ │ └── index.ts │ ├── perp88.ts │ ├── perpetual-protocol.ts │ ├── phantom.ts │ ├── pharaoh-exchange.ts │ ├── phoenix/ │ │ └── index.ts │ ├── photon.ts │ ├── phygitals/ │ │ └── index.ts │ ├── pika-protocol.ts │ ├── pinksale/ │ │ └── index.ts │ ├── pinnako.ts │ ├── pistachio.ts │ ├── pizza-city.ts │ ├── plasma-one/ │ │ └── index.ts │ ├── plasma-saving-vaults/ │ │ └── index.ts │ ├── plasma.ts │ ├── playground/ │ │ └── index.ts │ ├── pleasing-gold.ts │ ├── pocket-universe.ts │ ├── polter/ │ │ ├── index.ts │ │ └── types.ts │ ├── polycule.ts │ ├── polygon.ts │ ├── polymarket.ts │ ├── polynomial.ts │ ├── pooltogether-v5/ │ │ └── index.ts │ ├── possumlabs/ │ │ └── index.ts │ ├── predict-fun/ │ │ └── index.ts │ ├── predy-finance-v5.ts │ ├── premia-v2.ts │ ├── premia-v3.ts │ ├── prerich-app.ts │ ├── prestocks/ │ │ └── index.ts │ ├── primordium.ts │ ├── prisma-finance.ts │ ├── privacy-cash/ │ │ └── index.ts │ ├── privacy-pools.ts │ ├── provenance.ts │ ├── puffer-finance/ │ │ └── index.ts │ ├── puffer-vaults.ts │ ├── pulsechain.ts │ ├── pump-swap/ │ │ └── index.ts │ ├── pumpdotfun.ts │ ├── pumper/ │ │ └── index.ts │ ├── pumpparty/ │ │ └── index.ts │ ├── pumpup.ts │ ├── punk-strategy.ts │ ├── punk.coffee/ │ │ └── index.ts │ ├── pyth-entropy/ │ │ └── index.ts │ ├── pyth-express/ │ │ └── index.ts │ ├── pyth-network/ │ │ └── index.ts │ ├── pyth-pro/ │ │ └── index.ts │ ├── qidao.ts │ ├── quai-network/ │ │ └── index.ts │ ├── quanto/ │ │ └── index.ts │ ├── qubic-mining/ │ │ └── index.ts │ ├── quenta/ │ │ └── index.ts │ ├── quickswap-hydra/ │ │ └── index.ts │ ├── quickswap-perps/ │ │ └── index.ts │ ├── rabby.ts │ ├── radiant.ts │ ├── radpie.ts │ ├── railgun.ts │ ├── rain/ │ │ └── index.ts │ ├── rain-one/ │ │ └── index.ts │ ├── rainbow-predictions.ts │ ├── rainbow-token-launchpad.ts │ ├── rainbow-wallet.ts │ ├── ramses-exchange-v1/ │ │ ├── bribes.ts │ │ └── index.ts │ ├── ramses-exchange-v2/ │ │ ├── bribes.ts │ │ └── index.ts │ ├── rank-trading/ │ │ └── index.ts │ ├── rarible/ │ │ └── index.ts │ ├── ratio/ │ │ └── index.ts │ ├── raybot.ts │ ├── razordex.ts │ ├── re-protocol/ │ │ └── index.ts │ ├── reachme/ │ │ └── index.ts │ ├── ready-cards.ts │ ├── reental/ │ │ └── index.ts │ ├── renzo/ │ │ ├── common.ts │ │ └── index.ts │ ├── rerange/ │ │ └── index.ts │ ├── reserve/ │ │ └── index.ts │ ├── reservoir-protocol.ts │ ├── resolv/ │ │ └── index.ts │ ├── resupply/ │ │ └── index.ts │ ├── rezerve-money/ │ │ ├── bonds.ts │ │ ├── index.ts │ │ ├── rebases.ts │ │ └── shadow.ts │ ├── rfx/ │ │ └── index.ts │ ├── rhea-cross-chain/ │ │ └── index.ts │ ├── rhea-lend/ │ │ └── index.ts │ ├── rhea-lst/ │ │ └── index.ts │ ├── ribbon/ │ │ └── index.ts │ ├── rifts/ │ │ └── index.ts │ ├── rings/ │ │ └── index.ts │ ├── rip-fun/ │ │ └── index.ts │ ├── ripple.ts │ ├── rise-launchpad.ts │ ├── river/ │ │ ├── config.ts │ │ └── index.ts │ ├── rocketpool.ts │ ├── rocksolid-network/ │ │ └── index.ts │ ├── rollbit.ts │ ├── roots/ │ │ └── index.ts │ ├── rosetta.ts │ ├── royalbet.ts │ ├── royco.ts │ ├── rubicon/ │ │ └── index.ts │ ├── rubyscore/ │ │ └── index.ts │ ├── saber/ │ │ └── index.ts │ ├── sablier.ts │ ├── safe.ts │ ├── sanctum/ │ │ └── index.ts │ ├── sanctum-infinity/ │ │ └── index.ts │ ├── sanctum-validator-lsts/ │ │ └── index.ts │ ├── santa-browser/ │ │ └── index.ts │ ├── saros.ts │ ├── satoshi-perps/ │ │ └── index.ts │ ├── saturn-protocol/ │ │ └── index.ts │ ├── scallop/ │ │ └── index.ts │ ├── scatter.ts │ ├── scoop.ts │ ├── sdai.ts │ ├── seamless-v2.ts │ ├── securitize/ │ │ └── index.ts │ ├── seda.ts │ ├── sedge/ │ │ └── index.ts │ ├── segment-finance.ts │ ├── sei.ts │ ├── sendshot.ts │ ├── sentinel-trader-bot.ts │ ├── sharky/ │ │ └── index.ts │ ├── sharpe-earn/ │ │ └── index.ts │ ├── shmonad/ │ │ └── index.ts │ ├── shoebillFinance-v2/ │ │ └── index.ts │ ├── shuriken.ts │ ├── sideshift.ts │ ├── sierra/ │ │ └── index.ts │ ├── silent.ts │ ├── silo-finance/ │ │ └── index.ts │ ├── silo-finance-v2/ │ │ └── index.ts │ ├── size-credit.ts │ ├── skale.ts │ ├── smithii/ │ │ └── index.ts │ ├── snakefinance.ts │ ├── sns.ts │ ├── socket/ │ │ └── index.ts │ ├── sofa-org/ │ │ └── index.ts │ ├── sol-trading-bot/ │ │ └── index.ts │ ├── solana.ts │ ├── solar-studios/ │ │ └── index.ts │ ├── solend.ts │ ├── solid-yield.ts │ ├── solidly-v3.ts │ ├── solidlydex.ts │ ├── solomon-usdv.ts │ ├── solstice-usx/ │ │ └── index.ts │ ├── solv-finance/ │ │ └── index.ts │ ├── sommelier.ts │ ├── soneium.ts │ ├── sonne-finance/ │ │ ├── helpers.ts │ │ └── index.ts │ ├── sosovalue/ │ │ └── index.ts │ ├── sosovalue-basis/ │ │ └── index.ts │ ├── spaace/ │ │ └── index.ts │ ├── space-and-time.ts │ ├── spark/ │ │ └── index.ts │ ├── spark-liquidity-layer/ │ │ ├── index.ts │ │ └── spark-liquidity-layer-revenue.sql │ ├── sparkdex-v3-1/ │ │ └── index.ts │ ├── spiko/ │ │ └── index.ts │ ├── splash/ │ │ └── index.ts │ ├── splitswap/ │ │ └── index.ts │ ├── springsui/ │ │ └── index.ts │ ├── springsui-ecosystem/ │ │ └── index.ts │ ├── ssv-network.ts │ ├── stUSDT/ │ │ └── index.ts │ ├── stability/ │ │ └── index.ts │ ├── stac-clo/ │ │ └── index.ts │ ├── stackingdao/ │ │ └── index.ts │ ├── stacks.ts │ ├── stader.ts │ ├── staked-hype/ │ │ └── index.ts │ ├── stakedao/ │ │ └── index.ts │ ├── stakedotlink/ │ │ └── index.ts │ ├── stakee/ │ │ └── index.ts │ ├── stakestone-stone/ │ │ └── index.ts │ ├── stakewise.ts │ ├── standx-dusd/ │ │ └── index.ts │ ├── stargate-finance-v2/ │ │ └── index.ts │ ├── stargate.ts │ ├── starknet.ts │ ├── stars-arena.ts │ ├── stbot.ts │ ├── stealcam.ts │ ├── steamm/ │ │ └── index.ts │ ├── steer/ │ │ └── index.ts │ ├── stellar/ │ │ └── index.ts │ ├── step-finance/ │ │ └── index.ts │ ├── stockfi/ │ │ └── index.ts │ ├── ston/ │ │ └── index.ts │ ├── stormtrade/ │ │ └── index.ts │ ├── stout/ │ │ └── index.ts │ ├── strata-markets/ │ │ └── index.ts │ ├── stratex/ │ │ └── index.ts │ ├── streamflow/ │ │ └── index.ts │ ├── stride.ts │ ├── strike-finance/ │ │ └── index.ts │ ├── substanceX/ │ │ └── index.ts │ ├── sudofinance/ │ │ └── index.ts │ ├── sudoswap-v1.ts │ ├── sudoswap-v2.ts │ ├── sui.ts │ ├── suilend/ │ │ └── index.ts │ ├── suite/ │ │ └── index.ts │ ├── summer.fi/ │ │ └── index.ts │ ├── sundaeswap/ │ │ └── index.ts │ ├── sunpump.ts │ ├── sunswap-v1.ts │ ├── sunswap-v2.ts │ ├── sunswap-v3.ts │ ├── superchain.ts │ ├── superfund/ │ │ └── index.ts │ ├── superstate/ │ │ └── index.ts │ ├── superstate-uscc/ │ │ └── index.ts │ ├── surf-liquid.ts │ ├── surge-trade.ts │ ├── sushiswap-agg.ts │ ├── swap-coffee/ │ │ └── index.ts │ ├── swell-restaking/ │ │ └── index.ts │ ├── swell.ts │ ├── swing/ │ │ └── index.ts │ ├── symbiotic/ │ │ └── index.ts │ ├── symmio/ │ │ └── index.ts │ ├── synapse/ │ │ └── index.ts │ ├── synfutures-v3/ │ │ └── index.ts │ ├── synthetix-v3.ts │ ├── synthetix.ts │ ├── tangible-rwa.ts │ ├── tarot.ts │ ├── taulabs.ts │ ├── tbtc.ts │ ├── tectonic/ │ │ └── index.ts │ ├── telegram-wallet-perps/ │ │ └── index.ts │ ├── tempo/ │ │ └── index.ts │ ├── termmax.ts │ ├── tether/ │ │ └── index.ts │ ├── tether-gold/ │ │ └── index.ts │ ├── tezos.ts │ ├── thegraph.ts │ ├── thena-integral.ts │ ├── thena-v1.ts │ ├── thena-v3.ts │ ├── theo/ │ │ └── index.ts │ ├── theo-straddle-vaults/ │ │ └── index.ts │ ├── thorchain-dex/ │ │ └── index.ts │ ├── thorchain.ts │ ├── thorswap/ │ │ └── index.ts │ ├── thorwallet/ │ │ └── index.ts │ ├── tickr.ts │ ├── tigris/ │ │ └── index.ts │ ├── time-fun.ts │ ├── tlx-finance/ │ │ └── index.ts │ ├── tna.ts │ ├── token-works/ │ │ └── index.ts │ ├── ton.ts │ ├── ton4you/ │ │ └── index.ts │ ├── tonco/ │ │ └── index.ts │ ├── tonstakers-lsd/ │ │ └── index.ts │ ├── topcut/ │ │ └── index.ts │ ├── torch/ │ │ └── index.ts │ ├── tornado/ │ │ └── index.ts │ ├── toros/ │ │ └── index.ts │ ├── touch.fan.ts │ ├── trade-wiz.ts │ ├── trading-terminal/ │ │ └── index.ts │ ├── trado/ │ │ └── index.ts │ ├── tree-news/ │ │ └── index.ts │ ├── treehouse-protocol/ │ │ └── index.ts │ ├── trends-curve.ts │ ├── trends.ts │ ├── tria-card.ts │ ├── tribe-run.ts │ ├── triggerx/ │ │ └── index.ts │ ├── tristero-margin.ts │ ├── tron.ts │ ├── tronsave/ │ │ └── index.ts │ ├── trust-wallet.ts │ ├── turbos/ │ │ └── index.ts │ ├── typus-dov.ts │ ├── typus-perp.ts │ ├── typus-safu.ts │ ├── unibot.ts │ ├── unichain.ts │ ├── unicornx.ts │ ├── unicrypt.ts │ ├── uniderp/ │ │ └── index.ts │ ├── unidex.ts │ ├── uniswap-lab.ts │ ├── universalx.ts │ ├── unlock-protocol.ts │ ├── up-vs-down-game.ts │ ├── updown/ │ │ └── index.ts │ ├── upheaval-spot/ │ │ └── index.ts │ ├── upshift/ │ │ └── index.ts │ ├── usdai/ │ │ ├── index.ts │ │ ├── legacyUtils.ts │ │ └── metrics.ts │ ├── usdd/ │ │ └── index.ts │ ├── usdo.ts │ ├── usdx.ts │ ├── usual.ts │ ├── vader-ai.ts │ ├── valas-finance.ts │ ├── valorem/ │ │ ├── constants.ts │ │ ├── helpers.ts │ │ ├── index.ts │ │ └── interfaces.ts │ ├── variational/ │ │ └── index.ts │ ├── varlamore/ │ │ └── index.ts │ ├── vaulta-ram/ │ │ └── index.ts │ ├── vaulta-rex/ │ │ └── index.ts │ ├── vaultcraft.ts │ ├── vaultka.ts │ ├── vbill/ │ │ └── index.ts │ ├── veax.ts │ ├── vectorfun.ts │ ├── veda.ts │ ├── velo/ │ │ └── index.ts │ ├── velodrome/ │ │ └── index.ts │ ├── velodrome-v2/ │ │ └── index.ts │ ├── veno-finance.ts │ ├── venus-finance.ts │ ├── venus-flux/ │ │ ├── index.ts │ │ └── revenue.ts │ ├── verse.ts │ ├── vesper/ │ │ └── index.ts │ ├── vest-markets/ │ │ └── index.ts │ ├── vesta-finance.ts │ ├── vexy/ │ │ └── index.ts │ ├── vfat/ │ │ └── index.ts │ ├── vibes-meme.ts │ ├── vicuna-finance/ │ │ └── index.ts │ ├── vinufinance/ │ │ └── index.ts │ ├── virtual-protocol.ts │ ├── virtue/ │ │ └── index.ts │ ├── volboost.ts │ ├── volo-vault/ │ │ └── index.ts │ ├── volta-markets/ │ │ └── index.ts │ ├── voodoo-trade.ts │ ├── votre/ │ │ └── index.ts │ ├── walrus.ts │ ├── waterneuron.ts │ ├── waves/ │ │ └── index.ts │ ├── wavex/ │ │ └── index.ts │ ├── wbtc/ │ │ └── index.ts │ ├── wedefin.ts │ ├── welephant/ │ │ └── index.ts │ ├── wen-markets.ts │ ├── wigoswap.ts │ ├── wildcat.ts │ ├── wingriders/ │ │ └── index.ts │ ├── wisdomtree/ │ │ └── index.ts │ ├── wise-lending-v2/ │ │ └── index.ts │ ├── witty/ │ │ └── index.ts │ ├── woofi.ts │ ├── worldle/ │ │ └── index.ts │ ├── worm-wtf/ │ │ └── index.ts │ ├── wormhole/ │ │ └── index.ts │ ├── wrapped-hlp/ │ │ └── index.ts │ ├── x2y2.ts │ ├── xaue/ │ │ └── index.ts │ ├── xdc.ts │ ├── xdock-meme.ts │ ├── xeleb/ │ │ └── index.ts │ ├── xena-finance.ts │ ├── xlayer.ts │ ├── xmarket.ts │ ├── xrpl/ │ │ └── index.ts │ ├── xtrade-protocol.ts │ ├── y2k-v1.ts │ ├── y2k-v2.ts │ ├── yakafinance/ │ │ └── index.ts │ ├── yala/ │ │ └── index.ts │ ├── yamfore.ts │ ├── yearn-ether.ts │ ├── yearn-finance.ts │ ├── yeet-bgt-auction.ts │ ├── yfx-v3.ts │ ├── yfx-v4.ts │ ├── yield-basis/ │ │ └── index.ts │ ├── yield-yak-staked-avax.ts │ ├── yieldfi/ │ │ └── index.ts │ ├── yieldnest.ts │ ├── yo-protocol/ │ │ └── index.ts │ ├── yologames/ │ │ └── index.ts │ ├── yusan.ts │ ├── yuzu-finance.ts │ ├── zapfi/ │ │ └── index.ts │ ├── zapzy/ │ │ └── index.ts │ ├── zarban/ │ │ └── index.ts │ ├── zcash/ │ │ └── index.ts │ ├── zeebu/ │ │ └── index.ts │ ├── zenland/ │ │ └── index.ts │ ├── zeno.ts │ ├── zerion-wallet.ts │ ├── zircuit-staking/ │ │ └── index.ts │ ├── zivoe/ │ │ └── index.ts │ ├── zns/ │ │ └── index.ts │ ├── zo/ │ │ └── index.ts │ ├── zonic.ts │ ├── zoodotfun.ts │ ├── zora-sofi.ts │ ├── zora.ts │ ├── zunami/ │ │ └── index.ts │ ├── zyberswap-v2.ts │ ├── zyberswap-v3.ts │ └── zyfai.ts ├── helpers/ │ ├── GUIDELINES.md │ ├── aave/ │ │ ├── abi.ts │ │ ├── helper.ts │ │ └── index.ts │ ├── aggregators/ │ │ ├── bungee.ts │ │ ├── dzap.ts │ │ ├── haiku.ts │ │ └── lifi.ts │ ├── allium.ts │ ├── alliumDex.ts │ ├── aptos.ts │ ├── attestations-stablecoins.ts │ ├── balancer.ts │ ├── bitqueryFees.ts │ ├── blockscoutFees.ts │ ├── cache.ts │ ├── cardano.ts │ ├── chains.ts │ ├── coinbase-commerce.ts │ ├── compoundV2.ts │ ├── coreAssets.json │ ├── crypto-card.ts │ ├── curators/ │ │ ├── configs.ts │ │ └── index.ts │ ├── curve/ │ │ ├── helpers.ts │ │ └── index.ts │ ├── dune.ts │ ├── duneSolanaDex.ts │ ├── env.ts │ ├── erc4626.ts │ ├── ethereum-builder.ts │ ├── ethereum-l2.ts │ ├── etherscanFees.ts │ ├── extended-exchange.ts │ ├── fraxlend.ts │ ├── friend-tech.ts │ ├── getBlock.ts │ ├── getChainFees.ts │ ├── getTxReceipts.ts │ ├── getUniSubgraph/ │ │ ├── index.ts │ │ └── utils.ts │ ├── getUniSubgraphVolume.ts │ ├── gmx.ts │ ├── hyperliquid.ts │ ├── indexer.ts │ ├── joe.ts │ ├── liquity.ts │ ├── lists.ts │ ├── metrics.ts │ ├── neony.ts │ ├── orderly.ts │ ├── polymarket.ts │ ├── pool.ts │ ├── prices.ts │ ├── queries/ │ │ ├── bags.sql │ │ ├── bitget-wallet-card.sql │ │ ├── bob-blockchain.sql │ │ ├── conveyor.sql │ │ ├── cow-protocol.sql │ │ ├── dbc-config.sql │ │ ├── dbc.sql │ │ ├── definitive.sql │ │ ├── drift-protocol.sql │ │ ├── eulerswap.sql │ │ ├── exa-card.sql │ │ ├── flashbots.sql │ │ ├── futarchy.sql │ │ ├── jito.sql │ │ ├── jupiter-lend.sql │ │ ├── jupiter-perpetual-oi.sql │ │ ├── jupiter-perpetual.sql │ │ ├── kyros.sql │ │ ├── sol-lst.sql │ │ ├── stader.sql │ │ └── virtual-protocol.sql │ ├── readableStartTimestamp.js │ ├── ripple.ts │ ├── saddle.ts │ ├── solana.ts │ ├── solidly.ts │ ├── subscanFees.ts │ ├── sui.ts │ ├── symmio.ts │ ├── time-fun.ts │ ├── token.ts │ ├── tonLst.ts │ ├── tristeroMargin.ts │ ├── uniswap.ts │ ├── useTokenLabels.js │ └── utils/ │ ├── findClosest.ts │ └── index.ts ├── incentives/ │ ├── GUIDELINES.md │ └── bitcoin/ │ └── index.ts ├── normalized-volume/ │ └── .gitkeep ├── open-interest/ │ ├── 01-xyz.ts │ ├── GUIDELINES.md │ ├── aevo-options-oi.ts │ ├── aevo-perps-oi.ts │ ├── aftermath-fi-perp.ts │ ├── antarctic-oi.ts │ ├── apollox.ts │ ├── astro-perp-oi.ts │ ├── boros-oi.ts │ ├── bounce-tech-oi.ts │ ├── bullet.ts │ ├── capybara-perp.ts │ ├── challenge4trading-perp.ts │ ├── dango-oi.ts │ ├── defx.ts │ ├── denaria.ts │ ├── derive-options.ts │ ├── drift-trade.ts │ ├── edgeX.ts │ ├── ethereal-oi.ts │ ├── evedex.ts │ ├── flashtrade-oi.ts │ ├── gameclub.ts │ ├── gmtrade-oi.ts │ ├── gmx-v2-gmx-v2-trade.ts │ ├── hibachi.ts │ ├── holdstation-defutures-oi.ts │ ├── hotstuff-oi.ts │ ├── hyperliquid-perp-oi.ts │ ├── injective-derivatives.ts │ ├── jupiter-perpetual-oi.ts │ ├── leverup-oi.ts │ ├── lighter-v2.ts │ ├── lyra-v2.ts │ ├── monday-trade-perp-oi.ts │ ├── myx-finance.ts │ ├── nado.ts │ ├── neony.ts │ ├── opinion-oi.ts │ ├── orderly-perps-oi.ts │ ├── pacifica-oi.ts │ ├── paradex.ts │ ├── perpl.ts │ ├── perptools-perp-oi.ts │ ├── phoenix-trade-oi.ts │ ├── pika-v4.ts │ ├── polymarket-oi.ts │ ├── polymarket-us-oi.ts │ ├── reya-dex-oi.ts │ ├── rho-trading.ts │ ├── risex-perps-oi.ts │ ├── rocket-oi.ts │ ├── satori-oi.ts │ ├── sodex-perps-oi.ts │ ├── standx.ts │ ├── sunperp-oi.ts │ ├── synfutures-v3.ts │ ├── synthetix-v3.ts │ ├── synthetix-v4.ts │ ├── synthetix.ts │ ├── tristero-margin.ts │ ├── txflow-perps-oi.ts │ └── vest-markets.ts ├── options/ │ ├── GUIDELINES.md │ ├── aevo/ │ │ └── index.ts │ ├── arrow-markets/ │ │ └── index.ts │ ├── dopex/ │ │ ├── clamm.ts │ │ └── index.ts │ ├── hegic/ │ │ ├── index.ts │ │ └── interfaces.ts │ ├── hypersurface/ │ │ └── index.ts │ ├── ithaca/ │ │ └── index.ts │ ├── ivx/ │ │ └── index.ts │ ├── jaspervault/ │ │ └── index.ts │ ├── kyan.ts │ ├── lyra-v2/ │ │ └── index.ts │ ├── moby/ │ │ └── index.ts │ ├── optfun/ │ │ └── index.ts │ ├── optionBlitz/ │ │ └── index.ts │ ├── opyn/ │ │ └── index.ts │ ├── pancakeswap-options/ │ │ └── index.ts │ ├── paradex/ │ │ └── index.ts │ ├── premia-v2.ts │ ├── premia-v3.ts │ ├── rysk-finance/ │ │ └── index.ts │ ├── rysk-v12/ │ │ └── index.ts │ ├── sofa-org/ │ │ └── index.ts │ ├── tigris/ │ │ └── index.ts │ ├── ton-hedge.ts │ ├── toros/ │ │ └── index.ts │ ├── typus/ │ │ ├── getChainData.ts │ │ └── index.ts │ └── valorem/ │ └── index.ts ├── package.json ├── pnpm-workspace.yaml ├── pull_request_template.md ├── skills/ │ └── adapter-author/ │ ├── SKILL.md │ └── references/ │ ├── intake.md │ ├── patterns.md │ └── validation.md ├── tsconfig.cli.json ├── tsconfig.json ├── users/ │ ├── chains.ts │ ├── compound-v2/ │ │ └── index.ts │ ├── list.ts │ ├── routers/ │ │ ├── index.ts │ │ └── routerAddresses.ts │ └── utils/ │ ├── convertChain.ts │ ├── countUsers.ts │ └── types.ts └── utils/ ├── date.ts ├── deleteRedundantFiles.ts ├── fetchURL.ts ├── prices.ts └── utils.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .coderabbit.yaml ================================================ # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json language: "en-US" early_access: true reviews: profile: "assertive" request_changes_workflow: true high_level_summary: true high_level_summary_in_walkthrough: true poem: false review_status: true collapse_walkthrough: false sequence_diagrams: true changed_files_summary: true estimate_code_review_effort: true assess_linked_issues: true related_issues: true related_prs: true suggested_labels: true auto_apply_labels: true suggested_reviewers: true auto_review: enabled: true drafts: false base_branches: - master # Pre-merge checks (Pro feature) pre_merge_checks: docstrings: mode: "warning" threshold: 50 title: mode: "warning" requirements: "Title should be descriptive and follow format: [type] protocol-name - description" description: mode: "warning" custom_checks: - name: "Breakdown Methodology Check" mode: "warning" instructions: "For fees adapters: verify that all breakdown labels used in .add() calls have corresponding entries in breakdownMethodology object. Check that breakdownMethodology is exported in the adapter." - name: "Income Statement Compliance" mode: "warning" instructions: "For fees adapters: verify dailyFees represents Gross Protocol Revenue (all potential fees), dailyRevenue represents Gross Profit (protocol's portion), and dailySupplySideRevenue represents Cost of Funds (supplier payments). Ensure dailyRevenue = dailyFees - dailySupplySideRevenue conceptually." - name: "Version 2 Required" mode: "warning" instructions: "New adapters must use version: 2 format. Check that the adapter exports version: 2 unless it's updating an existing v1 adapter." # Finishing touches (Pro feature) finishing_touches: docstrings: enabled: true unit_tests: enabled: false simplify: enabled: true # Path-specific review instructions path_instructions: - path: "fees/**" instructions: | Review fees adapters for: - Correct income statement mapping (dailyFees = Gross Protocol Revenue, dailyRevenue = Gross Profit, dailySupplySideRevenue = Cost of Funds) - All breakdown labels must have corresponding breakdownMethodology entries - Labels should be descriptive (not vague like "Protocol Fees" or "Other") - dailySupplySideRevenue required when protocol pays suppliers (LPs, lenders, stakers, integrators, referrers) - Block rewards are incentives NOT fees - Use web search to verify protocol's fee structure if unclear - path: "dexs/**" instructions: | Review DEX adapters for: - Volume calculation accuracy - For perpetuals: ONLY track taker volume (do NOT double-count maker+taker) - Wash trading concerns on low-fee chains - If fees are tracked, verify income statement compliance (see fees/ guidelines) - Use helper functions when available (uniV2Exports, uniV3Exports) - path: "aggregators/**" instructions: | Review aggregator adapters for: - Volume should be routed volume, NOT double-counted with underlying DEX volume - Check for integration/partner fees as supply-side costs - If fees tracked, verify income statement compliance - path: "aggregator-derivatives/**" instructions: | Review derivatives aggregator adapters for: - ONLY track taker volume (no maker+taker double-counting) - Check open interest tracking if applicable - If fees tracked, verify income statement compliance - path: "aggregator-options/**" instructions: | Review options aggregator adapters for: - Both dailyNotionalVolume and dailyPremiumVolume required - Ensure routed options volume is not double-counted with underlying protocols - If fees tracked, verify income statement compliance - path: "bridge-aggregators/**" instructions: | Review bridge aggregator adapters for: - Track routed bridge volume only (dailyBridgeVolume) - Avoid double-counting with underlying bridge protocols - Verify multi-chain transfer accounting consistency - If fees tracked, verify income statement compliance - path: "options/**" instructions: | Review options adapters for: - Both dailyNotionalVolume and dailyPremiumVolume required - Don't confuse notional vs premium volume - If fees tracked, verify income statement compliance - path: "incentives/**" instructions: | Review incentives adapters for: - Block rewards and emissions classified as incentives, not fees - dailyTokenIncentives required; dailyIncentives when applicable - No double-counting with fees adapters - path: "helpers/**" instructions: | Review helper code for: - Reusability across multiple adapters - Proper TypeScript types - No npm dependencies allowed - Use api.multiCall for batching, not Promise.all # Labeling suggestions labeling_instructions: - label: "fees" instructions: "Apply when PR changes files in fees/ directory" - label: "dexs" instructions: "Apply when PR changes files in dexs/ directory" - label: "aggregators" instructions: "Apply when PR changes files in aggregators/ directory" - label: "new-adapter" instructions: "Apply when PR adds a new adapter file that didn't exist before" - label: "methodology" instructions: "Apply when PR changes fee/revenue calculation methodology or breakdownMethodology" - label: "helper" instructions: "Apply when PR changes files in helpers/ directory" - label: "bug-fix" instructions: "Apply when PR fixes a bug in existing adapter" # Tools for linting tools: biome: enabled: true eslint: enabled: true github-checks: enabled: true timeout_ms: 300000 chat: auto_reply: true knowledge_base: web_search: enabled: true opt_out: false code_guidelines: enabled: true filePatterns: - "**/GUIDELINES.md" learnings: scope: global issues: scope: global pull_requests: scope: global ================================================ FILE: .github/CODEOWNERS ================================================ # Protect dependency and config files — require @g1nt0ki @0xngmi approval /.github/CODEOWNERS @g1nt0ki @0xngmi package.json @g1nt0ki @0xngmi pnpm-lock.yaml @g1nt0ki @0xngmi pnpm-workspace.yaml @g1nt0ki @0xngmi ================================================ FILE: .github/workflows/build-modules-and-alert.yml ================================================ name: Build dimensionModules and alert unlisted projects on: push: branches: [ "master" ] jobs: build-and-upload: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - uses: pnpm/action-setup@v4 name: Install pnpm with: version: 10 run_install: false - name: Install Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'pnpm' - name: Install dependencies run: pnpm install - name: Run buildImports script run: pnpm run build - name: Publish dimensionModules.json as "latest" release uses: ncipollo/release-action@v1 with: tag: latest name: Latest dimensionModules artifacts: cli/dimensionModules.json allowUpdates: true alert-unlisted: needs: build-and-upload # waits for build-and-upload to succeed first runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Update unlisted run: | curl --fail https://born-to-llama.llama.fi/refresh-dimensions exit $? ================================================ FILE: .github/workflows/comment.yml ================================================ name: comment-pr on: workflow_run: workflows: ["test-adapter"] types: [completed] permissions: pull-requests: write actions: read jobs: comment: runs-on: ubuntu-latest # We don't gate on conclusion because the test workflow intentionally exits # non-zero when an adapter errors, and we still want to post the error comment. steps: - name: Download PR comments artifact id: download uses: actions/download-artifact@v4 with: name: pr-comments run-id: ${{ github.event.workflow_run.id }} github-token: ${{ secrets.GITHUB_TOKEN }} path: pr-comments continue-on-error: true - name: Post comments on PR if: steps.download.outcome == 'success' uses: actions/github-script@v7 with: script: | const fs = require('fs'); const path = require('path'); const dir = 'pr-comments'; if (!fs.existsSync(dir)) { core.info('No pr-comments directory, nothing to post.'); return; } const prNumberPath = path.join(dir, 'pr-number.txt'); if (!fs.existsSync(prNumberPath)) { core.info('No pr-number.txt, nothing to post.'); return; } const prNumber = Number(fs.readFileSync(prNumberPath, 'utf8').trim()); if (!Number.isInteger(prNumber) || prNumber <= 0) { core.setFailed(`Invalid PR number in artifact: ${prNumber}`); return; } const files = fs.readdirSync(dir) .filter(f => f.endsWith('.md')) .sort(); for (const f of files) { const body = fs.readFileSync(path.join(dir, f), 'utf8'); if (!body.trim()) continue; await github.rest.issues.createComment({ issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, body, }); } ================================================ FILE: .github/workflows/commentResult.js ================================================ const { readFileSync, writeFileSync, mkdirSync } = require('fs'); const path = require('path'); function main() { const [, , log, outDir, adapterNameKey] = process.argv; const file = readFileSync(log, 'utf-8'); const [, adapterName] = (adapterNameKey || '').split('@'); const errorString = 'ERROR'; const summaryIndex = file.indexOf('---------------------------------------------------'); const errorIndex = file.indexOf(errorString); let body; if (summaryIndex != -1) { body = `The ${adapterName} adapter exports: \n \n ${file.replaceAll('\n', '\n ')}`; } else if (errorIndex != -1) { body = `Error while running adapter ${adapterName} adapter: \n \n ${file.split(errorString)[1].replaceAll('\n', '\n ')}`; } else { console.info(`No error or summary found in log file`); return; } console.info(`Preparing comment:\n${body}`); mkdirSync(outDir, { recursive: true }); const safeName = (adapterNameKey || 'general').replace(/[^a-zA-Z0-9._-]/g, '_'); const fileName = `${Date.now()}-${process.pid}-${safeName}.md`; writeFileSync(path.join(outDir, fileName), body); } main(); ================================================ FILE: .github/workflows/getFileList.js ================================================ const ALLOWED_ROOTS = ['volumes', 'dexs', 'options', 'derivatives', 'incentives', 'fees', 'options', 'protocols', 'aggregators','aggregator-derivatives','bridge-aggregators', 'open-interest'] const MODIFIED = parse(process.env.MODIFIED) const ADDED = parse(process.env.ADDED) const fileSet = new Set(); [...MODIFIED, ...ADDED].forEach(file => { // Skip markdown documentation files (e.g., GUIDELINES.md) if (file.endsWith('.md')) return; const [root, adapter] = file.split('/') if (ALLOWED_ROOTS.includes(root) && adapter !== undefined) fileSet.add(`${root}@${adapter}`) }) console.log(JSON.stringify([...fileSet])) function parse(data) { return data.replace('[', '').replace(']', '').split(',') } ================================================ FILE: .github/workflows/test-adapter.yml ================================================ name: test-adapter on: [pull_request] jobs: test: runs-on: ubuntu-latest steps: - id: file_changes uses: trilom/file-changes-action@ce38c8ce2459ca3c303415eec8cb0409857b4272 with: output: 'json' fileOutput: 'json' - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - uses: pnpm/action-setup@v4 name: Install pnpm with: version: 10 run_install: false - name: Install Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'pnpm' - name: Install dependencies run: pnpm install - name: Record PR number run: | mkdir -p pr-comments echo "${{ github.event.number }}" > pr-comments/pr-number.txt - name: Run changes files through test script run: | # Store the current commit hash in a variable current_commit=$(git rev-parse HEAD) # Checkout to master to check if new adapters files are of v2 git fetch origin master:master # Checkout back to the original commit git checkout $current_commit RUN_FILES=$( MODIFIED=${{ steps.file_changes.outputs.files_modified}} \ ADDED=${{ steps.file_changes.outputs.files_added}} \ node ${{ github.workspace }}/.github/workflows/getFileList.js ) if [ "$RUN_FILES" = "[]" ]; then echo "No adapter files were modified" exit 0 fi list=$(echo $RUN_FILES | tr -d '"[]' | tr "," "\n") for i in ${list} do { IFS='@' read -r -a array <<< "$i" npm run test ${array[0]} ${array[1]} 2>&1 | tee output.txt node ${{ github.workspace }}/.github/workflows/commentResult.js ${{ github.workspace }}/output.txt ${{ github.workspace }}/pr-comments ${i} if grep -q "\-\-\-\- ERROR \-\-\-\-" output.txt; then exit 1; fi } || { echo -n $i echo ' doesnt run' } done - name: Upload PR comments artifact if: always() uses: actions/upload-artifact@v4 with: name: pr-comments path: pr-comments/ if-no-files-found: ignore retention-days: 1 ================================================ FILE: .github/workflows/ts-check.yml ================================================ name: Check ts on: [pull_request] jobs: ts-check: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - uses: pnpm/action-setup@v4 name: Install pnpm with: version: 10 run_install: false - name: Install Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'pnpm' - name: Install dependencies run: pnpm install - name: Checking adapters run: pnpm run ts-check - name: Checking cli run: pnpm run ts-check-cli ================================================ FILE: .gitignore ================================================ node_modules .vscode .DS_store .env .idea yarn.lock test.py test.js cli/dimensionModules.json wash/ *.log .claude CLAUDE.md ================================================ FILE: GUIDELINES.md ================================================ # DefiLlama Dimension Adapters - Global Guidelines These guidelines apply to ALL adapters in this repository. ## PR Description - Always provide Website and twitter links in the description ## Code Structure - Use on-chain data/event logs where possible. We are stricter about on-chain for chains where we maintain our own indexer, or where there is significant volume/fees, or where you suspect wash trading - Use `pullHourly: true`, wherever evm logs and allium queries are used to avoid recomputing data for the same time period and provide more granular data - Never swallow errors silently. For recoverable chain-specific failures, return 0 and log the error so the adapter continues for other chains. For system-level or critical errors, throw/propagate to fail fast - Use/add helper code when multiple adapters use similar logic - check `helpers/` folder first - Do NOT add npm dependencies - this leads to bloat - Use `api.multiCall` where possible, avoid `Promise.all`. Use PromisePool for non-EVM calls - Return token breakdown where possible - always include `methodology` and `breakdownMethodology` ## Adapter Version | | Version 2 | Version 1 | |---|---|---| | **Use when** | On-chain logs, contract calls, subgraphs, Dune queries with timestamp filters | External API that only returns daily aggregates | | **Fetch signature** | `(options: FetchOptions)` | `(timestamp, chainBlocks, options)` | | **Time range** | Arbitrary start/end timestamps | Fixed day (00:00–23:59 UTC) | | **`pullHourly`** | Supported | Not supported | | **Preference** | Always prefer this | Use only when v2 is not possible | ## Core Dimensions by Dashboard ### DEXs and DEX Aggregators | Dimension | Required | Description | |-----------|----------|-------------| | `dailyVolume` | YES | Trading volume for the period | ### Derivatives and Aggregator-Derivatives | Dimension | Required | Description | |-----------|----------|-------------| | `dailyVolume` | YES | Perpetual trading volume (TAKER volume only, do NOT double-count maker+taker) | | `openInterestAtEnd` | Optional | Open interest at period end | | `longOpenInterestAtEnd` | Optional | Long positions open interest | | `shortOpenInterestAtEnd` | Optional | Short positions open interest | ### Bridge Aggregators | Dimension | Required | Description | |-----------|----------|-------------| | `dailyBridgeVolume` | YES | Bridge volume for the period | ### Options | Dimension | Required | Description | |-----------|----------|-------------| | `dailyNotionalVolume` | YES | Notional volume of options contracts | | `dailyPremiumVolume` | YES | Premium volume collected/paid | | `openInterestAtEnd` | Optional | Open interest at period end | ### Fees (Income Statement Model) | Dimension | Required | Description | |-----------|----------|-------------| | `dailyFees` | YES | All fees from ALL sources (Gross Protocol Revenue) - everything protocol could theoretically keep if it took 100% | | `dailyRevenue` | YES | Portion kept by protocol (Gross Profit = dailyFees - dailySupplySideRevenue) | | `dailySupplySideRevenue` | When applicable | Portion to LPs, lenders, stakers, integrators, referrers, creators (Cost of Revenue) | | `dailyUserFees` | Optional | Portion directly paid by end-users | | `dailyProtocolRevenue` | Optional | Portion allocated to treasury | | `dailyHoldersRevenue` | When applicable | All value to token holders (buybacks, burns, distributions, external airdrops, bribes) | ## Minimum Requirements for Listing - **Must provide** all required dimensions for the adapter category (see tables above) - **For fees adapters**: must provide accurate `dailyFees` and `dailyRevenue` - **Strongly encouraged**: `dailySupplySideRevenue` when protocol has supply-side costs - **Include when applicable**: `dailyHoldersRevenue` for protocols distributing to holders - **Always include**: breakdown labels and `breakdownMethodology` - **Deprecated**: `total*` cumulative dimensions - do not use ## Income Statement Mapping | Display Name | Code Field | |--------------|------------| | Gross Protocol Revenue | dailyFees | | Cost of Funds | dailySupplySideRevenue | | Gross Profit | dailyRevenue | | Tokenholder Income | dailyHoldersRevenue | ## Fee/Revenue Attribution by Protocol Type | Attribute | DEXs | Lending | Chains | NFT Marketplace | Derivatives | CDP | Liquid Staking | Yield | |-----------|------|---------|--------|-----------------|-------------|-----|----------------|-------| | Fees | Swap fees | Borrow interest | Gas fees | Trading fees | Trading fees + mint/burn | Borrow fees | Staking rewards | Yield | | SupplySideRevenue | LP revenue | Interest to lenders | Sequencer costs, blob fees | Creator earnings | LP revenue, rebates | N/A | Rewards to stakers | Yield minus fees | | Revenue | Protocol's % | Protocol's % | Burned fees | Marketplace rev | Protocol's % | Protocol's % | Protocol fee % | Protocol fees | | HoldersRevenue | Token distributions | N/A | N/A | N/A | Staker distributions | N/A | N/A | N/A | **Notes:** - `Revenue = Fees - SupplySideRevenue` - `Revenue = HoldersRevenue + ProtocolRevenue` - For chains: only track transaction fees paid by users. Perp DEX fees (e.g., Hyperliquid L1) are tracked under the perp adapter, not chain adapter ## Breakdown Labels - ALWAYS provide labels even when there is only one source/destination of fees - Labels prevent needing to update and backfill data when adapter is listed under a parent protocol - `dailyFees`: Use source-of-fees labels (e.g., 'Swap Fees', 'Borrow Interest') - `dailyRevenue`/`dailySupplySideRevenue`/`dailyHoldersRevenue`: Use detailed destination labels (e.g., 'Swap Fees To LPs', 'Borrow Interest To Treasury') **Every label used in `.add()` calls MUST appear in `breakdownMethodology`**, and every label in `breakdownMethodology` must have corresponding data in code. ## Deprecated Fields - `dailyBribesRevenue` and `dailyTokenTaxes` are deprecated; put these as sub-sections within `dailyHoldersRevenue` instead ## Data Classification Rules - **Fees**: Only fees paid by users for transactions should be tracked as fees. Block rewards are incentives, NOT fees - **Revenue**: Only the portion that gets burnt or goes to protocol treasury. Staker payments are NOT revenue - **Holder Revenue**: Same as revenue unless portion is set aside for protocol - **Chain Fees**: Track only transaction fees paid by users (no perp DEX fees for chains like Hyperliquid L1) ## Guiding Principle 'Gross Protocol Revenue' (dailyFees) should include everything the protocol COULD charge if it became maximally greedy. Example: For Aave, if depositors get 70% and protocol gets 30% of borrow fees, dailyFees includes 100% because protocol could theoretically take it all. ## Watch For - Wash trading - be vigilant especially on low-fee chains - Incorrect fee/revenue classification - Missing breakdown labels - Hardcoded values that should be dynamic - Double-counting (e.g., both taker and maker volume in perps) ================================================ FILE: README.md ================================================ # Adapters Find the instructions to list, write, test and submit an adapter [here](https://docs.llama.fi/list-your-project/other-dashboards) ## Install dependencies `pnpm i` ## test adapter commands `pnpm test fees bitcoin` `pnpm test fees bitcoin 2025-10-10` ## Adding custom RPC URLs Create an `.env` file and add custom RPC URLs using the `{CHAIN}_RPC` format (use uppercase chain name): ``` ETHEREUM_RPC="https://yourcustomrpc.com" ``` ================================================ FILE: active-users/aptos.ts ================================================ import { Dependencies, SimpleAdapter, ProtocolType, FetchOptions } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { queryAllium } from "../helpers/allium"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const start = new Date(options.fromTimestamp * 1000).toISOString() const end = new Date(options.toTimestamp * 1000).toISOString() const alliumQuery = ` SELECT COALESCE(count(distinct sender), 0) as user_count, COALESCE(count(*), 0) as transaction_count FROM aptos.raw.transactions where block_timestamp BETWEEN '${start}' AND '${end}' `; const alliumResult = await queryAllium(alliumQuery); return { dailyActiveUsers: alliumResult[0].user_count, dailyTransactionsCount: alliumResult[0].transaction_count, } } const adapter: SimpleAdapter = { version: 1, fetch, chains: [CHAIN.APTOS], dependencies: [Dependencies.ALLIUM], isExpensiveAdapter: true, protocolType: ProtocolType.CHAIN, start: "2022-10-20", }; export default adapter; ================================================ FILE: active-users/kyan.ts ================================================ import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { httpGet } from "../utils/fetchURL"; const API_URL = "https://production.kyan.sh/api/v1/defillama/overview"; const ONE_DAY = 24 * 60 * 60; const fetch = async () => { const data = await httpGet(API_URL); const now = Math.floor(Date.now() / 1000); if (Math.abs(now - data.timestamp) > ONE_DAY) throw new Error("Kyan API data is stale (older than 24h)"); return { dailyActiveUsers: data.activity.unique_traders, }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.ARBITRUM]: { fetch, start: "2025-04-25", runAtCurrTime: true, }, }, }; export default adapter; ================================================ FILE: active-users/sui.ts ================================================ import { Dependencies, SimpleAdapter, ProtocolType, FetchOptions } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { queryAllium } from "../helpers/allium"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const start = new Date(options.fromTimestamp * 1000).toISOString() const end = new Date(options.toTimestamp * 1000).toISOString() const alliumQuery = ` SELECT COALESCE(count(distinct sender), 0) as user_count, COALESCE(sum(transactions_count), 0) as total_transaction_count FROM sui.raw.transaction_blocks where checkpoint_timestamp BETWEEN '${start}' AND '${end}' `; const alliumResult = await queryAllium(alliumQuery); return { dailyActiveUsers: alliumResult[0].user_count, dailyTransactionsCount: alliumResult[0].total_transaction_count, } } const adapter: SimpleAdapter = { version: 1, fetch, chains: [CHAIN.SUI], dependencies: [Dependencies.ALLIUM], isExpensiveAdapter: true, protocolType: ProtocolType.CHAIN, start: "2023-04-12", }; export default adapter; ================================================ FILE: adapters/types.ts ================================================ import { Balances, ChainApi, util } from '@defillama/sdk'; import sdk from '@defillama/sdk'; export type Chain = string const { blocks: { getChainBlocks } } = util export type ChainBlocks = Awaited> export type ChainEndpoints = { [chain: string]: string } export type FetchResultBase = { timestamp?: number; block?: number; }; export type FetchResultV2 = { [key: string]: FetchResponseValue | undefined; }; export type FetchResultGeneric = FetchResultBase & { [key: string]: FetchResponseValue | undefined; } export type FetchOptions = { createBalances: () => Balances; getBlock: (timestamp: number, chain: string, chainBlocks: ChainBlocks) => Promise; getLogs: (params: FetchGetLogsOptions) => Promise; streamLogs: (params: Parameters[0] & { targetsFilter?: string[] | Set }) => Promise; toTimestamp: number; fromTimestamp: number; startOfDay: number; getFromBlock: () => Promise; getToBlock: () => Promise; chain: string, api: ChainApi, fromApi: ChainApi, toApi: ChainApi, startTimestamp: number, endTimestamp: number, getStartBlock: () => Promise, getEndBlock: () => Promise, dateString: string, preFetchedResults?: any, moduleUID: string, // randomly generated unique identifier for the module, useful for caching (used only for batch processing dune queries for now) startOfDayId?: string, // id used in some subgraphs to identify daily data, usually it's the startOfDay timestamp divided by 86400 metadata?: { [key: string]: any adapterType?: string protocolName?: string name?: string id?: string runType?: string isHourlyAdapter?: boolean } } export type FetchGetLogsOptions = { eventAbi?: string, topic?: string, target?: string, targets?: string[], onlyArgs?: boolean, fromBlock?: number, toBlock?: number, flatten?: boolean, cacheInCloud?: boolean, entireLog?: boolean, skipCacheRead?: boolean, skipCache?: boolean, skipIndexer?: boolean, topics?: string[], noTarget?: boolean, parseLog?: boolean, } export type Fetch = ( timestamp: number, chainBlocks: ChainBlocks, options: FetchOptions, ) => Promise; export type FetchV2 = ( options: FetchOptions, ) => Promise; export type IStartTimestamp = () => Promise export type BaseAdapterChainConfig = { start?: IStartTimestamp | number | string; // date can be in "YYYY-MM-DD" format - indicates when the adapter can start fetching data deadFrom?: IStartTimestamp | number | string; // date can be in "YYYY-MM-DD" format - indicates when the adapter should stop fetching data fetch?: Fetch | FetchV2; runAtCurrTime?: boolean; } export const whitelistedBaseAdapterKeys = new Set([ 'start', 'deadFrom', 'fetch', 'runAtCurrTime' ]) export type BaseAdapter = { [chain: string]: BaseAdapterChainConfig }; export enum ProtocolType { CHAIN = 'chain', PROTOCOL = 'protocol', COLLECTION = 'collection', } export enum Dependencies { DUNE = 'dune', ALLIUM = 'allium' } export type AdapterBase = { timetravel?: boolean isExpensiveAdapter?: boolean, dependencies?: Dependencies[] protocolType?: ProtocolType; version?: number; deadFrom?: string; allowNegativeValue?: boolean; doublecounted?: boolean; methodology?: string | IJSON; breakdownMethodology?: Record>; fetch?: Fetch | FetchV2; chains?: (string | [string, BaseAdapterChainConfig])[] prefetch?: FetchV2; runAtCurrTime?: boolean; start?: IStartTimestamp | number | string; // date can be in "YYYY-MM-DD" format _randomUID?: string; // sometimes fee & volume adapters share the same code, we can optimize the run by caching the results - We stopped caching these results but left as is as it is used in batching dune queries, we can re-use it later if needed pullHourly?: boolean; skipBreakdownValidation?: boolean; // this is to skip the validation that requires at least one of dailyRevenue, dailySupplySideRevenue or dailyProtocolRevenue to be present when dailyFees is present, this is useful for some adapters that have a breakdown in their dailyFees but dont have a clear way to attribute the fees to either supply side or protocol revenue } export type SimpleAdapter = AdapterBase & { adapter?: BaseAdapter } export type Adapter = SimpleAdapter; export type FetchResponseValue = string | number | Balances; /** * Include here new adaptors types */ // VOLUME export type FetchResultVolume = FetchResultBase & { dailyVolume?: FetchResponseValue shortOpenInterestAtEnd?: FetchResponseValue longOpenInterestAtEnd?: FetchResponseValue openInterestAtEnd?: FetchResponseValue dailyBridgeVolume?: FetchResponseValue dailyNormalizedVolume?: FetchResponseValue dailyActiveLiquidity?: FetchResponseValue }; // FEES export type FetchResultFees = FetchResultBase & { dailyFees?: FetchResponseValue; dailyUserFees?: FetchResponseValue; dailyRevenue?: FetchResponseValue; dailyProtocolRevenue?: FetchResponseValue; dailyHoldersRevenue?: FetchResponseValue; dailySupplySideRevenue?: FetchResponseValue; dailyBribesRevenue?: FetchResponseValue; dailyTokenTaxes?: FetchResponseValue; dailyOtherIncome?: FetchResponseValue; dailyOperatingIncome?: FetchResponseValue; dailyNetIncome?: FetchResponseValue; }; // INCENTIVES export type FetchResultIncentives = FetchResultBase & { tokenIncentives?: FetchResponseValue }; // AGGREGATORS export type FetchResultAggregators = FetchResultBase & { dailyVolume?: FetchResponseValue }; export type FetchResultActiveUsers = FetchResultBase & { dailyActiveUsers?: FetchResponseValue; dailyTransactionsCount?: FetchResponseValue; dailyGasUsed?: FetchResponseValue; }; export type FetchResultNewUsers = FetchResultBase & { dailyNewUsers?: FetchResponseValue; }; // OPTIONS export type FetchResultOptions = FetchResultBase & { dailyPremiumVolume?: FetchResponseValue dailyNotionalVolume?: FetchResponseValue shortOpenInterestAtEnd?: FetchResponseValue longOpenInterestAtEnd?: FetchResponseValue openInterestAtEnd?: FetchResponseValue }; export enum AdapterType { FEES = 'fees', DEXS = 'dexs', INCENTIVES = 'incentives', AGGREGATORS = 'aggregators', DERIVATIVES = 'derivatives', OPTIONS = 'options', PROTOCOLS = 'protocols', OPEN_INTEREST = 'open-interest', // ROYALTIES = 'royalties', AGGREGATOR_DERIVATIVES = 'aggregator-derivatives', BRIDGE_AGGREGATORS = 'bridge-aggregators', NORMALIZED_VOLUME = 'normalized-volume', NFT_VOLUME = 'nft-volume', ACTIVE_USERS = 'active-users', NEW_USERS = 'new-users', } export type FetchResult = FetchResultVolume & FetchResultFees & FetchResultAggregators & FetchResultOptions & FetchResultIncentives & FetchResultActiveUsers & FetchResultNewUsers export const whitelistedDimensionKeys = new Set([ 'startTimestamp', 'chain', 'timestamp', 'block', 'dailyVolume', 'shortOpenInterestAtEnd', 'longOpenInterestAtEnd', 'openInterestAtEnd', 'dailyBridgeVolume', 'dailyNormalizedVolume', 'dailyActiveLiquidity', 'totalFees', 'dailyFees', 'dailyUserFees', 'dailyRevenue', 'dailyProtocolRevenue', 'dailyHoldersRevenue', 'dailySupplySideRevenue', 'dailyBribesRevenue', 'dailyTokenTaxes', 'tokenIncentives', 'dailyOtherIncome', 'dailyOperatingIncome', 'dailyNetIncome',, 'dailyPremiumVolume', 'dailyNotionalVolume', 'dailyActiveUsers', 'dailyNewUsers', 'dailyTransactionsCount', 'dailyGasUsed', ]) export const accumulativeKeySet = new Set([ 'totalVolume', 'totalBridgeVolume', 'tokenIncentives', 'totalPremiumVolume', 'totalNotionalVolume', 'totalFees', 'totalRevenue', 'totalProtocolRevenue', 'totalSupplySideRevenue', 'totalUserFees', 'totalHoldersRevenue', 'totalOtherIncome', 'totalOperatingIncome', 'totalNetIncome' ]) // End of specific adaptors type export interface IJSON { [key: string]: T } export const ADAPTER_TYPES = Object.values(AdapterType).filter((adapterType: any) => adapterType !== AdapterType.PROTOCOLS) ================================================ FILE: adapters/utils/importAdapter.ts ================================================ import { getAdapterFromHelpers, listHelperProtocols } from "../../factory/registry"; import { SimpleAdapter } from "../types"; export interface ImportAdapterResult { adapter: SimpleAdapter; source: 'file' | 'factory'; factoryName?: string; } /** * Import an adapter by trying file-based lookup first, then factory registry * @param adapterType - The adapter type (e.g., 'fees', 'dexs', 'normalized-volume') * @param protocolName - The protocol name * @param filePath - The file path to try importing from (relative to project root) * @returns ImportAdapterResult with adapter and source information * @throws Error if adapter is not found */ export async function importAdapter( adapterType: string, protocolName: string, filePath: string ): Promise { try { // Try to import the individual file first const adapterModule = (await import(filePath)).default; return { adapter: adapterModule, source: 'file' }; } catch (error) { // File doesn't exist, try to find it in factory registry const result = getAdapterFromHelpers(adapterType, protocolName); if (!result) { // Only show error if not found in registry either const errorMessage = `❌ Protocol "${protocolName}" not found in ${adapterType}/ or factory registry`; throw new Error(errorMessage); } return { adapter: result.adapter, source: 'factory', factoryName: result.factoryName }; } } ================================================ FILE: adapters/utils/runAdapter.ts ================================================ import * as sdk from '@defillama/sdk'; import { Balances, ChainApi, elastic, getEventLogs, getProvider } from '@defillama/sdk'; import * as _env from '../../helpers/env'; import { getBlock } from "../../helpers/getBlock"; import { getUniqStartOfTodayTimestamp } from '../../helpers/getUniSubgraphVolume'; import { getDateString } from '../../helpers/utils'; import { accumulativeKeySet, BaseAdapter, BaseAdapterChainConfig, ChainBlocks, Fetch, FetchGetLogsOptions, FetchOptions, FetchResponseValue, FetchV2, SimpleAdapter } from '../types'; import { CHAIN } from '../../helpers/chains'; // to trigger inclusion of the env.ts file const _include_env = _env.getEnv('BITLAYER_RPC') const ONE_DAY_IN_SECONDS = 60 * 60 * 24 function getUnixTimeNow() { return Math.floor(Date.now() / 1000) } function genUID(length: number = 10): string { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' let result = '' for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * characters.length)) } return result } function roundValue(value: any): number { const num = Number(value) const abs = Math.abs(num) if (abs < 1) return +num.toFixed(4) if (abs < 10) return +num.toFixed(2) return +num.toFixed(0) } // const adapterRunResponseCache = {} as any export async function setModuleDefaults(module: SimpleAdapter) { const { chains = [], fetch, start, runAtCurrTime } = module const rootConfig: any = {} if (fetch) rootConfig.fetch = fetch if (start) rootConfig.start = start if (runAtCurrTime) rootConfig.runAtCurrTime = runAtCurrTime if (!module._randomUID) module._randomUID = genUID(10) let adapterObject: BaseAdapter = module.adapter || {} module.adapter = adapterObject if (!module.version) module.version = 1 // default to version 1 module.runAtCurrTime = runAtCurrTime ?? Object.values(adapterObject).some((c: BaseAdapterChainConfig) => c.runAtCurrTime) if (!Array.isArray(chains)) throw new Error(`Chains should be an array, got ${typeof chains} instead`) Object.keys(adapterObject).filter(chain => !chains.includes(chain)).forEach(chain => chains.push(chain)) for (const cConfig of chains) { if (typeof cConfig === 'string') { setChainConfig(cConfig, rootConfig) } else if (Array.isArray(cConfig)) { const [chain, chainConfig] = cConfig if (typeof chain !== 'string' || typeof chainConfig !== 'object') throw new Error(`Invalid chain config: ${cConfig}`) setChainConfig(chain, { ...rootConfig, ...chainConfig }) } else { throw new Error(`Invalid chain config: ${cConfig}`) } } // check if chain already has a given field before setting it, so we dont end up overwriting it with defaults function setChainConfig(chain: string, config: BaseAdapterChainConfig) { if (!adapterObject[chain]) adapterObject[chain] = {} const chainConfigObject = adapterObject[chain] as BaseAdapterChainConfig for (const key of Object.keys(config)) { if (!chainConfigObject.hasOwnProperty(key)) (chainConfigObject as any)[key] = (config as any)[key] } } } export function isHourlyAdapter(module: SimpleAdapter) { const adapterVersion = module.version return adapterVersion === 2 && (module as any).pullHourly === true } export function isPlainDateArg(rawTimeArg?: string) { return !!rawTimeArg && /^\d{4}-\d{2}-\d{2}$/.test(rawTimeArg) } type AdapterRunOptions = { deadChains?: Set, // chains that are dead and should be skipped module: SimpleAdapter, endTimestamp: number, name?: string, isTest?: boolean, // we print run response to console in test mode withMetadata?: boolean, // if true, returns metadata with the response cacheResults?: boolean, // deprecated, if true, caches the results in adapterRunResponseCache runWindowInSeconds?: number, // time window for which the adapter should run, default is 1 day metadata?: { [key: string]: any adapterType?: string protocolName?: string name?: string id?: string runType?: string isHourlyAdapter?: boolean } } export default async function runAdapter(options: AdapterRunOptions) { const { module,} = options if (!module) throw new Error('Module is not set') setModuleDefaults(module) return _runAdapter(options) } const startOfDayIdCache: { [key: string]: string } = {} function getStartOfDayId(timestamp: number): string { if (!startOfDayIdCache[timestamp]) { startOfDayIdCache[timestamp] = '' + Math.floor(timestamp / 86400) } return startOfDayIdCache[timestamp] } async function _runAdapter({ module, endTimestamp, name, isTest = false, withMetadata = false, deadChains = new Set(), runWindowInSeconds = ONE_DAY_IN_SECONDS, metadata = {}, }: AdapterRunOptions) { const cleanCurrentDayTimestamp = endTimestamp const adapterVersion = module.version const moduleUID = module._randomUID // const isHourly = isHourlyAdapter(module) // const WINDOW_SECONDS = isHourly ? 60 * 60 : ONE_DAY_IN_SECONDS const WINDOW_SECONDS = runWindowInSeconds const chainBlocks: ChainBlocks = {} // we need it as it is used in the v1 adapters const { prefetch, allowNegativeValue = false, } = module let adapterObject = module.adapter if (!adapterObject) throw new Error('Adapter object is not set') if ((module as any).breakdown) throw new Error('Breakdown adapters are deprecated, migrate it to use simple adapter') const closeToCurrentTime = Math.trunc(Date.now() / 1000) - cleanCurrentDayTimestamp < 24 * 60 * 60 // 12 hours const chains = Object.keys(adapterObject) if (chains.some(c => !c) || chains.includes('undefined')) { throw new Error(`Invalid chain labels: ${chains.filter(c => !c || c === 'undefined').join(', ')}`) } const badChainNames = chains.filter(chain => !/^[a-z0-9_]+$/.test(chain)); if (badChainNames.length) { throw new Error(` Invalid chain names: ${badChainNames.join(', ')} Chain names should only contain lowercase letters, numbers and underscores `) } const validStart = {} as { [chain: string]: { canRun: boolean, startTimestamp: number endTimestamp?: number } } await Promise.all(chains.map(setChainValidStart)) // Run prefetch if provided let preFetchedResults: any = null; if (typeof prefetch === 'function') { const firstChain = chains.find(chain => validStart[chain]?.canRun); if (firstChain) { const options = await getOptionsObject({ timestamp: cleanCurrentDayTimestamp, chain: firstChain, chainBlocks, moduleUID, windowSize: WINDOW_SECONDS, }); preFetchedResults = await prefetch(options); } } const aggregated = {} as any let breakdownByToken: any = {} let breakdownByLabelByChain: any = {} let breakdownByLabel: any = {} const response = await Promise.all(chains.filter(chain => { const res = validStart[chain] if (isTest && !res.canRun) { if (res.endTimestamp) console.log(`Skipping ${chain} because the adapter ended at ${new Date(res.endTimestamp! * 1e3).toUTCString()} \n\n`) else console.log(`Skipping ${chain} because the configured start time is ${new Date(res.startTimestamp * 1e3).toUTCString()} \n\n`) } return validStart[chain]?.canRun && !deadChains.has(chain) }).map(getChainResult)) Object.entries(breakdownByToken).forEach(([chain, data]: any) => { if (typeof data !== 'object' || data === null || !Object.keys(data).length) delete breakdownByToken[chain] }) if (Object.keys(breakdownByToken).length === 0) breakdownByToken = undefined if (Object.keys(breakdownByLabel).length === 0) breakdownByLabel = undefined if (Object.keys(breakdownByLabelByChain).length === 0) breakdownByLabelByChain = undefined // if the special chain_global metric is present, it holds the aggregated value for the metric, so we move it to the value field and remove it from the chains object to avoid double counting in the aggregated value if (chains.includes(CHAIN.CHAIN_GLOBAL)) { Object.keys(aggregated).forEach(metricType => { const metricObject = aggregated[metricType] if (metricObject.chains[CHAIN.CHAIN_GLOBAL] !== undefined) { metricObject.value = metricObject.chains[CHAIN.CHAIN_GLOBAL] delete metricObject.chains[CHAIN.CHAIN_GLOBAL] } }) } const adaptorRecordV2JSON: any = { aggregated, breakdownByLabel, breakdownByLabelByChain, timestamp: response.find(i => i?.timestamp)?.timestamp } if (withMetadata) return { response, adaptorRecordV2JSON, breakdownByToken } return response async function getChainResult(chain: string) { const startTime = getUnixTimeNow() const metadata = { application: "dimensions", type: 'protocol-chain', name, chain, version: adapterVersion, } const fetchFunction = adapterObject![chain].fetch try { const options = await getOptionsObject({ timestamp: cleanCurrentDayTimestamp, chain, chainBlocks, moduleUID, windowSize: WINDOW_SECONDS, }) if (preFetchedResults !== null) { options.preFetchedResults = preFetchedResults; } let result: any if (adapterVersion === 1) { result = await (fetchFunction as Fetch)(options.toTimestamp, chainBlocks, options); } else if (adapterVersion === 2) { result = await (fetchFunction as FetchV2)(options); result.timestamp = options.toTimestamp } else { throw new Error(`Adapter version ${adapterVersion} not supported`) } const ignoreKeys = ['timestamp', 'block'] const improbableValue = 2e11 // 200 billion // validate and inject missing record if any validateAdapterResult(result, module) // add missing metrics if need addMissingMetrics(chain, result) for (const [recordType, value] of Object.entries(result)) { if (ignoreKeys.includes(recordType)) continue; if (value === undefined || value === null) { // dont store undefined or null values delete result[recordType] continue; } // if (value === undefined || value === null) throw new Error(`Value: ${value} ${recordType} is undefined or null`) if (value instanceof Balances) { const { labelBreakdown, usdTvl, usdTokenBalances, rawTokenBalances } = await value.getUSDJSONs() // if (usdTvl > 1e6) value.debug() result[recordType] = usdTvl breakdownByToken[chain] = breakdownByToken[chain] || {} breakdownByToken[chain][recordType] = { usdTvl, usdTokenBalances, rawTokenBalances } if (labelBreakdown) { if (!breakdownByLabel[recordType]) breakdownByLabel[recordType] = {} if (!breakdownByLabelByChain[recordType]) breakdownByLabelByChain[recordType] = {} const aggData = breakdownByLabel[recordType] const breakData = breakdownByLabelByChain[recordType] for (let [label, labelValue] of Object.entries(labelBreakdown)) { labelValue = roundValue(labelValue) aggData[label] = (aggData[label] || 0) + labelValue if (!breakData[label]) breakData[label] = {} breakData[label][chain] = labelValue } } } result[recordType] = roundValue(result[recordType]) if (!aggregated[recordType]) aggregated[recordType] = { value: 0, chains: {} } aggregated[recordType].value += result[recordType] aggregated[recordType].chains[chain] = result[recordType] let errorPartialString = `| ${chain}-${recordType}: ${value}` if (isNaN(result[recordType] as number)) throw new Error(`value is NaN ${errorPartialString}`) if (result[recordType] < 0 && !allowNegativeValue) throw new Error(`value is negative ${errorPartialString}`) if (result[recordType] > improbableValue) { let showError = accumulativeKeySet.has(recordType) ? result[recordType] > improbableValue * 10 : true if (showError) throw new Error(`value is too damn high ${errorPartialString}`) } } const endTime = getUnixTimeNow() await elastic.addRuntimeLog({ runtime: endTime - startTime, success: true, metadata, }) return { chain, startTimestamp: validStart[chain].startTimestamp, ...result } } catch (error) { const endTime = getUnixTimeNow() try { await elastic.addErrorLog({ error, metadata, errorString: error?.toString(), } as any) await elastic.addRuntimeLog({ runtime: endTime - startTime, success: false, metadata, }); (error as any).chain = chain } catch { } throw error } } async function getOptionsObject({ timestamp, chain, chainBlocks, windowSize = ONE_DAY_IN_SECONDS, moduleUID = genUID(10) }: { timestamp: number, chain: string, chainBlocks: ChainBlocks, windowSize?: number, moduleUID?: string }): Promise { const withinTwoHours = Math.trunc(Date.now() / 1000) - timestamp < 24 * 60 * 60 // 24 hours const createBalances: () => Balances = () => { let _chain = chain // workaround for mismatch in chain names between dimensions repo and rest of the codebase switch (chain) { case 'bitlayer': _chain = 'btr'; break; } return new Balances({ timestamp: closeToCurrentTime ? undefined : timestamp, chain: _chain }) } const toTimestamp = timestamp - 1 const fromTimestamp = toTimestamp - windowSize const getFromBlock = async () => await getBlock(fromTimestamp, chain) const getToBlock = async () => await getBlock(toTimestamp, chain, chainBlocks) const problematicChains = new Set(['sei',]) const getLogs = async ({ target, targets, onlyArgs = true, fromBlock, toBlock, flatten = true, eventAbi, topics, topic, cacheInCloud = false, skipCacheRead = false, entireLog = false, skipIndexer, noTarget, ...rest }: FetchGetLogsOptions) => { if (problematicChains.has(chain)) throw new Error(`getLogs is disabled for ${chain} chain due to frequent timeouts`) fromBlock = fromBlock ?? await getFromBlock() toBlock = toBlock ?? await getToBlock() const requestCount = targets ? targets.length : 1 if (api) api.addStat('logsRequests', requestCount) return getEventLogs({ ...rest, fromBlock, toBlock, chain, target, targets, onlyArgs, flatten, eventAbi, topics, topic, cacheInCloud, skipCacheRead, entireLog, skipIndexer, noTarget }) } const streamLogs = async (params: Parameters[0] & { targetsFilter?: string[] | Set }) => { if (!sdk.indexer.supportedChainSet2.has(chain)) { throw new Error(`streamLogs is not supported for ${chain} chain`) } const origProcessor = params.processor let targetsFilter = params.targetsFilter if (Array.isArray(targetsFilter)) targetsFilter = new Set(targetsFilter.map((t) => t.toLowerCase())) if (!params.hasOwnProperty('fromBlock')) params.fromBlock = await getFromBlock() if (!params.hasOwnProperty('toBlock')) params.toBlock = await getToBlock() if (!params.hasOwnProperty('all')) params.all = true if (!params.hasOwnProperty('clientStreaming')) params.clientStreaming = true if (!params.hasOwnProperty('collect')) params.collect = false if (!params.hasOwnProperty('onlyArgs') && !params.entireLog) params.onlyArgs = true if (params.hasOwnProperty('processor')) params.processor = (chunk: any | any[]) => { let swapLogs = Array.isArray(chunk) ? chunk : [chunk] if (targetsFilter) swapLogs = swapLogs.filter((log) => targetsFilter!.has(log.address.toLowerCase())) origProcessor!(swapLogs) } const requestCount = params.targets ? params.targets.length : 1 if (api) api.addStat('streamLogs', requestCount) return sdk.indexer.getLogs({ ...params, chain }) } // we intentionally add a delay to avoid fetching the same block before it is cached // await randomDelay() let fromBlock, toBlock // we fetch current block and previous blocks only for evm chains/ chains we have RPC for if (getProvider(chain)) { fromBlock = await getFromBlock() toBlock = await getToBlock() } const fromApi = new ChainApi({ chain, timestamp: fromTimestamp, block: fromBlock }) const api = new ChainApi({ chain, timestamp: withinTwoHours ? undefined : timestamp, block: toBlock }) const startOfDay = getUniqStartOfTodayTimestamp(new Date(toTimestamp * 1000)) const startTimestamp = fromTimestamp const endTimestamp = toTimestamp + 1 const getStartBlock = getFromBlock const getEndBlock = getToBlock const toApi = api api.getLogs = () => { throw new Error('api.getLogs is disabled, use getLogs from options object instead') } fromApi.getLogs = () => { throw new Error('fromApi.getLogs is disabled, use getLogs from options object instead') } return { createBalances, getBlock, toTimestamp, fromTimestamp, getFromBlock, getToBlock, getLogs, chain, fromApi, toApi, api, startOfDay, startTimestamp, endTimestamp, getStartBlock, getEndBlock, dateString: getDateString(startOfDay), moduleUID, startOfDayId: getStartOfDayId(startOfDay), streamLogs, metadata, } } // code for random 1-4 second delay async function randomDelay() { const delay = Math.floor(Math.random() * 4) + 1 return new Promise((resolve) => setTimeout(resolve, delay * 1000)) } async function setChainValidStart(chain: string) { const cleanPreviousDayTimestamp = cleanCurrentDayTimestamp - ONE_DAY_IN_SECONDS let _start = adapterObject![chain]?.start ?? 0 // Use root-level deadFrom if set, otherwise use chain-specific deadFrom let _end = module.deadFrom ?? adapterObject![chain]?.deadFrom if (typeof _start === 'string') _start = new Date(_start).getTime() / 1000 if (typeof _end === 'string') _end = new Date(_end).getTime() / 1000 // if (_start === undefined) return; // Only check deadFrom if it's explicitly set (not undefined) if (_end !== undefined && typeof _end === 'number' && _end > 0 && _end < cleanPreviousDayTimestamp) { validStart[chain] = { canRun: false, startTimestamp: _start as number, endTimestamp: _end as number, } return; } if (typeof _start === 'number') { validStart[chain] = { canRun: _start <= cleanPreviousDayTimestamp, startTimestamp: _start } return; } const defaultStart = Math.trunc(Date.now() / 1000) if (closeToCurrentTime) {// intentionally set to true to allow for backfilling validStart[chain] = { canRun: true, startTimestamp: defaultStart } return; } // if _start is an async function that returns timestamp const start = await (_start as any)().catch(() => { console.error(`Failed to get start time for ${name} ${adapterVersion} ${chain}`) return defaultStart }) validStart[chain] = { canRun: typeof start === 'number' && start <= cleanPreviousDayTimestamp, startTimestamp: start } } } function createBalanceFrom(options: { chain: string, timestamp: number | undefined, amount: FetchResponseValue }): Balances { const { chain, timestamp, amount } = options const balance = new Balances({ chain, timestamp }) if (amount) { if (typeof amount === 'number' || typeof amount === 'string') { balance.addUSDValue(amount) } else { balance.addBalances(amount) } } return balance; } function subtractBalance(options: { balance: Balances, amount: FetchResponseValue }) { const { balance, amount } = options if (amount) { if (typeof amount === 'number' || typeof amount === 'string') { const otherBalance = createBalanceFrom({ chain: balance.chain, timestamp: balance.timestamp, amount }) balance.subtract(otherBalance) } else { balance.subtract(amount) } } } function validateAdapterResult(result: any, module: any) { // validate metrics // this is to ensure that we do this validation only for the new adapters if (result.dailyFees && result.dailyFees instanceof Balances && result.dailyFees.hasBreakdownBalances()) { // should include atleast SupplySideRevenue or ProtocolRevenue or Revenue if (!result.dailySupplySideRevenue && !result.dailyProtocolRevenue && !result.dailyRevenue && !module?.skipBreakdownValidation) { throw Error('found dailyFees record but missing all dailyRevenue, dailySupplySideRevenue, dailyProtocolRevenue records') } } } function addMissingMetrics(chain: string, result: any) { // add missing metrics for Balances which has breakdown labels only // this is to ensure that we dont change behavior of existing adapters if (result.dailyFees && result.dailyFees instanceof Balances && result.dailyFees.hasBreakdownBalances()) { // if we have supplySideRevenue but missing revenue, add revenue = fees - supplySideRevenue if (result.dailySupplySideRevenue && result.dailyRevenue === undefined) { result.dailyRevenue = createBalanceFrom({ chain, timestamp: result.timestamp, amount: result.dailyFees }) subtractBalance({ balance: result.dailyRevenue, amount: result.dailySupplySideRevenue }) } } } ================================================ FILE: aggregator-derivatives/.gitkeep ================================================ ================================================ FILE: aggregator-derivatives/GUIDELINES.md ================================================ # Derivatives Aggregator Guidelines These guidelines apply to all adapters in the `aggregator-derivatives/` directory. ## Required Dimensions | Dimension | Required | Description | |-----------|----------|-------------| | `dailyVolume` | YES | Perpetual/derivatives trading volume (TAKER volume only) | ## What is a Derivatives Aggregator? Derivatives aggregators route perpetual and derivatives trades through multiple protocols to find optimal execution. ## Volume Calculation - Track derivatives volume ROUTED through the aggregator - **Track TAKER volume ONLY** - do NOT double-count by adding both taker and maker volumes - Include perpetual swaps, futures, and other derivative products - Do NOT double-count volume already tracked in underlying derivatives protocol adapters ## Optional Dimensions | Dimension | Description | |-----------|-------------| | `openInterestAtEnd` | Total open interest at period end | | `longOpenInterestAtEnd` | Long positions open interest | | `shortOpenInterestAtEnd` | Short positions open interest | ## Data Sources 1. **On-chain logs** - Track aggregator contract events 2. **Protocol APIs** - When on-chain tracking is complex 3. **Query engines** - For complex aggregation analysis ## Fees/Revenue Tracking If the aggregator charges fees and this adapter returns fee/revenue dimensions, follow the guidelines in `fees/GUIDELINES.md`. Include: - `dailyFees` - All fees collected - `dailyRevenue` - Aggregator's portion - `dailySupplySideRevenue` - Partner/integration fees ## Common Mistakes to Avoid 1. Double-counting volume with underlying derivatives adapters 2. Mixing spot and derivatives volume 3. Not tracking all chains/protocols aggregated 4. Missing open interest tracking when available 5. Counting both taker AND maker volume (should only count taker) ================================================ FILE: aggregator-derivatives/defiapp/index.ts ================================================ // DEFI_APP_BUILDER_ADDRESS = '0x1922810825C90F4270048B96Da7b1803CD8609Ef'; import { FetchResult, SimpleAdapter } from "../../adapters/types"; import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { getEnv } from "../../helpers/env"; const tsToISO = (ts: number) => new Date(ts * 1e3).toISOString(); const fetch = async (_: any, _b: any, options: any): Promise => { // 2-day delay: Hyperliquid builder volumes are reported to DefiApp with a 2-day lag. const startDate = options.startOfDay - (24 * 3600); const endDate = options.startOfDay; const response = await httpGet(`https://api.defi.app/api/stats/volume-perps/between?startTime=${tsToISO(startDate)}&endTime=${tsToISO(endDate)}`, { headers: { "Content-Type": "application/json", "X-API-KEY": getEnv('DEFIAPP_API_KEY'), User: "defillama", }, }); const dailyVolume = response.totalPerpsVolumeUsd; return { dailyVolume, }; }; const adapter: SimpleAdapter = { version: 1, adapter: { [CHAIN.HYPERLIQUID]: { fetch, start: "2025-05-01", // May 1st, 2025 }, }, doublecounted: true, }; export default adapter; ================================================ FILE: aggregator-derivatives/flat-money/helper.ts ================================================ import {CHAIN} from "../../helpers/chains"; import {gql, GraphQLClient} from "graphql-request"; export const CONFIG = { [CHAIN.BASE]: { startTimestamp: 1721161357, endpoint: "https://gateway-arbitrum.network.thegraph.com/api/c26ffec48be89fe71a1af11eb1ae5776/subgraphs/id/HnQeWxwtLY5ZnBS39GmYt84gcHToG7cqjb8KVPApm89h", decimals: { price: 18, amount: 18, } }, [CHAIN.OPTIMISM]: { startTimestamp: 1744830648, endpoint: "https://gateway-arbitrum.network.thegraph.com/api/c26ffec48be89fe71a1af11eb1ae5776/subgraphs/id/C5B1KnswowpwwVGNCVw8Ph7X4rqEuyoZZN7UWjjckEtm", decimals: { price: 18, amount: 8, } }, [CHAIN.ARBITRUM]: { startTimestamp: 1744830648, endpoint: "https://gateway-arbitrum.network.thegraph.com/api/c26ffec48be89fe71a1af11eb1ae5776/subgraphs/id/4Ttk2WinVSCURA9vVZ5tDz7TwG7tEDkQbFbGur5qxoWG", decimals: { price: 18, amount: 8, } }, }; export const fetchVolume = async (chainId: CHAIN, query: string, volumeField: string, startTimestamp: number, endTimestamp: number) => { const { endpoint } = CONFIG[chainId]; let allData = []; let skip = 0; const batchSize = 1000; while (true) { try { const data = await new GraphQLClient(endpoint).request(query, { startTimestamp, endTimestamp, first: batchSize, skip }); const entries = data[volumeField]; if (entries.length === 0) break; allData = allData.concat(entries); skip += batchSize; if (entries.length < batchSize) break; await sleep(500); } catch (e) { throw new Error(`Error fetching data for chain ${chainId}: ${e.message}`); } } return allData; }; export const calculateOpensVolume = (data: any, amountDecimals: number): number => data.reduce((acc: number, item: any) => { const priceFormatted = Number(item.entryPrice) / 1e18; const marginFormatted = Number(item.margin) / 10 ** amountDecimals; const sizeFormatted = Number(item.size) / 10 ** amountDecimals; return acc + (marginFormatted + sizeFormatted) * priceFormatted; }, 0); export const calculateAdjustsVolume = (data: any, amountDecimals: number): number => data.reduce((acc: number, item: any) => { const priceFormatted = Number(item.adjustPrice) / 1e18; const marginDeltaFormatted = Number(Math.abs(item.marginDelta)) / 10 ** amountDecimals; const sizeDeltaFormatted = Number(Math.abs(item.sizeDelta)) / 10 ** amountDecimals; return acc + (marginDeltaFormatted + sizeDeltaFormatted) * priceFormatted; }, 0); export const calculateClosesVolume = (data: any, amountDecimals: number): number => data.reduce((acc: number, item: any) => { const priceFormatted = Number(item.closePrice) / 1e18; const settledMarginFormatted = Number(item.settledMargin) / 10 ** amountDecimals; const sizeFormatted = Number(item.size) / 10 ** amountDecimals; return acc + (settledMarginFormatted + sizeFormatted) * priceFormatted; }, 0); function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } export const leverageOpensQuery = gql` query leverageOpens($startTimestamp: BigInt!, $endTimestamp: BigInt!) { leverageOpens( where: { blockTimestamp_gte: $startTimestamp, blockTimestamp_lte: $endTimestamp }, first: 1000, orderBy: blockTimestamp, orderDirection: asc ) { margin, size, entryPrice } }`; export const leverageAdjustsQuery = gql` query leverageAdjusts($startTimestamp: BigInt!, $endTimestamp: BigInt!) { leverageAdjusts( where: { blockTimestamp_gte: $startTimestamp, blockTimestamp_lte: $endTimestamp }, first: 1000, orderBy: blockTimestamp, orderDirection: asc ) { marginDelta, sizeDelta, adjustPrice } }`; export const leverageClosesQuery = gql` query leverageCloses($startTimestamp: BigInt!, $endTimestamp: BigInt!) { leverageCloses( where: { blockTimestamp_gte: $startTimestamp, blockTimestamp_lte: $endTimestamp }, first: 1000, orderBy: blockTimestamp, orderDirection: asc ) { settledMargin, size, closePrice } }`; ================================================ FILE: aggregator-derivatives/flat-money/index.ts ================================================ import { SimpleAdapter, FetchV2, FetchResultV2 } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { calculateAdjustsVolume, calculateClosesVolume, calculateOpensVolume, CONFIG, fetchVolume, leverageAdjustsQuery, leverageClosesQuery, leverageOpensQuery } from "./helper"; const fetch: FetchV2 = async ({ startTimestamp, endTimestamp, chain }): Promise => { const config = CONFIG[chain]; if (!config) throw new Error(`Unsupported chain: ${chain}`); const { decimals, } = config; const [ dailyOpensData, dailyAdjustsData, dailyClosesData, ] = await Promise.all([ fetchVolume(chain as CHAIN, leverageOpensQuery, "leverageOpens", startTimestamp, endTimestamp), fetchVolume(chain as CHAIN, leverageAdjustsQuery, "leverageAdjusts", startTimestamp, endTimestamp), fetchVolume(chain as CHAIN, leverageClosesQuery, "leverageCloses", startTimestamp, endTimestamp), ]); return { dailyVolume: calculateOpensVolume(dailyOpensData, decimals.amount) + calculateAdjustsVolume(dailyAdjustsData, decimals.amount) + calculateClosesVolume(dailyClosesData, decimals.amount), }; }; const adapter: SimpleAdapter = { adapter: Object.fromEntries( Object.entries(CONFIG).map(([chain, config]) => [ chain, { fetch, start: config.startTimestamp } ]) ), version: 2, pullHourly: true, }; export default adapter; ================================================ FILE: aggregator-derivatives/flat-money-v1/index.ts ================================================ import { SimpleAdapter, FetchV2, FetchResultV2 } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { calculateAdjustsVolume, calculateClosesVolume, calculateOpensVolume, CONFIG, fetchVolume, leverageAdjustsQuery, leverageClosesQuery, leverageOpensQuery } from "../flat-money/helper"; const fetch: FetchV2 = async ({ startTimestamp, endTimestamp, chain }): Promise => { const config = CONFIG[chain]; if (!config) throw new Error(`Unsupported chain: ${chain}`); const { decimals, } = config; const [ dailyOpensData, dailyAdjustsData, dailyClosesData, ] = await Promise.all([ fetchVolume(chain as CHAIN, leverageOpensQuery, "leverageOpens", startTimestamp, endTimestamp), fetchVolume(chain as CHAIN, leverageAdjustsQuery, "leverageAdjusts", startTimestamp, endTimestamp), fetchVolume(chain as CHAIN, leverageClosesQuery, "leverageCloses", startTimestamp, endTimestamp), ]); return { dailyVolume: calculateOpensVolume(dailyOpensData, decimals.amount) + calculateAdjustsVolume(dailyAdjustsData, decimals.amount) + calculateClosesVolume(dailyClosesData, decimals.amount), }; }; const adapter: SimpleAdapter = { adapter: Object.fromEntries( Object.entries(CONFIG).filter(([chain, config]) => chain === CHAIN.BASE).map(([chain, config]) => [ chain, { fetch, start: config.startTimestamp } ]) ), pullHourly: true, version: 2 }; export default adapter; ================================================ FILE: aggregator-derivatives/flat-money-v2/index.ts ================================================ import { SimpleAdapter, FetchV2, FetchResultV2 } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { calculateAdjustsVolume, calculateClosesVolume, calculateOpensVolume, CONFIG, fetchVolume, leverageAdjustsQuery, leverageClosesQuery, leverageOpensQuery } from "../flat-money/helper"; const fetch: FetchV2 = async ({ startTimestamp, endTimestamp, chain }): Promise => { const config = CONFIG[chain]; if (!config) throw new Error(`Unsupported chain: ${chain}`); const { decimals, } = config; const [ dailyOpensData, dailyAdjustsData, dailyClosesData, ] = await Promise.all([ fetchVolume(chain as CHAIN, leverageOpensQuery, "leverageOpens", startTimestamp, endTimestamp), fetchVolume(chain as CHAIN, leverageAdjustsQuery, "leverageAdjusts", startTimestamp, endTimestamp), fetchVolume(chain as CHAIN, leverageClosesQuery, "leverageCloses", startTimestamp, endTimestamp), ]); return { dailyVolume: calculateOpensVolume(dailyOpensData, decimals.amount) + calculateAdjustsVolume(dailyAdjustsData, decimals.amount) + calculateClosesVolume(dailyClosesData, decimals.amount), }; }; const adapter: SimpleAdapter = { adapter: Object.fromEntries( Object.entries(CONFIG).filter(([chain, config]) => chain === CHAIN.OPTIMISM || chain === CHAIN.ARBITRUM).map(([chain, config]) => [ chain, { fetch, start: config.startTimestamp } ]) ), pullHourly: true, version: 2 }; export default adapter; ================================================ FILE: aggregator-derivatives/kwenta/index.ts ================================================ import { SimpleAdapter, FetchV2, FetchResultV2 } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { gql, GraphQLClient } from "graphql-request"; const PROVIDER_CONFIG = { [CHAIN.BASE]: { startTimestamp: 1702943900, start: '2023-12-18', endpoint: "https://subgraph.satsuma-prod.com/404b0c87e4a3/kwenta/base-perps-v3/api", query: gql` query aggregateStats($startTimestamp: BigInt!, $endTimestamp: BigInt!) { perpsV3AggregateStats( where: { timestamp_gte: $startTimestamp, timestamp_lte: $endTimestamp, period: "86400", marketId: "0" }, first: 9999, orderBy: timestamp, orderDirection: asc ) { timestamp, volume } }`, volumeField: "perpsV3AggregateStats" }, [CHAIN.OPTIMISM]: { startTimestamp: 1671494100, start: '2022-12-19', endpoint: "https://subgraph.satsuma-prod.com/404b0c87e4a3/kwenta/optimism-perps/api", query: gql` query aggregateStats($startTimestamp: BigInt!, $endTimestamp: BigInt!) { futuresAggregateStats( where: { timestamp_gte: $startTimestamp, timestamp_lte: $endTimestamp, asset: "0x", period: "86400" }, first: 9999, orderBy: timestamp, orderDirection: asc ) { timestamp, volume } }`, volumeField: "futuresAggregateStats" }, [CHAIN.ARBITRUM]: { startTimestamp: 1696032000, start: '2023-09-30', endpoint: "https://subgraph.perennial.finance/arbitrum", query: gql` query aggregateStats($startTimestamp: BigInt!, $endTimestamp: BigInt!) { marketAccumulations( where: { and: [{ bucket: daily, timestamp_gte: $startTimestamp, timestamp_lte: $endTimestamp }, { or: [{ shortNotional_gt: "0" }, { longNotional_gt: "0" }] }] }, first: 9999, orderBy: timestamp, orderDirection: asc ) { timestamp, longNotional, shortNotional } }`, volumeField: "marketAccumulations" } }; const fetchVolume = async (chainId: CHAIN, startTimestamp: number, endTimestamp: number) => { const { endpoint, query } = PROVIDER_CONFIG[chainId]; try { return await new GraphQLClient(endpoint).request(query, { startTimestamp, endTimestamp }); } catch (e) { throw new Error(`Failed to fetch data for chain ${chainId}: ${e.message}`); } }; const calculateVolume = (data: any, volumeField: string): number => data[volumeField].reduce((acc: number, item: any) => acc + (volumeField === "marketAccumulations" ? (Number(item.longNotional) + Number(item.shortNotional)) / 1e6 : Number(item.volume) / 1e18 ), 0); const fetch: FetchV2 = async ({ startTimestamp, endTimestamp, chain }): Promise => { const config = PROVIDER_CONFIG[chain]; if (!config) throw new Error(`Unsupported chain: ${chain}`); const dailyData = await fetchVolume(chain as CHAIN, startTimestamp || (endTimestamp - 86400), endTimestamp); return { timestamp: endTimestamp, dailyVolume: calculateVolume(dailyData, config.volumeField).toString(), }; }; const adapter: SimpleAdapter = { adapter: Object.fromEntries( Object.entries(PROVIDER_CONFIG).map(([chain, config]) => [ chain, { fetch, start: config.start } ]) ), pullHourly: true, version: 2, deadFrom: '2025-08-26', }; export default adapter; ================================================ FILE: aggregator-derivatives/mux-protocol-agge.ts ================================================ import fetchURL from "../utils/fetchURL" import { Chain, FetchOptions } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; const historicalVolumeEndpoint = "https://stats.mux.network/api/public/dashboard/13f401da-31b4-4d35-8529-bb62ca408de8/dashcard/389/card/306" interface IVolumeall { volume: string; time: string; title: string; } const chainsMap = { [CHAIN.ARBITRUM]: "Arbitrum", [CHAIN.AVAX]: "Avalanche", [CHAIN.BSC]: "BNB Chain", [CHAIN.FANTOM]: "Fantom" } const fetch = async (_1: number, _: any, { chain, dateString }: FetchOptions) => { const callhistoricalVolume = (await fetchURL(historicalVolumeEndpoint))?.data.rows; const historicalVolume: IVolumeall[] = callhistoricalVolume.map((e: string[] | number[]) => { const [time, title, volume] = e; return { time, volume, title } as IVolumeall; }); const historical = historicalVolume.filter((e: IVolumeall) => e.title === (chainsMap as any)[chain]); const dailyVolume = historical .find(dayItem => dayItem.time.slice(0, 10) === dateString)?.volume return { dailyVolume: dailyVolume, }; } export default { fetch, version: 1, chains: Object.keys(chainsMap) as Chain[], } ================================================ FILE: aggregator-derivatives/vooi/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchResult, SimpleAdapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import asyncRetry from "async-retry"; async function fetchStatistics(startOfDay: number) { const data = await asyncRetry( async () => fetchURL(`https://vooi-rebates.fly.dev/defillama/volumes?ts=${startOfDay}`), { retries: 3, minTimeout: 1000, maxTimeout: 5000, factor: 2, } ); return data.map((item: any) => ({ ...item, dailyVolume: Number(item.dailyVolume), })); } const getItems: Record) => Array> = { [CHAIN.ARBITRUM]: (items: Array): Array => { return items.filter(item => ['ostium'].includes(item.protocol) || (['gmx', 'gains', 'synfutures'].includes(item.protocol) && item.network === 'arbitrum')) }, [CHAIN.ORDERLY]: (items: Array): Array => { return items.filter(item => item.protocol === 'orderly') }, [CHAIN.HYPERLIQUID]: (items: Array): Array => { return items.filter(item => item.protocol === 'hyperliquid') }, [CHAIN.BSC]: (items: Array): Array => { return items.filter(item => item.protocol == 'kiloex' && (item.network === 'bnb' || item.network === null)) }, [CHAIN.BASE]: (items: Array): Array => { return items.filter(item => ['synfutures', 'kiloex'].includes(item.protocol) && item.network === 'base') }, [CHAIN.BLAST]: (items: Array): Array => { return items.filter(item => item.protocol == 'kiloex' && item.network === 'blast') }, [CHAIN.TAIKO]: (items: Array): Array => { return items.filter(item => item.protocol == 'synfutures' && item.network === 'taiko') }, [CHAIN.MANTA]: (items: Array): Array => { return items.filter(item => item.protocol == 'kiloex' && item.network === 'manta') }, [CHAIN.OP_BNB]: (items: Array): Array => { return items.filter(item => item.protocol == 'kiloex' && item.network === 'opbnb') }, [CHAIN.OFF_CHAIN]: (items: Array): Array => { return items.filter(item => ['aster', 'lighter'].includes(item.protocol)) }, } const prefetch = async (options: FetchOptions): Promise => { return await fetchStatistics(options.startOfDay); } const fetch = async (_a: number, _t: any, options: FetchOptions): Promise => { const results = options.preFetchedResults; const items = getItems[options.chain](results) let dailyVolume = 0; for (const item of items) { // reported wrong - spike volume on this day on ostium if (options.chain === CHAIN.ARBITRUM && options.startOfDay === 1768003200 && item.protocol === 'ostium') { dailyVolume += 0; } else { dailyVolume += item.dailyVolume; } } return { dailyVolume } } const adapter: SimpleAdapter = { version: 1, fetch, prefetch, adapter: { [CHAIN.ARBITRUM]: { start: "2024-05-02", }, [CHAIN.ORDERLY]: { start: "2024-05-02", }, [CHAIN.BSC]: { start: "2024-06-01", }, [CHAIN.BASE]: { start: "2024-08-01", }, [CHAIN.HYPERLIQUID]: { start: "2024-11-04", }, [CHAIN.TAIKO]: { start: "2025-10-20", }, [CHAIN.MANTA]: { start: "2025-10-20", }, [CHAIN.BLAST]: { start: "2025-10-20", }, [CHAIN.OP_BNB]: { start: "2025-10-20", }, [CHAIN.OFF_CHAIN]: { start: '2025-11-01' } }, doublecounted: true, }; export default adapter; ================================================ FILE: aggregator-options/GUIDELINES.md ================================================ # Options Aggregator Guidelines These guidelines apply to all adapters in the `aggregator-options/` directory. ## Required Dimensions | Dimension | Required | Description | |-----------|----------|-------------| | `dailyNotionalVolume` | YES | Notional volume of options contracts traded/settled | | `dailyPremiumVolume` | YES | Premium volume collected/paid | ## What is an Options Aggregator? Options aggregators route options trades through multiple protocols/vaults to find optimal pricing and execution. ## Volume Types ### Notional Volume - The underlying value of options contracts - Example: A call option on 1 ETH at $2000 strike has $2000 notional value ### Premium Volume - The actual premium paid/received for options contracts - This is what users actually pay to enter positions ## Optional Dimensions | Dimension | Description | |-----------|-------------| | `openInterestAtEnd` | Total open interest at period end | | `longOpenInterestAtEnd` | Long positions open interest | | `shortOpenInterestAtEnd` | Short positions open interest | ## Data Sources 1. **On-chain logs** - Option settlement and exercise events 2. **Protocol APIs** - Complex options data 3. **Query engines** - For aggregated analysis ## Fees/Revenue Tracking If the aggregator charges fees and this adapter returns fee/revenue dimensions, follow the guidelines in `fees/GUIDELINES.md`. ## Common Mistakes to Avoid 1. Confusing notional vs premium volume 2. Double-counting with underlying options protocol adapters 3. Not tracking both call and put options 4. Missing settlement/exercise fees ================================================ FILE: aggregator-options/example.ts ================================================ //code here ================================================ FILE: aggregator-options/grix/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; export type GrixMetricsData = { totalNotionalVolume24Hr: string; }; const fetchGrix = async (_a: any, _b: any, { endTimestamp}: FetchOptions) => { /** Timestamp representing the end of the 24 hour period */ const url = `https://internal-api-dev.grix.finance/volumeData?endTimestamp=${endTimestamp}`; const grixMetricsResponse = await httpGet(url); const grixMetricsData = parseGrixMetricsData(grixMetricsResponse); if (!grixMetricsData) { throw new Error("No data found when fetching Grix volume data"); } const dailyNotionalVolume = Number(grixMetricsData.totalNotionalVolume24Hr); return { dailyNotionalVolume, }; }; const parseGrixMetricsData = (result: any): GrixMetricsData | null => { if (typeof result === "object" && result !== null) { return result as GrixMetricsData; } return result ? (JSON.parse(result) as GrixMetricsData) : null; }; const grix_adapter: SimpleAdapter = { version: 1, fetch: fetchGrix, runAtCurrTime: true, // currently we don't take the timestamp into account, should be changed soon adapter: { [CHAIN.ARBITRUM]: { start: "2024-11-01", }, }, }; export default grix_adapter; ================================================ FILE: aggregators/1delta/index.ts ================================================ import { Adapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet, httpPost } from "../../utils/fetchURL"; const FUEL_SUBGRAPH_URL = 'https://endpoint.sentio.xyz/1delta/fuel-subgraph/volume' const FUEL_SUBGRAPH_API_KEY = 'mHWELZ01Oo3BRfGb0WrhFvryge78baQVT' const fetchFuelVolume = async (options: FetchOptions) => { const data = await httpPost( FUEL_SUBGRAPH_URL, JSON.stringify({ "startTimestamp": options.startTimestamp, "endTimestamp": options.endTimestamp }), { headers: { 'api-key': FUEL_SUBGRAPH_API_KEY, 'Content-Type': 'application/json', } }) const dailyVolume = data.syncSqlResponse.result?.rows.reduce((acc: number, row: any) => acc + Number(row.volumeUsd), 0) return { dailyVolume, } } const chainConfig: Record = { [CHAIN.MANTLE]: { chainId: 5000, start: '2025-03-01' }, [CHAIN.OPTIMISM]: { chainId: 10, start: '2025-03-01' }, [CHAIN.POLYGON]: { chainId: 137, start: '2025-03-01' }, [CHAIN.LINEA]: { chainId: 59144, start: '2025-03-01' }, [CHAIN.BSC]: { chainId: 56, start: '2025-03-01' }, [CHAIN.AVAX]: { chainId: 43114, start: '2025-03-01' }, [CHAIN.TAIKO]: { chainId: 167000, start: '2025-03-01' }, [CHAIN.BASE]: { chainId: 8453, start: '2025-03-01' }, [CHAIN.ARBITRUM]: { chainId: 42161, start: '2025-03-01' }, //[CHAIN.BLAST]: { chainId: 81457, start: '2025-03-01' }, //invalid spike [CHAIN.METIS]: { chainId: 1088, start: '2025-03-01' }, // [CHAIN.XDAI]: { chainId: 100, start: '2025-03-01' }, // invalid spike [CHAIN.MODE]: { chainId: 34443, start: '2025-03-01' }, [CHAIN.HEMI]: { chainId: 43111, start: '2025-03-01' }, [CHAIN.SCROLL]: { chainId: 534352, start: '2025-03-01' }, [CHAIN.CORE]: { chainId: 1116, start: '2025-03-01' }, [CHAIN.SONIC]: { chainId: 146, start: '2025-03-01' }, [CHAIN.FANTOM]: { chainId: 250, start: '2025-03-01' }, [CHAIN.KLAYTN]: { chainId: 8217, start: '2025-10-21' }, // Kaia [CHAIN.SONEIUM]: { chainId: 1868, start: '2025-10-21' }, [CHAIN.HYPERLIQUID]: { chainId: 999, start: '2025-10-21' }, [CHAIN.BERACHAIN]: { chainId: 80094, start: '2025-10-21' }, [CHAIN.CRONOS]: { chainId: 25, start: '2025-10-21' }, [CHAIN.XDC]: { chainId: 50, start: '2025-10-21' }, [CHAIN.UNICHAIN]: { chainId: 130, start: '2025-10-21' }, [CHAIN.KATANA]: { chainId: 747474, start: '2025-10-21' }, [CHAIN.ETHEREUM]: { chainId: 1, start: '2025-10-21' }, [CHAIN.TELOS]: { chainId: 40, start: '2025-10-21' }, [CHAIN.MORPH]: { chainId: 2818, start: '2025-10-21' }, [CHAIN.MANTA]: { chainId: 169, start: '2025-10-21' }, [CHAIN.PLASMA]: { chainId: 9745, start: '2025-10-21' }, //[CHAIN.MOONBEAM]: { chainId: 1284, start: '2025-10-21' }, //invalid spike [CHAIN.FUEL]: { chainId: 0, start: '2025-01-20' } } const fetch = async (options: FetchOptions) => { const chain = options.chain as CHAIN; const dailyVolume = options.createBalances() if (chain === CHAIN.FUEL) { return await fetchFuelVolume(options) } const fromBlock = await options.getFromBlock() const toBlock = await options.getToBlock() const url = `https://volume.1delta.io/volume?chainId=${chainConfig[chain].chainId}&fromBlock=${fromBlock}&toBlock=${toBlock}` const volumeByAsset = await httpGet(url, { headers: { 'Content-Type': 'application/json', } }) Object.entries(volumeByAsset).forEach(([asset, volume]) => { dailyVolume.add(asset, volume) }) return { dailyVolume } } const adapter: Adapter = { pullHourly: true, version: 2, fetch, adapter: chainConfig } export default adapter; ================================================ FILE: aggregators/1inch-agg/index.ts ================================================ import { Dependencies, FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; import { CHAIN } from "../../helpers/chains"; import { getDefaultDexTokensBlacklisted } from "../../helpers/lists"; const chainsMap: Record = { [CHAIN.ETHEREUM]: 'ethereum', [CHAIN.ARBITRUM]: 'arbitrum', [CHAIN.POLYGON]: 'polygon', [CHAIN.BSC]: 'bnb', [CHAIN.AVAX]: 'avalanche_c', [CHAIN.OPTIMISM]: 'optimism', [CHAIN.BASE]: 'base', [CHAIN.XDAI]: 'gnosis', [CHAIN.LINEA]: 'linea', [CHAIN.SONIC]: 'sonic', [CHAIN.UNICHAIN]: 'unichain', [CHAIN.ERA]: 'zksync', }; const prefetch = async (options: FetchOptions) => { const blacklisted = getDefaultDexTokensBlacklisted(CHAIN.BSC); const sql_query = ` SELECT blockchain, sum(amount_usd) as volume_24h FROM oneinch.swaps WHERE TIME_RANGE -- AND src_token_address NOT IN (${blacklisted}) -- AND dst_token_address NOT IN (${blacklisted}) GROUP BY 1 ORDER BY volume_24h DESC `; const result = await queryDuneSql(options, sql_query); return result; }; const fetch = async ( _a: any, _b: any, options: FetchOptions ): Promise => { const results = options.preFetchedResults || []; const chainData = results.find((item: any) => item.blockchain === chainsMap[options.chain]); return { dailyVolume: chainData ? chainData.volume_24h : 0, }; }; const adapter: SimpleAdapter = { version: 1, dependencies: [Dependencies.DUNE], fetch, chains: Object.keys(chainsMap), start: "2023-12-05", prefetch, isExpensiveAdapter: true, }; export default adapter; ================================================ FILE: aggregators/3route/index.ts ================================================ import { gql, request } from "graphql-request"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL" import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; interface DappStat { volume_usd: number; } interface TezosVolumeResponse { dapp_stat_1d: DappStat[]; } interface EtherlinkVolumeResponse { day: string; total_volume: number; } const dappSlug = '3route' const tezosURL = 'https://dapps-indexer.dipdup.net/v1/graphql'; const etherlinkURL = 'https://3route-etherlink.dipdup.net/v1/volume/day' const query = gql` query GetDailyVolume($dappSlug: String!, $startDate: timestamptz!, $endDate: timestamptz!) { dapp_stat_1d( where: { dapp_slug: {_eq: $dappSlug} bucket: { _gte: $startDate _lt: $endDate } } ) { volume_usd } } `; const fetchTezos = async (_: any, _1: any, { startOfDay }: FetchOptions): Promise => { const startDate = new Date(startOfDay * 1000).toISOString() const endDate = new Date((startOfDay + 86400) * 1000).toISOString() const response = await request(tezosURL, query, { dappSlug, startDate, endDate }) if (response.dapp_stat_1d.length == 0) { return { dailyVolume: 0 } } return { dailyVolume: response.dapp_stat_1d[0].volume_usd } } const fetchEtherlink = async (_: any, _1: any, { startOfDay }: FetchOptions): Promise => { const startDate = new Date(startOfDay * 1000).toISOString().split('T')[0] const endDate = new Date((startOfDay + 86400) * 1000).toISOString().split('T')[0] const response: EtherlinkVolumeResponse[] = await fetchURL(`${etherlinkURL}?start=${startDate}&end=${endDate}`); if (response.length == 0) { return { dailyVolume: 0 } } return { dailyVolume: response[0].total_volume } } const adapter: SimpleAdapter = { version: 1, adapter: { [CHAIN.TEZOS]: { fetch: fetchTezos, start: '2022-11-15', }, [CHAIN.ETHERLINK]: { fetch: fetchEtherlink, start: '2025-09-01', }, }, }; export default adapter; ================================================ FILE: aggregators/8dx-aggregator/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from "../../helpers/prices"; const EVENT_SWAP_EXECUTED = "event SwapExecuted(address indexed sender, address indexed srcToken, address indexed dstToken, uint256 spentAmount, uint256 returnAmount)"; const CONTRACTS: Record = { [CHAIN.ETHEREUM]: "0xEEe3fdCc5b9D7821570294b26070B2f45cFd8aEc", }; const START_DATE: Record = { [CHAIN.ETHEREUM]: "2025-09-21", }; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const target = CONTRACTS[options.chain]; if (!target) return { dailyVolume }; const logs = await options.getLogs({ target, eventAbi: EVENT_SWAP_EXECUTED, }); logs.forEach((log) => { addOneToken({ balances: dailyVolume, chain: options.chain, token0: log.srcToken, amount0: log.spentAmount, token1: log.dstToken, amount1: log.returnAmount }) }); return { dailyVolume }; } const adapter: SimpleAdapter = { pullHourly: true, version: 2, adapter: Object.keys(CONTRACTS).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: START_DATE[chain] }, }; }, {} as Record), methodology: { Volume: "Volume is calculated by tracking SwapExecuted events and summing spentAmount for each input token.", }, }; export default adapter; ================================================ FILE: aggregators/GUIDELINES.md ================================================ # DEX Aggregator Guidelines These guidelines apply to all adapters in the `aggregators/` directory. ## Required Dimensions | Dimension | Required | Description | |-----------|----------|-------------| | `dailyVolume` | YES | Trading volume routed through the aggregator | ## What is an Aggregator? DEX aggregators route trades through multiple DEXs to find optimal prices. They aggregate liquidity but don't provide it themselves. ## Volume Calculation - Track volume that is ROUTED through the aggregator - Do NOT double-count volume that is already tracked in the underlying DEX adapters - Aggregator volume represents user intent to trade through the aggregator interface ## Data Sources 1. **On-chain logs** - Track aggregator contract events 2. **Aggregator APIs** - When on-chain tracking is complex 3. **Query engines** - For cross-DEX aggregation analysis ## Common Event Patterns ```typescript // Example: Track fill events from aggregator contract const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const logs = await options.getLogs({ target: AGGREGATOR_CONTRACT, eventAbi: 'event Fill(address taker, address makerToken, address takerToken, uint256 makerAmount, uint256 takerAmount)' }); logs.forEach(log => { dailyVolume.add(log.takerToken, log.takerAmount); }); return { dailyVolume }; }; ``` ## Fees/Revenue Tracking If the aggregator charges fees and this adapter returns fee/revenue dimensions, follow the guidelines in `fees/GUIDELINES.md`. Common aggregator fee patterns: - Positive slippage capture - Integration fees - Protocol fees on certain routes ## Common Mistakes to Avoid 1. Double-counting volume with underlying DEX adapters 2. Not tracking all chains the aggregator operates on 3. Missing integration/partner fees as supply-side revenue 4. Counting failed/reverted transactions ================================================ FILE: aggregators/aftermath-aggregator/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = "https://aftermath.finance/api/router/volume-24hrs"; const fetch = async (): Promise => { const dailyVolume = await fetchURL(URL) return { dailyVolume, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.SUI]: { fetch, runAtCurrTime: true, start: '2023-07-20' }, }, }; export default adapter; ================================================ FILE: aggregators/aggre/index.ts ================================================ import { Chain } from "../../adapters/types"; import { FetchV2, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; let abi = ["event SwapExecuted(address indexed user, address tokenIn, address tokenOut, uint amountIn, uint amountOut, uint swapType)"]; type IContract = { [c: string | Chain]: string; } const contract: IContract = { [CHAIN.SCROLL]: '0xcf8bcaCb401C31774EA39296b367B9DaB4F72267', } const fetch: FetchV2 = async ({ getLogs, createBalances, chain, }) => { const dailyVolume = createBalances(); const logs = (await getLogs({ target: contract[chain], eventAbi: abi[0], })) logs.map((log: any) => dailyVolume.add(log.tokenOut, log.amountOut)); return { dailyVolume, }; }; const adapter: SimpleAdapter = { adapter: Object.keys(contract).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2023-10-30', } } }, {}), version: 2, pullHourly: true, }; export default adapter; ================================================ FILE: aggregators/akka/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = 'https://routerv2.akka.finance'; interface IAPIResponse { dailyVolume: string; } const chainIds = { [CHAIN.CORE]: 1116, [CHAIN.XDC]: 50, [CHAIN.BITLAYER]: 200901, [CHAIN.BSQUARED]: 223, }; const startTimestamps = { [CHAIN.CORE]: '2024-06-01', [CHAIN.XDC]: '2024-10-29', [CHAIN.BITLAYER]: '2024-10-29', [CHAIN.BSQUARED]: '2024-10-29', }; const fetch = async (_a: any, _b: any, options: FetchOptions): Promise => { const chainId = chainIds[options.chain]; const endpoint = `/v2/${chainId}/statistics/dappradar`; const response = await fetchURL(`${URL}${endpoint}`); const { dailyVolume }: IAPIResponse = response; return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 1, adapter: Object.keys(chainIds).reduce((acc, chain) => { const startTimestamp = startTimestamps[chain]; return { ...acc, [chain]: { fetch, runAtCurrTime: true, start: startTimestamp, }, }; }, {}), }; export default adapter; ================================================ FILE: aggregators/allox/index.ts ================================================ import { Adapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addTokensReceived } from "../../helpers/token"; const FEE_RECIPIENT = "0x6A80f57ac54123cB71e6c79B3935A381b87B4308"; const configs: Record = { [CHAIN.BSC]: { start: "2026-03-17", }, [CHAIN.BASE]: { start: "2026-04-22", }, [CHAIN.ETHEREUM]: { start: "2026-05-05", }, }; const fetch = async (options: FetchOptions) => { const dailyFees = await addTokensReceived({ options, target: FEE_RECIPIENT, }); // flat 0.25% fee on trades, volume is scaled by 400 return { dailyVolume: dailyFees.clone(400) }; }; const adapter: Adapter = { version: 2, pullHourly: true, adapter: configs, fetch, methodology: { Volume: 'Total USD value of swaps AlloX routed through Uniswap (V2/V3/V4 Universal Router) and PancakeSwap (Universal Router).', } }; export default adapter; ================================================ FILE: aggregators/anqa/index.ts ================================================ import { Dependencies, FetchOptions, FetchResult, } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { queryDuneSql } from "../../helpers/dune"; const fetch = async (_1: any, _2: any, options: FetchOptions): Promise => { const query = ` WITH table_a AS ( SELECT LEAST( COALESCE( TRY_CAST(json_value(data,'lax $.input_amount_usd') AS DOUBLE), TRY_CAST(json_value(TRY_CAST(json_value(data,'lax $.extra_data') AS VARCHAR),'lax $.amountInUsd') AS DOUBLE) ), COALESCE( TRY_CAST(json_value(data,'lax $.output_amount_usd') AS DOUBLE), TRY_CAST(json_value(TRY_CAST(json_value(data,'lax $.extra_data') AS VARCHAR),'lax $.amountOutUsd') AS DOUBLE) ) ) AS tx_value_usd FROM aptos.events AS e WHERE ( e.event_type = '0x2e8671ebdf16028d7de00229c26b551d8f145d541f96278eec54d9d775a49fe3::router::SwapEvent' OR e.event_type = '0x59b8a7918da8ba9d98ded64d49519ec889d311a515c61b06abc1aaa42c508fae::router::SwapEvent' OR e.event_type = '0x165287033a77aa487c547a486a619de3a12099cff98a63bb0352a411772b7e73::router::SwapEvent' OR e.event_type = '0x1cb4fd7144568b4eae2b0d32aaf51fe87fc729eb498295b0a976d91f1692522d::router::SwapEvent' ) AND e.tx_version NOT IN ( 1002108310,1001748840,1001765227,1001624974,1001809346,1002110994, 1002041129,1002041841,1001720818,1001719551,1001718924,1001751891, 1001760947,1001749166,1001750827,1001750564,1001752517,1001812177, 1001748059,1001820233,1001811399,1001762548,1001749445,1001670382, 1001675112,1001967617,1002038932,1001811791,1001820520,1001751178, 1001748578,1001812467,1001620076,1082187676,1082197658,1082197383, 1082197246,1082197771,1082189106,1082188929 ) AND e.tx_success = TRUE AND e.block_date >= from_unixtime(${options.startTimestamp}) AND e.block_date <= from_unixtime(${options.endTimestamp}) ) SELECT SUM(tx_value_usd) AS total_volume FROM table_a; ` const chainData = await queryDuneSql(options, query) return { dailyVolume: chainData[0]["total_volume"], }; }; const adapter: any = { version: 1, dependencies: [Dependencies.DUNE], adapter: { [CHAIN.APTOS]: { fetch: fetch, start: '2023-06-16', } }, isExpensiveAdapter: true, }; export default adapter; ================================================ FILE: aggregators/apstation/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const SwapEvent = "event Swap(address tokenIn, address tokenOut, uint256 amountIn, address referer, address sender)"; const factory_contract = "0x4f4b84b42059E8CaabB211Aa8F02A9cab53A6c4e"; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const data: any[] = await options.getLogs({ target: factory_contract, eventAbi: SwapEvent, }); data.forEach((log: any) => { dailyVolume.add(log.tokenIn, log.amountIn); }); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, methodology: { Volume: "Apstation volume", }, fetch, adapter: { [CHAIN.HYPERLIQUID]: { start: "2025-07-05", }, }, }; export default adapter; ================================================ FILE: aggregators/arbitrage-inc/index.ts ================================================ import type { Adapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addTokensReceived } from "../../helpers/token"; const FEE_RECEIVER = '0xafF5340ECFaf7ce049261cff193f5FED6BDF04E7'; const FEE_RATE = 0.001; const fetch = async (options: FetchOptions) => { const dailyFees = await addTokensReceived({ options, targets: [FEE_RECEIVER], }); const dailyVolume = dailyFees.clone(1 / FEE_RATE); return { dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, dailyVolume, }; }; const DEV_FEE_DESC = "Developer fees (0.1% per swap) are collected from each trade and sent to the designated fee receiver address."; const methodology = { Fees: "We track fees sent to the fee receiver address which represents the developer commission for every swap executed via our frontend integration.", Revenue: DEV_FEE_DESC, ProtocolRevenue: DEV_FEE_DESC, Volume: "Amount of trades executed on the Arbitrage Inc platform", }; const breakdownMethodology = { Fees: { 'Developer Fees': DEV_FEE_DESC, }, Revenue: { 'Developer Fees': DEV_FEE_DESC, }, ProtocolRevenue: { 'Developer Fees': DEV_FEE_DESC, }, }; const adapter: Adapter = { version: 2, pullHourly: true, chains: [CHAIN.BSC], fetch, start: '2026-03-23', methodology, breakdownMethodology, }; export default adapter; ================================================ FILE: aggregators/atmos-aggregator.ts ================================================ import { FetchOptions, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { httpGet } from "../utils/fetchURL"; const API_ENDPOINT = "https://api.atmos.ag/stats/defillama/stats"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const response = await httpGet(`${API_ENDPOINT}?timestamp=${options.startOfDay}`); const dailyVolume = response.data.aggregator.volume; return { dailyVolume }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.SUPRA]: { fetch, start: '2025-09-23', }, }, }; export default adapter; ================================================ FILE: aggregators/aura-agg/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const TransformedERC20Event = "event TransformedERC20(address indexed taker, address inputToken, address outputToken, uint256 inputTokenAmount, uint256 outputTokenAmount)"; const AURA_AGGREGATOR_CONTRACT = "0xEc46A87ba4d423BaF59aeD8e16AE3E91800581Ef" const FLAT_FEE_RATE = 0.0005 // 0.05% const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const logs: any[] = await options.getLogs({ target: AURA_AGGREGATOR_CONTRACT, eventAbi: TransformedERC20Event, }); for (const log of logs) { let token = log.inputToken; if (log.inputToken === "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") { // price for native token not supported - WXPL token = "0x6100E367285b01F48D07953803A2d8dCA5D19873"; } dailyVolume.add(token, log.inputTokenAmount); dailyFees.add(token, Number(log.inputTokenAmount) * FLAT_FEE_RATE); } return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, start: "2025-10-14", methodology: { Volume: "Total trading volume aggregated via Aura routers.", Fees: "Flat 0.05% amount of trading fees on all trades.", Revenue: "Flat 0.05% amount of trading fees on all trades are revenue.", ProtocolRevenue: "Flat 0.05% amount of trading fees on all trades are revenue.", }, chains: [CHAIN.PLASMA], }; export default adapter; ================================================ FILE: aggregators/avnu/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = 'https://starknet.api.avnu.fi'; const endpoint = '/v1/analytics/volumes/'; interface IAPIResponse { date: number; dailyVolume: string; } const fetch = async (timestamp: number): Promise => { const { dailyVolume }: IAPIResponse = (await fetchURL(`${URL}${endpoint}${timestamp * 1000}`)); if (Number(dailyVolume) >= 100000000) { throw new Error('Daily volume is greater than 100M unusually high'); } return { dailyVolume, }; } const adapter: SimpleAdapter = { version: 1, adapter: { [CHAIN.STARKNET]: { fetch, start: '2023-05-15', }, }, }; export default adapter; ================================================ FILE: aggregators/barter/index.ts ================================================ import { ethers } from "ethers"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const EXECUTORS = [ "0x2c0552e5dcb79b064fd23e358a86810bc5994244", "0x2141af658ffda533da864dd11b2ffdb8529c8b94", "0xb2f72662ed42067ccce278f8462a0215b6adcabb", ]; const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; const executorSet = new Set(EXECUTORS.map(e => e.toLowerCase())); const fetch = async ({ createBalances, getLogs }: FetchOptions) => { const dailyVolume = createBalances(); const allLogs: any[] = []; for (const executor of EXECUTORS) { const padded = ethers.zeroPadValue(executor, 32); const logs = await getLogs({ topics: [TRANSFER_TOPIC, null as any, padded], noTarget: true, eventAbi: "event Transfer(address indexed from, address indexed to, uint256 value)", entireLog: true, }); for (const log of logs) { if (log.data === "0x") continue; const from = "0x" + log.topics[1].slice(26).toLowerCase(); if (executorSet.has(from)) continue; allLogs.push(log); } } // Per transaction: keep only the first Transfer (lowest log index). // This is the sell-token inflow from the user, before any DEX routing // or multi-hop returns inflate the count. const firstByTx: Record = {}; for (const log of allLogs) { const txHash = log.transactionHash.toLowerCase(); const idx = log.logIndex ?? log.index ?? 0; const prev = firstByTx[txHash]; if (!prev || idx < (prev.logIndex ?? prev.index ?? 0)) { firstByTx[txHash] = log; } } for (const log of Object.values(firstByTx)) { dailyVolume.add(log.address, log.data); } return { dailyVolume }; }; const methodology = { Volume: "For each transaction involving a Barter executor, the first ERC-20 Transfer " + "received by the executor (by log index) is taken as the sell-side volume. " + "Subsequent transfers (DEX returns, multi-hop intermediates) are excluded.", }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.ETHEREUM]: { fetch, start: "2023-01-01" }, }, methodology, }; export default adapter; ================================================ FILE: aggregators/bebop/index.ts ================================================ import { ethers } from "ethers"; import { Adapter, Dependencies, FetchOptions } from "../../adapters/types"; import { getTransactions } from "../../helpers/getTxReceipts"; import JAM_ABI from "./jamAbi"; import {queryDuneSql} from "../../helpers/dune" import { CHAIN } from "../../helpers/chains" const abis = { "AggregateOrderExecuted": "event AggregateOrderExecuted(bytes32 order_hash)", "OrderSignerRegistered": "event OrderSignerRegistered(address maker, address signer, bool allowed)", "AGGREGATED_ORDER_TYPE_HASH": "function AGGREGATED_ORDER_TYPE_HASH() view returns (bytes32)", "DOMAIN_SEPARATOR": "function DOMAIN_SEPARATOR() view returns (bytes32)", "EIP712_DOMAIN_TYPEHASH": "function EIP712_DOMAIN_TYPEHASH() view returns (bytes32)", "PARTIAL_AGGREGATED_ORDER_TYPE_HASH": "function PARTIAL_AGGREGATED_ORDER_TYPE_HASH() view returns (bytes32)", "SettleAggregateOrder": "function SettleAggregateOrder((uint256 expiry, address taker_address, address[] maker_addresses, uint256[] maker_nonces, address[][] taker_tokens, address[][] maker_tokens, uint256[][] taker_amounts, uint256[][] maker_amounts, address receiver, bytes commands) order, (uint8 signatureType, bytes signatureBytes) takerSig, ((uint8 signatureType, bytes signatureBytes) signature, bool usingPermit2)[] makerSigs) payable returns (bool)", "SettleAggregateOrderWithTakerPermits": "function SettleAggregateOrderWithTakerPermits((uint256 expiry, address taker_address, address[] maker_addresses, uint256[] maker_nonces, address[][] taker_tokens, address[][] maker_tokens, uint256[][] taker_amounts, uint256[][] maker_amounts, address receiver, bytes commands) order, (uint8 signatureType, bytes signatureBytes) takerSig, ((uint8 signatureType, bytes signatureBytes) signature, bool usingPermit2)[] makerSigs, (bytes[] permitSignatures, bytes signatureBytesPermit2, uint48[] noncesPermit2, uint48 deadline) takerPermitsInfo) payable returns (bool)", "hashAggregateOrder": "function hashAggregateOrder((uint256 expiry, address taker_address, address[] maker_addresses, uint256[] maker_nonces, address[][] taker_tokens, address[][] maker_tokens, uint256[][] taker_amounts, uint256[][] maker_amounts, address receiver, bytes commands) order) view returns (bytes32)", "hashPartialOrder": "function hashPartialOrder((uint256 expiry, address taker_address, address maker_address, uint256 maker_nonce, address[] taker_tokens, address[] maker_tokens, uint256[] taker_amounts, uint256[] maker_amounts, address receiver, bytes commands) order) view returns (bytes32)", "Trade": "event Trade(address indexed owner, address sellToken, address buyToken, uint256 sellAmount, uint256 buyAmount, uint256 feeAmount, bytes orderUid)", // gnosis "swap": "function swap((bytes32 poolId, uint256 assetInIndex, uint256 assetOutIndex, uint256 amount, bytes userData)[] swaps, address[] tokens, (uint256 sellTokenIndex, uint256 buyTokenIndex, address receiver, uint256 sellAmount, uint256 buyAmount, uint32 validTo, bytes32 appData, uint256 feeAmount, uint256 flags, uint256 executedAmount, bytes signature) trade)", // gnosis "settle": "function settle(address[] tokens, uint256[] clearingPrices, (uint256 sellTokenIndex, uint256 buyTokenIndex, address receiver, uint256 sellAmount, uint256 buyAmount, uint32 validTo, bytes32 appData, uint256 feeAmount, uint256 flags, uint256 executedAmount, bytes signature)[] trades, (address target, uint256 value, bytes callData)[][3] interactions)", // gnosis "sellOrderSwap": "function sellOrderSwap((uint256 deadline, address tokenIn, uint256 amountIn, uint256 nonce, bytes signature, address allowanceTarget, address swapper, bytes swapData, address tokenOut, uint256 minAmountOut, (address recipient, uint256 shareBps)[] transferOut) _params) payable returns (uint256 _amountIn, uint256 _amountOut)", // maestro "swapAndDeposit": "function swapAndDeposit(address tokenToSell, address tokenToDeposit, (address router, address spender, uint256 amountIn, uint256 minAmountOut, bytes swapBytes) swapData) returns (uint256)", "swapAndDepositNative": "function swapAndDepositNative(address tokenToDeposit, (address router, address spender, uint256 amountIn, uint256 minAmountOut, bytes swapBytes) swapData) payable returns (uint256)", "swapAndDepositWithPermit": "function swapAndDepositWithPermit(address tokenToSell, address tokenToDeposit, (address router, address spender, uint256 amountIn, uint256 minAmountOut, bytes swapBytes) swapData, (uint256 amount, uint256 deadline, bytes32 r, bytes32 vs) permit) returns (uint256)", "swapAndDepositWithPermit2": "function swapAndDepositWithPermit2(address tokenToSell, address tokenToDeposit, (address router, address spender, uint256 amountIn, uint256 minAmountOut, bytes swapBytes) swapData, (uint256 amount, uint256 deadline, bytes32 r, bytes32 vs) permit) returns (uint256)", "swapAndWithdraw": "function swapAndWithdraw(address tokenToSell, address tokenToReceive, (address router, address spender, uint256 amountIn, uint256 minAmountOut, bytes swapBytes) swapData, address to) returns (uint256)", "swapAndWithdrawNative": "function swapAndWithdrawNative(address tokenToSell, (address router, address spender, uint256 amountIn, uint256 minAmountOut, bytes swapBytes) swapData, address to) returns (uint256 output)", "trade": "function trade((bytes32 positionId, int256 quantity, uint256 limitPrice, uint8 cashflowCcy, int256 cashflow) tradeParams, (address spender, address router, uint256 swapAmount, bytes swapBytes, address flashLoanProvider) execParams) returns (bytes32, (int256 quantity, (uint8 inputCcy, int256 input, int256 output, uint256 price) swap, uint8 cashflowCcy, int256 cashflow, uint256 fee, uint8 feeCcy, uint256 forwardPrice))", "tradeAndLinkedOrder": "function tradeAndLinkedOrder((bytes32 positionId, int256 quantity, uint256 limitPrice, uint8 cashflowCcy, int256 cashflow) tradeParams, (address spender, address router, uint256 swapAmount, bytes swapBytes, address flashLoanProvider) execParams, (uint128 limitPrice, uint128 tolerance, uint8 cashflowCcy, uint32 deadline, uint8 orderType) linkedOrderParams) payable returns (bytes32 positionId, (int256 quantity, (uint8 inputCcy, int256 input, int256 output, uint256 price) swap, uint8 cashflowCcy, int256 cashflow, uint256 fee, uint8 feeCcy, uint256 forwardPrice) trade_, bytes32 linkedOrderId)", "tradeAndLinkedOrders": "function tradeAndLinkedOrders((bytes32 positionId, int256 quantity, uint256 limitPrice, uint8 cashflowCcy, int256 cashflow) tradeParams, (address spender, address router, uint256 swapAmount, bytes swapBytes, address flashLoanProvider) execParams, (uint128 limitPrice, uint128 tolerance, uint8 cashflowCcy, uint32 deadline, uint8 orderType) linkedOrderParams1, (uint128 limitPrice, uint128 tolerance, uint8 cashflowCcy, uint32 deadline, uint8 orderType) linkedOrderParams2) payable returns (bytes32 positionId, (int256 quantity, (uint8 inputCcy, int256 input, int256 output, uint256 price) swap, uint8 cashflowCcy, int256 cashflow, uint256 fee, uint8 feeCcy, uint256 forwardPrice) trade_, bytes32 linkedOrderId1, bytes32 linkedOrderId2)", "tradeAndWithdraw": "function tradeAndWithdraw((bytes32 positionId, int256 quantity, uint256 limitPrice, uint8 cashflowCcy, int256 cashflow) tradeParams, (address spender, address router, uint256 swapAmount, bytes swapBytes, address flashLoanProvider) execParams, address to) returns (bytes32 positionId, (int256 quantity, (uint8 inputCcy, int256 input, int256 output, uint256 price) swap, uint8 cashflowCcy, int256 cashflow, uint256 fee, uint8 feeCcy, uint256 forwardPrice) trade_, uint256 amount)", "tradeAndWithdrawNative": "function tradeAndWithdrawNative((bytes32 positionId, int256 quantity, uint256 limitPrice, uint8 cashflowCcy, int256 cashflow) tradeParams, (address spender, address router, uint256 swapAmount, bytes swapBytes, address flashLoanProvider) execParams, address to) returns (bytes32 positionId, (int256 quantity, (uint8 inputCcy, int256 input, int256 output, uint256 price) swap, uint8 cashflowCcy, int256 cashflow, uint256 fee, uint8 feeCcy, uint256 forwardPrice) trade_, uint256 amount)", } const contract_interface = new ethers.Interface(Object.values(abis)); const JamContract = new ethers.Contract('0xbebebeb035351f58602e0c1c8b59ecbff5d5f47b', JAM_ABI) const jamAddress: any = { [CHAIN.ERA]:'0x574d1fcF950eb48b11de5DF22A007703cbD2b129', default: '0xbebebeb035351f58602e0c1c8b59ecbff5d5f47b' } const fetch = async (_:any, _1:any, { createBalances, getLogs, chain, api }: FetchOptions) => { const dailyVolume = createBalances() const cowswapData: any = {} const logs = await getLogs({ target: '0xBeB09000fa59627dc02Bb55448AC1893EAa501A5', topics: ['0xc59522161f93d59c8c4520b0e7a3635fb7544133275be812a4ea970f4f14251b'] // AggregateOrderExecuted }); if (chain === CHAIN.ETHEREUM) { const cowswapLogs = await getLogs({ target: '0x9008d19f58aabd9ed0d60971565aa8510560ab41', eventAbi: abis.Trade, onlyArgs: false, entireLog: true, }); cowswapLogs.forEach((log: any) => { cowswapData[log.transactionHash.toLowerCase()] = contract_interface.parseLog(log)?.args }) } const data: any = await getTransactions(chain, logs.map((log: any) => log.transactionHash), { cacheKey: 'bebop' }) for (const d of data) { if (!d) continue; const decoded = contract_interface.parseTransaction(d) if (!decoded) { api.log('no decoded', d.hash, d.input.slice(0, 10), d.to, chain) continue; } if (decoded.args.order) { const { order: { taker_tokens, taker_amounts } } = decoded.args as any dailyVolume.add(taker_tokens.flat(), taker_amounts.flat()) } else if (cowswapData[d.hash.toLowerCase()]) { const { buyToken, buyAmount } = cowswapData[d.hash.toLowerCase()] dailyVolume.add(buyToken, buyAmount) } else if (decoded.args._params?.minAmountOut) { const { tokenIn, amountIn } = decoded.args._params as any dailyVolume.add(tokenIn, amountIn) } else { api.log('no order', d.hash, d.input.slice(0, 10), d.to, chain, decoded.signature) } } const jamLogs = await getLogs({ target: jamAddress[chain] || jamAddress.default, topics: ['0x7a70845dec8dc098eecb16e760b0c1569874487f0459ae689c738e281b28ed38'] // Settlement, }); const jamData: any = await getTransactions(chain, jamLogs.map((log: any) => log.transactionHash), { cacheKey: 'bebop' }) for (const d of jamData) { if (!d) continue; const decoded = JamContract.interface.parseTransaction(d) if (!decoded) { api.log('jam no decoded', d.hash, d.input.slice(0, 10), d.to, chain) continue; } const {buyAmounts = [], sellAmounts = [], buyTokens = [], sellTokens = []} = decoded?.args?.order buyAmounts?.forEach((amount: any, i: number) => { dailyVolume.add(buyTokens[i], amount) }) sellAmounts?.forEach((amount: any, i: number) => { dailyVolume.add(sellTokens[i], amount) }) } return { dailyVolume } }; // Prefetch function that will run once before any fetch calls const prefetch = async (options: FetchOptions) => { return queryDuneSql(options, ` SELECT blockchain, SUM(amount_usd) AS vol FROM bebop.trades WHERE block_time >= from_unixtime(${options.startTimestamp}) AND block_time < from_unixtime(${options.endTimestamp}) GROUP BY blockchain `); }; async function fetchDune(_:any, _1:any, options: FetchOptions){ const results = options.preFetchedResults || []; const chainData = results.find((item: any) => item.blockchain.toLowerCase() === options.chain.toLowerCase()); // volume can be null let dailyVolume = 0 if (chainData) { dailyVolume = chainData.vol; } return { dailyVolume }; } const adapter: Adapter = { version: 1, isExpensiveAdapter: true, dependencies: [Dependencies.DUNE], adapter: { [CHAIN.ARBITRUM]: { fetch: fetchDune, start: '2023-05-31', }, [CHAIN.ETHEREUM]: { fetch: fetchDune, start: '2023-05-31', }, [CHAIN.POLYGON]: { fetch: fetchDune, start: '2023-05-31', }, [CHAIN.BSC]: { fetch: fetchDune, start: '2023-05-31', }, [CHAIN.BLAST]: { fetch, start: '2023-05-31', }, [CHAIN.ERA]: { fetch, start: '2023-05-31', }, [CHAIN.OPTIMISM]: { fetch: fetchDune, start: '2023-05-31', }, [CHAIN.MODE]: { fetch, start: '2023-05-31', }, [CHAIN.BASE]: { fetch: fetchDune, start: '2023-05-31', }, [CHAIN.SCROLL]: { fetch: fetchDune, start: '2023-05-31', }, [CHAIN.TAIKO]: { fetch, start: '2023-05-31', }, }, prefetch: prefetch, }; export default adapter; ================================================ FILE: aggregators/bebop/jamAbi.ts ================================================ const ABI = [ { inputs: [ { internalType: "address", name: "_permit2", type: "address" }, { internalType: "address", name: "_daiAddress", type: "address" }, ], stateMutability: "nonpayable", type: "constructor", }, { anonymous: false, inputs: [ { indexed: true, internalType: "address", name: "receiver", type: "address", }, { indexed: false, internalType: "uint256", name: "amount", type: "uint256", }, ], name: "NativeTransfer", type: "event", }, { anonymous: false, inputs: [ { indexed: true, internalType: "uint256", name: "nonce", type: "uint256", }, ], name: "Settlement", type: "event", }, { inputs: [], name: "DOMAIN_SEPARATOR", outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], stateMutability: "view", type: "function", }, { inputs: [], name: "EIP712_DOMAIN_TYPEHASH", outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], stateMutability: "view", type: "function", }, { inputs: [], name: "JAM_ORDER_TYPE_HASH", outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], stateMutability: "view", type: "function", }, { inputs: [], name: "balanceManager", outputs: [ { internalType: "contract IJamBalanceManager", name: "", type: "address", }, ], stateMutability: "view", type: "function", }, { inputs: [{ internalType: "uint256", name: "nonce", type: "uint256" }], name: "cancelLimitOrder", outputs: [], stateMutability: "nonpayable", type: "function", }, { inputs: [ { components: [ { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "beforeSettle", type: "tuple[]", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "afterSettle", type: "tuple[]", }, ], internalType: "struct JamHooks.Def", name: "hooks", type: "tuple", }, ], name: "hashHooks", outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], stateMutability: "pure", type: "function", }, { inputs: [ { components: [ { internalType: "address", name: "taker", type: "address" }, { internalType: "address", name: "receiver", type: "address" }, { internalType: "uint256", name: "expiry", type: "uint256" }, { internalType: "uint256", name: "nonce", type: "uint256" }, { internalType: "address", name: "executor", type: "address" }, { internalType: "uint16", name: "minFillPercent", type: "uint16" }, { internalType: "bytes32", name: "hooksHash", type: "bytes32" }, { internalType: "address[]", name: "sellTokens", type: "address[]" }, { internalType: "address[]", name: "buyTokens", type: "address[]" }, { internalType: "uint256[]", name: "sellAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "buyAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "sellNFTIds", type: "uint256[]" }, { internalType: "uint256[]", name: "buyNFTIds", type: "uint256[]" }, { internalType: "bytes", name: "sellTokenTransfers", type: "bytes" }, { internalType: "bytes", name: "buyTokenTransfers", type: "bytes" }, ], internalType: "struct JamOrder.Data", name: "order", type: "tuple", }, { internalType: "bytes32", name: "hooksHash", type: "bytes32" }, ], name: "hashOrder", outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], stateMutability: "view", type: "function", }, { inputs: [ { internalType: "address", name: "taker", type: "address" }, { internalType: "uint256", name: "nonce", type: "uint256" }, ], name: "isLimitOrderNonceValid", outputs: [{ internalType: "bool", name: "", type: "bool" }], stateMutability: "view", type: "function", }, { inputs: [ { internalType: "address", name: "", type: "address" }, { internalType: "address", name: "", type: "address" }, { internalType: "uint256[]", name: "", type: "uint256[]" }, { internalType: "uint256[]", name: "", type: "uint256[]" }, { internalType: "bytes", name: "", type: "bytes" }, ], name: "onERC1155BatchReceived", outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], stateMutability: "nonpayable", type: "function", }, { inputs: [ { internalType: "address", name: "", type: "address" }, { internalType: "address", name: "", type: "address" }, { internalType: "uint256", name: "", type: "uint256" }, { internalType: "uint256", name: "", type: "uint256" }, { internalType: "bytes", name: "", type: "bytes" }, ], name: "onERC1155Received", outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], stateMutability: "nonpayable", type: "function", }, { inputs: [ { internalType: "address", name: "", type: "address" }, { internalType: "address", name: "", type: "address" }, { internalType: "uint256", name: "", type: "uint256" }, { internalType: "bytes", name: "", type: "bytes" }, ], name: "onERC721Received", outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], stateMutability: "nonpayable", type: "function", }, { inputs: [ { components: [ { internalType: "address", name: "taker", type: "address" }, { internalType: "address", name: "receiver", type: "address" }, { internalType: "uint256", name: "expiry", type: "uint256" }, { internalType: "uint256", name: "nonce", type: "uint256" }, { internalType: "address", name: "executor", type: "address" }, { internalType: "uint16", name: "minFillPercent", type: "uint16" }, { internalType: "bytes32", name: "hooksHash", type: "bytes32" }, { internalType: "address[]", name: "sellTokens", type: "address[]" }, { internalType: "address[]", name: "buyTokens", type: "address[]" }, { internalType: "uint256[]", name: "sellAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "buyAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "sellNFTIds", type: "uint256[]" }, { internalType: "uint256[]", name: "buyNFTIds", type: "uint256[]" }, { internalType: "bytes", name: "sellTokenTransfers", type: "bytes" }, { internalType: "bytes", name: "buyTokenTransfers", type: "bytes" }, ], internalType: "struct JamOrder.Data", name: "order", type: "tuple", }, { components: [ { internalType: "enum Signature.Type", name: "signatureType", type: "uint8", }, { internalType: "bytes", name: "signatureBytes", type: "bytes" }, ], internalType: "struct Signature.TypedSignature", name: "signature", type: "tuple", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "interactions", type: "tuple[]", }, { components: [ { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "beforeSettle", type: "tuple[]", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "afterSettle", type: "tuple[]", }, ], internalType: "struct JamHooks.Def", name: "hooks", type: "tuple", }, { components: [ { internalType: "address", name: "balanceRecipient", type: "address", }, { internalType: "uint16", name: "curFillPercent", type: "uint16" }, ], internalType: "struct ExecInfo.SolverData", name: "solverData", type: "tuple", }, ], name: "settle", outputs: [], stateMutability: "payable", type: "function", }, { inputs: [ { components: [ { internalType: "address", name: "taker", type: "address" }, { internalType: "address", name: "receiver", type: "address" }, { internalType: "uint256", name: "expiry", type: "uint256" }, { internalType: "uint256", name: "nonce", type: "uint256" }, { internalType: "address", name: "executor", type: "address" }, { internalType: "uint16", name: "minFillPercent", type: "uint16" }, { internalType: "bytes32", name: "hooksHash", type: "bytes32" }, { internalType: "address[]", name: "sellTokens", type: "address[]" }, { internalType: "address[]", name: "buyTokens", type: "address[]" }, { internalType: "uint256[]", name: "sellAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "buyAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "sellNFTIds", type: "uint256[]" }, { internalType: "uint256[]", name: "buyNFTIds", type: "uint256[]" }, { internalType: "bytes", name: "sellTokenTransfers", type: "bytes" }, { internalType: "bytes", name: "buyTokenTransfers", type: "bytes" }, ], internalType: "struct JamOrder.Data[]", name: "orders", type: "tuple[]", }, { components: [ { internalType: "enum Signature.Type", name: "signatureType", type: "uint8", }, { internalType: "bytes", name: "signatureBytes", type: "bytes" }, ], internalType: "struct Signature.TypedSignature[]", name: "signatures", type: "tuple[]", }, { components: [ { internalType: "bytes[]", name: "permitSignatures", type: "bytes[]", }, { internalType: "bytes", name: "signatureBytesPermit2", type: "bytes", }, { internalType: "uint48[]", name: "noncesPermit2", type: "uint48[]" }, { internalType: "uint48", name: "deadline", type: "uint48" }, ], internalType: "struct Signature.TakerPermitsInfo[]", name: "takersPermitsInfo", type: "tuple[]", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "interactions", type: "tuple[]", }, { components: [ { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "beforeSettle", type: "tuple[]", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "afterSettle", type: "tuple[]", }, ], internalType: "struct JamHooks.Def[]", name: "hooks", type: "tuple[]", }, { components: [ { internalType: "address", name: "balanceRecipient", type: "address", }, { internalType: "uint16[]", name: "curFillPercents", type: "uint16[]", }, { internalType: "bool[]", name: "takersPermitsUsage", type: "bool[]", }, { internalType: "bool", name: "transferExactAmounts", type: "bool" }, ], internalType: "struct ExecInfo.BatchSolverData", name: "solverData", type: "tuple", }, ], name: "settleBatch", outputs: [], stateMutability: "payable", type: "function", }, { inputs: [ { components: [ { internalType: "address", name: "taker", type: "address" }, { internalType: "address", name: "receiver", type: "address" }, { internalType: "uint256", name: "expiry", type: "uint256" }, { internalType: "uint256", name: "nonce", type: "uint256" }, { internalType: "address", name: "executor", type: "address" }, { internalType: "uint16", name: "minFillPercent", type: "uint16" }, { internalType: "bytes32", name: "hooksHash", type: "bytes32" }, { internalType: "address[]", name: "sellTokens", type: "address[]" }, { internalType: "address[]", name: "buyTokens", type: "address[]" }, { internalType: "uint256[]", name: "sellAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "buyAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "sellNFTIds", type: "uint256[]" }, { internalType: "uint256[]", name: "buyNFTIds", type: "uint256[]" }, { internalType: "bytes", name: "sellTokenTransfers", type: "bytes" }, { internalType: "bytes", name: "buyTokenTransfers", type: "bytes" }, ], internalType: "struct JamOrder.Data", name: "order", type: "tuple", }, { components: [ { internalType: "enum Signature.Type", name: "signatureType", type: "uint8", }, { internalType: "bytes", name: "signatureBytes", type: "bytes" }, ], internalType: "struct Signature.TypedSignature", name: "signature", type: "tuple", }, { components: [ { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "beforeSettle", type: "tuple[]", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "afterSettle", type: "tuple[]", }, ], internalType: "struct JamHooks.Def", name: "hooks", type: "tuple", }, { components: [ { internalType: "uint256[]", name: "increasedBuyAmounts", type: "uint256[]", }, { internalType: "uint16", name: "curFillPercent", type: "uint16" }, ], internalType: "struct ExecInfo.MakerData", name: "makerData", type: "tuple", }, ], name: "settleInternal", outputs: [], stateMutability: "payable", type: "function", }, { inputs: [ { components: [ { internalType: "address", name: "taker", type: "address" }, { internalType: "address", name: "receiver", type: "address" }, { internalType: "uint256", name: "expiry", type: "uint256" }, { internalType: "uint256", name: "nonce", type: "uint256" }, { internalType: "address", name: "executor", type: "address" }, { internalType: "uint16", name: "minFillPercent", type: "uint16" }, { internalType: "bytes32", name: "hooksHash", type: "bytes32" }, { internalType: "address[]", name: "sellTokens", type: "address[]" }, { internalType: "address[]", name: "buyTokens", type: "address[]" }, { internalType: "uint256[]", name: "sellAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "buyAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "sellNFTIds", type: "uint256[]" }, { internalType: "uint256[]", name: "buyNFTIds", type: "uint256[]" }, { internalType: "bytes", name: "sellTokenTransfers", type: "bytes" }, { internalType: "bytes", name: "buyTokenTransfers", type: "bytes" }, ], internalType: "struct JamOrder.Data", name: "order", type: "tuple", }, { components: [ { internalType: "enum Signature.Type", name: "signatureType", type: "uint8", }, { internalType: "bytes", name: "signatureBytes", type: "bytes" }, ], internalType: "struct Signature.TypedSignature", name: "signature", type: "tuple", }, { components: [ { internalType: "bytes[]", name: "permitSignatures", type: "bytes[]", }, { internalType: "bytes", name: "signatureBytesPermit2", type: "bytes", }, { internalType: "uint48[]", name: "noncesPermit2", type: "uint48[]" }, { internalType: "uint48", name: "deadline", type: "uint48" }, ], internalType: "struct Signature.TakerPermitsInfo", name: "takerPermitsInfo", type: "tuple", }, { components: [ { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "beforeSettle", type: "tuple[]", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "afterSettle", type: "tuple[]", }, ], internalType: "struct JamHooks.Def", name: "hooks", type: "tuple", }, { components: [ { internalType: "uint256[]", name: "increasedBuyAmounts", type: "uint256[]", }, { internalType: "uint16", name: "curFillPercent", type: "uint16" }, ], internalType: "struct ExecInfo.MakerData", name: "makerData", type: "tuple", }, ], name: "settleInternalWithPermitsSignatures", outputs: [], stateMutability: "payable", type: "function", }, { inputs: [ { components: [ { internalType: "address", name: "taker", type: "address" }, { internalType: "address", name: "receiver", type: "address" }, { internalType: "uint256", name: "expiry", type: "uint256" }, { internalType: "uint256", name: "nonce", type: "uint256" }, { internalType: "address", name: "executor", type: "address" }, { internalType: "uint16", name: "minFillPercent", type: "uint16" }, { internalType: "bytes32", name: "hooksHash", type: "bytes32" }, { internalType: "address[]", name: "sellTokens", type: "address[]" }, { internalType: "address[]", name: "buyTokens", type: "address[]" }, { internalType: "uint256[]", name: "sellAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "buyAmounts", type: "uint256[]" }, { internalType: "uint256[]", name: "sellNFTIds", type: "uint256[]" }, { internalType: "uint256[]", name: "buyNFTIds", type: "uint256[]" }, { internalType: "bytes", name: "sellTokenTransfers", type: "bytes" }, { internalType: "bytes", name: "buyTokenTransfers", type: "bytes" }, ], internalType: "struct JamOrder.Data", name: "order", type: "tuple", }, { components: [ { internalType: "enum Signature.Type", name: "signatureType", type: "uint8", }, { internalType: "bytes", name: "signatureBytes", type: "bytes" }, ], internalType: "struct Signature.TypedSignature", name: "signature", type: "tuple", }, { components: [ { internalType: "bytes[]", name: "permitSignatures", type: "bytes[]", }, { internalType: "bytes", name: "signatureBytesPermit2", type: "bytes", }, { internalType: "uint48[]", name: "noncesPermit2", type: "uint48[]" }, { internalType: "uint48", name: "deadline", type: "uint48" }, ], internalType: "struct Signature.TakerPermitsInfo", name: "takerPermitsInfo", type: "tuple", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "interactions", type: "tuple[]", }, { components: [ { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "beforeSettle", type: "tuple[]", }, { components: [ { internalType: "bool", name: "result", type: "bool" }, { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, ], internalType: "struct JamInteraction.Data[]", name: "afterSettle", type: "tuple[]", }, ], internalType: "struct JamHooks.Def", name: "hooks", type: "tuple", }, { components: [ { internalType: "address", name: "balanceRecipient", type: "address", }, { internalType: "uint16", name: "curFillPercent", type: "uint16" }, ], internalType: "struct ExecInfo.SolverData", name: "solverData", type: "tuple", }, ], name: "settleWithPermitsSignatures", outputs: [], stateMutability: "payable", type: "function", }, { inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], name: "supportsInterface", outputs: [{ internalType: "bool", name: "", type: "bool" }], stateMutability: "view", type: "function", }, { inputs: [ { internalType: "address", name: "receiver", type: "address" }, { internalType: "uint256", name: "amount", type: "uint256" }, ], name: "transferNativeFromContract", outputs: [], stateMutability: "nonpayable", type: "function", }, { inputs: [ { internalType: "address", name: "validationAddress", type: "address" }, { internalType: "bytes32", name: "hash", type: "bytes32" }, { components: [ { internalType: "enum Signature.Type", name: "signatureType", type: "uint8", }, { internalType: "bytes", name: "signatureBytes", type: "bytes" }, ], internalType: "struct Signature.TypedSignature", name: "signature", type: "tuple", }, ], name: "validateSignature", outputs: [], stateMutability: "view", type: "function", }, { stateMutability: "payable", type: "receive" }, ]; export default ABI; ================================================ FILE: aggregators/bim/config.ts ================================================ import { CHAIN } from "../../helpers/chains"; const SocketGatewayContracts: { [key: string]: string } = { [CHAIN.ETHEREUM]: '0x3a23f943181408eac424116af7b7790c94cb97a5', [CHAIN.ARBITRUM]: '0x3a23f943181408eac424116af7b7790c94cb97a5', [CHAIN.OPTIMISM]: '0x3a23f943181408eac424116af7b7790c94cb97a5', [CHAIN.BASE]: '0x3a23f943181408eac424116af7b7790c94cb97a5', [CHAIN.BSC]: '0x3a23f943181408eac424116af7b7790c94cb97a5', [CHAIN.POLYGON]: '0x3a23f943181408eac424116af7b7790c94cb97a5', } const BungeeGatewayContracts: { [key: string]: { audited: Array; unaudited: Array; } } = { [CHAIN.ETHEREUM]: { audited: [], unaudited: ['0xe772551F88E2c14aEcC880dF6b7CBd574561bf82'], }, [CHAIN.OPTIMISM]: { audited: ['0x09DAbdD517Ff1e155DeDEF64EC629Ca0285a31af'], unaudited: ['0x9c366293ba7e893cE184d75794330d674E4D17c2'] }, [CHAIN.BASE]: { audited: ['0x84F06fBaCc4b64CA2f72a4B26191DAD97f2b52BA'], unaudited: ['0x01710cdb7319292ed50a3f92561a599f5c650e2c'], }, [CHAIN.ARBITRUM]: { audited: ['0xCdEa28Ee7BD5bf7710B294d9391e1b6A318d809a'], unaudited: ['0x8d00ad02df0c7b0c379bc1cb49fd74aa10698bfc'], }, [CHAIN.BSC]: { audited: ['0x9aF2b913679049c966b77934af4CbE7Bb36Cf9D3'], unaudited: ['0x6a138b12be537e3b47328d627c1699bfaaaa68ce'], }, [CHAIN.POLYGON]: { audited: ['0x6DDe7CF4e6A6f53F058Bf5d2B4a54aFBba11EE54'], unaudited: ['0x652e1b759516fe79b2b63753f1c7b3c44faa3df8'], }, [CHAIN.XDAI]: { audited: [ '0x5e01dbBBe59F8987673FAdD1469DdD2Be71e00af', ], unaudited: ['0x8f503B6d9fFdae8d375d1E226b71B4B3144D3849'], }, [CHAIN.PLASMA]: { audited: ['0x8f503B6d9fFdae8d375d1E226b71B4B3144D3849'], unaudited: [], }, } export function fetchBimChains(): Array { const chains: { [key: string]: boolean } = {} for (const chain of Object.keys(SocketGatewayContracts).concat(Object.keys(BungeeGatewayContracts))) { chains[chain] = true } return Object.keys(chains) } ================================================ FILE: aggregators/bim/index.ts ================================================ import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { fetchBungeeData } from "../../helpers/aggregators/bungee"; import { fetchBimChains } from "./config"; const fetch: any = async (options: FetchOptions): Promise => { const { dailyVolume } = await fetchBungeeData(options, { swapVolume: true }, '2758') return { dailyVolume, }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, doublecounted: true, //Bungee adapter: fetchBimChains().reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2026-01-13', } } }, {}) }; export default adapter; ================================================ FILE: aggregators/binancewallet/index.ts ================================================ import { Dependencies, FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; import { CHAIN } from "../../helpers/chains"; import { getAllDexTokensBlacklisted } from "../../helpers/lists"; const chainsMap: Record = { [CHAIN.ETHEREUM]: 'ethereum', [CHAIN.ARBITRUM]: 'arbitrum', [CHAIN.POLYGON]: 'polygon', [CHAIN.BSC]: 'bnb', [CHAIN.AVAX]: 'avalanche_c', [CHAIN.OPTIMISM]: 'optimism', [CHAIN.BASE]: 'base', [CHAIN.LINEA]: 'linea', [CHAIN.SONIC]: 'sonic', [CHAIN.ERA]: 'zksync', [CHAIN.SOLANA]: 'solana', [CHAIN.PLASMA]: 'plasma' }; const prefetch = async (options: FetchOptions) => { const blacklisted = getAllDexTokensBlacklisted(); const sql_query = ` with sol as ( select tx_id , blockchain , block_time , trader_id tx_from , sum(amount_usd) amount_usd from dex_solana.trades where 1 = 1 and TIME_RANGE and block_month >= date '2025-01-01' group by 1 , 2 , 3 , 4 ) , binance_wallet_tx as ( select id as tx_id , block_date from solana.transactions , unnest (post_token_balances) as t (account, mint, owner, amount) , unnest (pre_token_balances) as t2 (account, mint, owner, amount) where ( t.owner in ('B3111yJCeHBcA1bizdJjUFPALfhAfSRnAbJzGUtnt56A') or t2.owner in ('B3111yJCeHBcA1bizdJjUFPALfhAfSRnAbJzGUtnt56A') or contains(account_keys, 'B3111yJCeHBcA1bizdJjUFPALfhAfSRnAbJzGUtnt56A') ) and TIME_RANGE and success = true group by 1, 2 ) , evm as ( select tx_hash , blockchain , tx_from , tx_to , block_date , evt_index , amount_usd from dex.trades where tx_to in ( 0xb300000b72DEAEb607a12d5f54773D1C19c7028d, -- all others 0x45a0B6ac062a6F137dDC12C01E580cfed1A6F4EC, -- zksync 0xe8B592a331a192d5988EFFff40586CF032e26277, -- linena 0x610776e63C5ca21B92217F4c06398E5437dB6A1E --sonic and plasma ) and not amount_usd is null and TIME_RANGE and token_sold_address NOT IN (${blacklisted.toString()}) and token_bought_address NOT IN (${blacklisted.toString()}) ) , total as ( select blockchain , sum(a.amount_usd) as trading_volume from sol a inner join binance_wallet_tx b on a.tx_id = b.tx_id where a.amount_usd < 10000000 group by 1 union all select blockchain , SUM(amount_usd) as trading_volume from evm where amount_usd < 10000000 group by 1 ) select blockchain , sum(trading_volume) as volume_24h from total group by 1 `; const result = await queryDuneSql(options, sql_query); return result; }; const fetch = async (_a: any, _b: any, options: FetchOptions): Promise => { const results = options.preFetchedResults || []; const chainData = results.find((item: any) => item.blockchain === chainsMap[options.chain]); return { dailyVolume: chainData ? chainData.volume_24h : 0, }; }; const adapter: SimpleAdapter = { version: 1, dependencies: [Dependencies.DUNE], fetch, chains: Object.keys(chainsMap), start: "2025-01-01", prefetch, isExpensiveAdapter: true, }; export default adapter; ================================================ FILE: aggregators/bitgetwallet/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const historicalVolumeEndpoint = "https://api-3rd.bitkeep.com/swap-go/open/getOrderDayVolume" interface IVolumeall { volume: string; date: string; } //https://dune.com/queries/5561137/9053445 const inflatedApiVolumes: Record = { [CHAIN.SOLANA]: [ { date: "2026-03-22", realVolume: 2681396 } ], [CHAIN.ETHEREUM]: [ { date: "2026-04-11", realVolume: 10274944 } ], [CHAIN.BSC]: [ { date: "2026-04-23", realVolume: 1928246 }, { date: "2026-04-26", realVolume: 7203337 }, ] } // to compute volume on chain: https://github.com/DefiLlama/dimension-adapters/pull/2059#issuecomment-2469986758 const fetch = async (_a: any, _b: any, options: FetchOptions) => { if (inflatedApiVolumes[options.chain]) { const realVolume = inflatedApiVolumes[options.chain].find(item => item.date === options.dateString)?.realVolume; if (realVolume) return { dailyVolume: realVolume } } const historicalVolume: IVolumeall[] = (await fetchURL(historicalVolumeEndpoint + `?chain=${options.chain}`))?.data?.list; const dailyVolume = historicalVolume?.find(dayItem => (new Date(dayItem.date).getTime() / 1000) === options.startOfDay)?.volume return { dailyVolume }; } const CHAINS: Array = [ CHAIN.APTOS, CHAIN.HYPERLIQUID, CHAIN.SOLANA, CHAIN.BLAST, CHAIN.BITCOIN, CHAIN.ARBITRUM, CHAIN.KLAYTN, CHAIN.SONIC, CHAIN.MANTLE, CHAIN.RIPPLE, CHAIN.AVAX, CHAIN.LINEA, CHAIN.SUI, CHAIN.SCROLL, CHAIN.BASE, CHAIN.POLYGON, CHAIN.TON, CHAIN.CRONOS, CHAIN.DOGECHAIN, CHAIN.BERACHAIN, CHAIN.MONAD, CHAIN.TRON, CHAIN.CELO, CHAIN.BSC, CHAIN.MORPH, CHAIN.XLAYER, CHAIN.CORE, CHAIN.OP_BNB, CHAIN.ZKSYNC, CHAIN.ETHEREUM, CHAIN.OPTIMISM, CHAIN.FANTOM, CHAIN.PLASMA, CHAIN.SEI ]; const adapter: SimpleAdapter = { version: 1, fetch, chains: CHAINS, start: '2025-04-01', runAtCurrTime: true, //API has results only for the latest day }; export default adapter; ================================================ FILE: aggregators/bluefin7k-aggregator/index.ts ================================================ import fetchURL from '../../utils/fetchURL'; import { FetchV2, SimpleAdapter } from '../../adapters/types'; import { CHAIN } from '../../helpers/chains'; // Bluefin7K Aggregator temporary use 7k.ag API to get volume data const URL = 'https://statistic.7k.ag'; const fetch: FetchV2 = async ({ fromTimestamp, toTimestamp }) => { const dailyVolume = await fetchURL( `${URL}/volume-with-ts?from_timestamp=${fromTimestamp}&to_timestamp=${toTimestamp}`, ); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.SUI]: { fetch, start: '2025-06-03', }, }, }; export default adapter; ================================================ FILE: aggregators/bountive/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = 'https://api.bountive.fi/metrics/volume/'; interface IAPIResponse { date: number; dailyVolume: string; } const fetch = async ({ endTimestamp, startTimestamp }: FetchOptions) => { const { dailyVolume }: IAPIResponse = await fetchURL( `${URL}${startTimestamp * 1000}/${endTimestamp * 1000}`, ); return { dailyVolume, }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.STARKNET]: { fetch: fetch, start: '2024-11-20', }, }, }; export default adapter; ================================================ FILE: aggregators/bungee-dex.ts ================================================ import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../adapters/types"; import { fetchBungeeChains, fetchBungeeData } from "../helpers/aggregators/bungee"; const fetch: any = async (options: FetchOptions): Promise => { const { dailyVolume } = await fetchBungeeData(options, { swapVolume: true }) return { dailyVolume, }; }; const adapter: SimpleAdapter = { pullHourly: true, version: 2, adapter: fetchBungeeChains().reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2023-08-10', } } }, {}) }; export default adapter; ================================================ FILE: aggregators/bytzz/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; const fetch = async (_:any, _1:any, { startOfDay }: FetchOptions) => { const data = await fetchURL( `https://bytzz.xyz/api/stats?timestamp=${startOfDay}` ); if (!data) throw new Error("No data"); return { dailyVolume: data?.volume24h, }; }; const adapter: SimpleAdapter = { fetch, start: "2025-08-26", methodology: { Volume: "Volume from Bytzz", }, chains: [CHAIN.XLAYER], }; export default adapter; ================================================ FILE: aggregators/carina-aggregator/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = "https://core.carina.finance/v1/orders/volume"; const fetch = async ({ fromTimestamp, toTimestamp }: FetchOptions) => { const response = await fetchURL( `${URL}?startTimestamp=${fromTimestamp}&endTimestamp=${toTimestamp}`, ); return { dailyVolume: response.data.volume }; }; export default { version: 2, adapter: { [CHAIN.SEI]: { fetch, start: "2025-11-03", }, }, }; ================================================ FILE: aggregators/cetus-aggregator/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; import { FetchOptions } from "../../adapters/types"; const fetchVolume = async (options: FetchOptions) => { const url = `https://api-sui.cetus.zone/v3/sui/vol/aggregator/time_range?date_type=hour&start_time=${options.startTimestamp}&end_time=${options.endTimestamp}`; const res = await httpGet(url); return { dailyVolume: res.data.vol_in_usd, } }; const adapter_agge: any = { version: 2, adapter: { [CHAIN.SUI]: { fetch: fetchVolume, start: '2024-07-18', }, }, }; export default adapter_agge; ================================================ FILE: aggregators/chainspot/index.ts ================================================ import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; const chains = [ CHAIN.ETHEREUM, CHAIN.POLYGON, CHAIN.BSC, CHAIN.AVAX, CHAIN.OPTIMISM, CHAIN.FANTOM, CHAIN.ARBITRUM, CHAIN.AURORA, CHAIN.CELO, CHAIN.BOBA, CHAIN.XDAI, CHAIN.TELOS, CHAIN.BASE, CHAIN.LINEA, CHAIN.MANTLE, CHAIN.MOONBEAM, CHAIN.CRONOS, CHAIN.BLAST, CHAIN.EVMOS, CHAIN.FUSE, CHAIN.HARMONY, CHAIN.KAVA, CHAIN.MOONRIVER, CHAIN.OKEXCHAIN, CHAIN.SCROLL, CHAIN.TRON, CHAIN.TON, CHAIN.WAN, CHAIN.ZKLINK, CHAIN.ZKSYNC, ]; const chainToId: Record = { [CHAIN.ETHEREUM]: 1, [CHAIN.POLYGON]: 137, [CHAIN.BSC]: 56, [CHAIN.AVAX]: 43114, [CHAIN.OPTIMISM]: 10, [CHAIN.FANTOM]: 250, [CHAIN.ARBITRUM]: 42161, [CHAIN.AURORA]: 1313161554, [CHAIN.CELO]: 42220, [CHAIN.BOBA]: 288, [CHAIN.XDAI]: 100, [CHAIN.TELOS]: 40, [CHAIN.BASE]: 8453, [CHAIN.LINEA]: 59144, [CHAIN.MANTLE]: 5000, [CHAIN.MOONBEAM]: 1284, [CHAIN.CRONOS]: 25, [CHAIN.BLAST]: 81457, [CHAIN.EVMOS]: 9001, [CHAIN.FUSE]: 122, [CHAIN.HARMONY]: 1666600000, [CHAIN.KAVA]: 2222, [CHAIN.MOONRIVER]: 1285, [CHAIN.OKEXCHAIN]: 66, [CHAIN.SCROLL]: 534352, [CHAIN.TRON]: 728126428, [CHAIN.TON]: -239, [CHAIN.WAN]: 888, [CHAIN.ZKLINK]: 810180, [CHAIN.ZKSYNC]: 324, }; const fetch = async (_at: number, _t: any, options: FetchOptions) => { const startOfDay = options.startOfDay const url = `https://app.chainspot.io/api/2.0/statistic/daily-volume?chainId=${chainToId[options.chain]}×tamp=${startOfDay * 1e3}`; const volume = ( await httpGet(url) )?.volume; return { dailyVolume: volume || 0, }; }; const adapter: SimpleAdapter = { fetch, chains, }; export default adapter; ================================================ FILE: aggregators/chimpx/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; // ChimpXVolumeRegistry deployed on BSC mainnet at block 82131810 // https://bscscan.com/address/0x8327839597934e1490f90D06F2b0A549dFC7edeB const VOLUME_REGISTRY = "0x8327839597934e1490f90D06F2b0A549dFC7edeB"; // VolumeRegistered(address indexed user, uint8 indexed actionType, uint256 volumeUsd, bytes32 txRef, uint256 timestamp) const EVENT_ABI = "event VolumeRegistered(address indexed user, uint8 indexed actionType, uint256 volumeUsd, bytes32 txRef, uint256 timestamp)"; const fetch = async (options: FetchOptions): Promise => { const dailyVolume = options.createBalances(); // Trust model: volumeUsd values are relayer-attested. The ChimpX backend // relayer calls registerVolume() on-chain after verifying each completed // transaction (swap, bridge, lend, borrow, stake, perps) via the underlying // protocol's own on-chain receipt. The relayer wallet address is public and // auditable on BSCScan. Volume figures are denominated in USD with 18 decimals // and correspond to the input/output token value of the routed transaction. const logs = await options.getLogs({ target: VOLUME_REGISTRY, eventAbi: EVENT_ABI, }); for (const log of logs) { // volumeUsd is stored with 18 decimals; addUSDValue expects a plain number const volumeUsd = Number(log.volumeUsd) / 1e18; dailyVolume.addUSDValue(volumeUsd); } return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.BSC]: { fetch, start: '2026-02-19', }, }, methodology: { Volume: "Volume is tracked via VolumeRegistered events emitted by the ChimpXVolumeRegistry contract on BNB Chain. The ChimpX backend relayer records USD volume (18 decimals) on-chain after each verified transaction. Covers swaps, bridges, lending, borrowing, staking, unstaking, and perpetuals (long/short) routed through the ChimpX AI-powered DeFi agent.", }, }; export default adapter; ================================================ FILE: aggregators/conveyor/index.ts ================================================ import { Dependencies, FetchOptions, FetchResult, SimpleAdapter, } from "../../adapters/types"; import { getSqlFromFile, queryDuneSql } from "../../helpers/dune"; import { CHAIN } from "../../helpers/chains"; const chainsMap: Record = { ETHEREUM: CHAIN.ETHEREUM, ARBITRUM: CHAIN.ARBITRUM, POLYGON: CHAIN.POLYGON, BNB: CHAIN.BSC, OPTIMISM: CHAIN.OPTIMISM, BASE: CHAIN.BASE, }; const prefetch = async (options: FetchOptions) => { const sql_query = getSqlFromFile('helpers/queries/conveyor.sql', {startTimestamp: options.startTimestamp, endTimestamp: options.endTimestamp}) return await queryDuneSql(options, sql_query); } const fetch = async (_a:any, _b:any, options: FetchOptions): Promise => { const results = options.preFetchedResults || []; const chainData = results.find((item: any) => chainsMap[item.blockchain] === options.chain.toLowerCase()); return { dailyVolume: chainData?.volume_24h || 0, }; } const adapter: SimpleAdapter = { version: 1, dependencies: [Dependencies.DUNE], adapter: { ...Object.values(chainsMap).reduce((acc, chain) => { return { ...acc, [(chainsMap as any)[chain] || chain]: { fetch: fetch, runAtCurrTime: true, start: '2023-08-24', }, }; }, {}), }, prefetch, isExpensiveAdapter: true, }; export default adapter; ================================================ FILE: aggregators/cowswap/index.ts ================================================ import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const abis = { "Trade": "event Trade(address indexed owner, address sellToken, address buyToken, uint256 sellAmount, uint256 buyAmount, uint256 feeAmount, bytes orderUid)", // gnosis } const fetch = async ({ createBalances, getLogs, }: FetchOptions) => { const dailyVolume = createBalances() const logs = await getLogs({ target: '0x9008d19f58aabd9ed0d60971565aa8510560ab41', eventAbi: abis.Trade, }) logs.forEach((log: any) => { dailyVolume.add(log.buyToken, log.buyAmount) }) return { dailyVolume } }; const adapter: any = { version: 2, fetch, adapter: { [CHAIN.ETHEREUM]: { start: '2023-05-31', }, [CHAIN.XDAI]: { start: '2023-05-31', }, [CHAIN.ARBITRUM]: { start: '2024-04-26', }, [CHAIN.BASE]: { start: '2024-12-10', }, [CHAIN.POLYGON]: { start: '2023-12-10', }, [CHAIN.AVAX]: { start: '2025-03-10', }, [CHAIN.LENS]: { start: '2025-06-16', }, [CHAIN.BSC]: { start: '2025-09-04', }, }, }; export default adapter; ================================================ FILE: aggregators/cro-ag/index.ts ================================================ import { CHAIN } from '../../helpers/chains' import { httpGet } from '../../utils/fetchURL' import { FetchOptions } from '../../adapters/types' const fetchVolume = async (options: FetchOptions) => { const url = `https://cro.ag/api/volume?start_time=${options.startTimestamp}&end_time=${options.endTimestamp}` const res = await httpGet(url) return { dailyVolume: res.data.vol_in_usd, } } const adapter: any = { version: 2, adapter: { [CHAIN.SUI]: { fetch: fetchVolume, start: '2025-03-19', }, }, } export default adapter ================================================ FILE: aggregators/dedust/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { Dependencies, FetchOptions } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const data = await queryDuneSql( options, ` WITH jetton_query AS ( SELECT trace_id, block_time, block_date, MAX(query_id) AS query_id FROM ton.jetton_events WHERE block_time >= from_unixtime(${options.startTimestamp}) AND block_time < from_unixtime(${options.endTimestamp}) GROUP BY trace_id, block_time, block_date ) SELECT SUM(dt.volume_usd) as volume_usd FROM ton.dex_trades AS dt LEFT JOIN jetton_query AS je ON dt.trace_id = je.trace_id AND dt.block_time = je.block_time WHERE BITWISE_RIGHT_SHIFT(COALESCE(dt.query_id, je.query_id), 32) = 988556692 AND dt.block_time >= from_unixtime(${options.startTimestamp}) AND dt.block_time < from_unixtime(${options.endTimestamp}); `, ); const chainData = data[0]; if (!chainData) throw new Error(`Dune query failed: ${JSON.stringify(data)}`); return { dailyVolume: chainData.volume_usd || "0", }; }; const adapter: any = { version: 1, dependencies: [Dependencies.DUNE], fetch, start: "2025-03-14", methodology: { Volume: "Volume is calculated by summing the USD volume of all trades routed through the DeDust aggregator that day.", }, chains: [CHAIN.TON], }; export default adapter; ================================================ FILE: aggregators/defiapp/index.ts ================================================ import { SimpleAdapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getEnv } from "../../helpers/env"; import { httpGet } from "../../utils/fetchURL"; const defiAppChainIdMap: Record = { [CHAIN.ETHEREUM]: { id: "1", start: "2025-02-13", }, [CHAIN.BSC]: { id: "56", start: "2025-02-13", }, [CHAIN.ARBITRUM]: { id: "42161", start: "2025-02-13", }, [CHAIN.SOLANA]: { id: "1151111081099710", start: "2025-02-13", }, [CHAIN.BASE]: { id: "8453", start: "2025-02-13", }, }; const tsToISO = (ts: number) => new Date(ts * 1e3).toISOString() const prefetch = async (options: FetchOptions) => { const res = await httpGet(`https://api.defi.app/api/stats/volume/between?startRefTime=${tsToISO(options.startTimestamp)}&endRefTime=${tsToISO(options.endTimestamp)}`, { headers: { "Content-Type": "application/json", "X-API-KEY": getEnv('DEFIAPP_API_KEY'), User: "defillama", }, }); return res; } const fetch = async (options: FetchOptions) => { const results = await options.preFetchedResults || []; const dailyVolume = results.perChainUsdVolume[defiAppChainIdMap[options.chain].id]; return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, adapter: Object.fromEntries( Object.entries(defiAppChainIdMap).map(([chain, config]) => [ chain, { fetch, start: config.start } ]) ), prefetch }; export default adapter; ================================================ FILE: aggregators/deluthium/index.ts ================================================ import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from "../../helpers/prices"; const quoteSettledEvent = `event QuoteSettled( address indexed maker, address indexed payer, address indexed inputToken, bytes32 quoteId, address to, address vault, address outputToken, uint256 grossAmountIn, uint256 feeAmount, address feeTo, uint256 amountOut, uint256 nonce )`; const settlementContracts: Record = { [CHAIN.BSC]: "0x5F86475d57e9B488500d3CdA6F6Cb3938B192077", [CHAIN.BASE]: "0x5F86475d57e9B488500d3CdA6F6Cb3938B192077", }; const SWAP_FEE_LABEL = "Swap Fees"; const fetch = async ({ getLogs, createBalances, chain }: FetchOptions) => { const settlement = settlementContracts[chain]; const dailyVolume = createBalances(); const dailyFees = createBalances(); const logs = await getLogs({ target: settlement, eventAbi: quoteSettledEvent, }); logs.forEach((log: any) => { addOneToken({ chain, balances: dailyVolume, token0: log.outputToken, amount0: log.amountOut, token1: log.inputToken, amount1: log.grossAmountIn }); dailyVolume.add(log.outputToken, log.amountOut); dailyFees.add(log.feeTo, log.feeAmount, SWAP_FEE_LABEL); }); return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const methodology = { Volume: "Sum of output token amounts from QuoteSettled events emitted by the Deluthium settlement contract.", Fees: "Swap fees collected by the Deluthium settlement contract, taken from the feeAmount field of each QuoteSettled event.", Revenue: "All swap fees are retained by the protocol.", ProtocolRevenue: "All swap fees are retained by the protocol.", }; const breakdownMethodology = { Fees: { [SWAP_FEE_LABEL]: "Swap fees paid by the user", }, Revenue: { [SWAP_FEE_LABEL]: "Swap fees paid by the user", }, ProtocolRevenue: { [SWAP_FEE_LABEL]: "Swap fees paid by the user", }, }; const adapter: any = { version: 2, pullHourly: true, fetch, adapter: { [CHAIN.BSC]: { start: '2026-03-24' }, [CHAIN.BASE]: { start: '2026-03-24' }, }, methodology, breakdownMethodology, }; export default adapter; ================================================ FILE: aggregators/dexhunter/index.ts ================================================ import { postURL } from "../../utils/fetchURL" import { FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = 'https://api-us.dexhunterv3.app/stats/fear_and_greed'; interface IAPIResponse { is_dexhunter: boolean; usd_volume: number; } const fetchData = async (period: '24h' | 'all'): Promise => { const response = await postURL(`${URL}`, { period }); const data: IAPIResponse[] = response; const dexhunterData = data.find(d => d.is_dexhunter); if (!dexhunterData) { throw new Error('No dexhunter data found'); } return (dexhunterData.usd_volume / 1000000).toString() } const fetch = async (): Promise => { const dailyVolume = await fetchData('24h'); return { dailyVolume: dailyVolume, }; } const adapter: SimpleAdapter = { adapter: { [CHAIN.CARDANO]: { fetch, runAtCurrTime: true, start: '2023-05-15', }, }, }; export default adapter; ================================================ FILE: aggregators/dexr/index.ts ================================================ import { Adapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { METRIC } from "../../helpers/metrics"; // ───────────────────────────────────────────── // DEXR — DEX Aggregator // https://dexr.finance // // Multi-chain volume tracking via SwapExecuted events emitted by the // FeeAggregatorMaster contract. Each event represents a single swap // routed through one of the chain's adapters (Uniswap V3/V4, // Aerodrome / Velodrome family, Balancer V2/V3, PancakeSwap V3, // THENA, Kumbaya, Prism, etc.). // // The Master contract is the same code on every chain — only the // adapter set and deployed address differ. That uniformity is what // makes one adapter file cover all four chains: same event ABI, // same fee semantics (0.3% on tokenIn), same revenue path (100% to // the Gnosis Safe replicated across chains via CREATE2). // // Scope of this adapter: // ✓ DEXR Master swaps on Base, Optimism, MegaETH, BNB Chain // ✗ LI.FI bridge / cross-chain swap volume (NOT included here) // // Why LI.FI volume is excluded: DEXR is a *direct* LI.FI integrator // (registered at portal.li.fi as integrator "DEXR" with a 30 BPS fee) // for cross-chain bridges and same-chain fallback on unsupported // chains. Those swaps don't pass through the Master contract — they // go through LI.FI's Diamond contract on each chain, which doesn't // emit SwapExecuted. The fee paid via LI.FI accrues to the same Safe // but is withdrawn through portal.li.fi rather than collected // on-chain at swap time. Tracking that volume requires LI.FI's // Analytics API (separate adapter — likely belongs under // bridge-aggregators/, not aggregators/). // ───────────────────────────────────────────── // Master contract address per chain. Same Solidity (FeeAggregatorMaster.sol) // at each address — chain-specific adapter wiring lives off-chain in // the `registerAdapter` calls made at deploy time. // // Note: Optimism and BNB Chain share the same Master address // (0x7eEdb990…F9377) because the contract was deployed via CREATE2 // with the same salt + bytecode on both chains. They are independent // deployments — the address collision is by construction, not a typo. const MASTER_ADDRESS: Record = { [CHAIN.BASE]: "0x4859608579D0f01605F6824ea173072a7Cc206c5", [CHAIN.OPTIMISM]: "0x7eEdb990a85Fd147BDCdDA651F9419E2741F9377", [CHAIN.MEGAETH]: "0x094AAbf518B483713Fc920eCf8af0922F8E51EFD", [CHAIN.BSC]: "0x7eEdb990a85Fd147BDCdDA651F9419E2741F9377", }; const SWAP_EXECUTED_EVENT = "event SwapExecuted(address indexed user, uint8 indexed adapterId, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, uint256 feeAmount)"; async function fetch(options: FetchOptions) { // SEPARATE balance objects for volume / fees / revenue. // Do not share references — the framework may post-process each // independently, so a shared object would conflate the three. const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const dailyRevenue = options.createBalances(); const target = MASTER_ADDRESS[options.chain]; if (!target) { // Defensive guard — should never trip because `chains` below // is the source of truth, but keeps the function honest if // the framework ever passes a chain we haven't configured. return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue }; } const logs = await options.getLogs({ target, eventAbi: SWAP_EXECUTED_EVENT, }); for (const log of logs) { // Volume: sum the *output* token value (industry standard for // aggregators). tokenOut is what the user actually receives, // after slippage and pool fees. dailyVolume.add(log.tokenOut, log.amountOut); // Fees: 0.3% protocol fee taken from tokenIn before forwarding // to the adapter. Matches feeBps=30 set in the Master constructor. dailyFees.add(log.tokenIn, log.feeAmount, METRIC.SWAP_FEES); // Revenue: 100% of fees flow to the multisig (no token holders, // no buyback). The multisig is the same Safe address replicated // to each chain via CREATE2 (0xD55cE54Ce3e0985867CD57f4266c27a5b060D665). dailyRevenue.add(log.tokenIn, log.feeAmount, METRIC.SWAP_FEES); } return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, }; } const methodology = { Volume: "Volume is the sum of tokenOut amounts from SwapExecuted events emitted by the DEXR FeeAggregatorMaster contract on each supported chain (Base, Optimism, MegaETH, BNB Chain). tokenOut represents the asset received by the user after the swap completes. Note: this counts only swaps that route through the on-chain Master contract; cross-chain bridges and same-chain swaps that fall back to LI.FI's router are not included here (DEXR is a direct LI.FI integrator but those flows accrue separately).", Fees: "DEXR charges a flat 0.3% protocol fee on the input token (tokenIn) of every swap. The feeAmount field of the SwapExecuted event captures this exactly. The same 0.3% rate applies to LI.FI-routed flows but those fees are collected via the LI.FI integrator portal, not on-chain — and are not counted here.", Revenue: "100% of the 0.3% protocol fee flows to a Gnosis Safe multisig (no token holders, no buyback). The same Safe address (0xD55cE54Ce3e0985867CD57f4266c27a5b060D665) is replicated across all chains. Revenue equals fees.", }; const breakdownMethodology = { Fees: { [METRIC.SWAP_FEES]: "0.3% swap fee charged on input token before swap", }, Revenue: { [METRIC.SWAP_FEES]: "0.3% swap fee charged on input token before swap", }, ProtocolRevenue: { [METRIC.SWAP_FEES]: "0.3% swap fee charged on input token before swap", }, }; const adapter: Adapter = { version: 2, pullHourly: true, // Per-chain start dates. Base was deployed first; Optimism, MegaETH, // and BNB Chain followed once the adapter pattern proved stable. // Using per-chain `start` keys (not a top-level `start`) so DefiLlama // doesn't try to query historical events from before deployment // on chains that came online later. adapter: { [CHAIN.BASE]: { fetch, start: "2026-05-04" }, [CHAIN.OPTIMISM]: { fetch, start: "2026-05-09" }, [CHAIN.MEGAETH]: { fetch, start: "2026-05-10" }, [CHAIN.BSC]: { fetch, start: "2026-05-13" }, }, methodology, breakdownMethodology, }; export default adapter; ================================================ FILE: aggregators/dflow/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { Dependencies, FetchOptions, SimpleAdapter, } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const data = await queryDuneSql( options, ` WITH base_data AS ( SELECT evt_block_time, input_mint, input_amount, output_mint, output_amount FROM dflow_solana.swap_orchestrator_evt_swapevent WHERE evt_block_time >= from_unixtime(${options.startTimestamp}) AND evt_block_time < from_unixtime(${options.endTimestamp}) ), prices AS ( SELECT timestamp AS minute, contract_address_varchar AS mint_address, price, decimals FROM prices.minute WHERE timestamp >= from_unixtime(${options.startTimestamp}) AND timestamp < from_unixtime(${options.endTimestamp}) AND blockchain = 'solana' ), volumes AS ( SELECT GREATEST( COALESCE(bd.input_amount / POW(10, p_in.decimals) * p_in.price, 0), COALESCE(bd.output_amount / POW(10, p_out.decimals) * p_out.price, 0) ) AS volume_usd FROM base_data bd LEFT JOIN prices p_in ON DATE_TRUNC('minute', bd.evt_block_time) = p_in.minute AND bd.input_mint = p_in.mint_address LEFT JOIN prices p_out ON DATE_TRUNC('minute', bd.evt_block_time) = p_out.minute AND bd.output_mint = p_out.mint_address ) SELECT SUM(volume_usd) AS volume FROM volumes WHERE volume_usd > 0 `, ); return { dailyVolume: data[0].volume, }; }; const adapter: SimpleAdapter = { version: 1, fetch, start: "2025-04-01", chains: [CHAIN.SOLANA], dependencies: [Dependencies.DUNE], methodology: { Volume: "Volume is calculated by summing the USD value of all trades routed through DFlow aggregator.", }, isExpensiveAdapter: true, }; export default adapter; ================================================ FILE: aggregators/dirol/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const CORE_AGGREGATORS = [ "0x77E73c3fCd3FEDba383025CDe4a5b97733A34c2E", // v1 (deprecated 2025-12-05 ~ 2026-02-27) "0x646462f4d0168A94fE1884c8ae82148a3618A18d", // v2 UUPS proxy (current) ]; const SWAP_EVENT = "event Swap(address indexed sender, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut)"; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const logs = await options.getLogs({ targets: CORE_AGGREGATORS, eventAbi: SWAP_EVENT, }); logs.forEach((log) => { dailyVolume.add(log.tokenIn, log.amountIn); }); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, methodology: { Volume: "Sum of amountIn from Swap events emitted by CORE_AGGREGATOR (tokenIn side).", }, adapter: { [CHAIN.MONAD]: { fetch, start: "2025-12-05", }, }, }; export default adapter; ================================================ FILE: aggregators/dodo-agg/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getDefaultDexTokensBlacklisted } from "../../helpers/lists"; import { formatAddress } from "../../utils/utils"; // https://api.dodoex.io/dodo-contract/list const config: any = { [CHAIN.ETHEREUM]: { DODOFeeRouteProxys: [ "0x21b9F852534Fb9DdC3A0A7B24f067B50d8AC9a99", "0x50f9bDe1c76bba997a5d6e7FEFff695ec8536194", "0xFe837A3530dD566401d35beFCd55582AF7c4dfFC", "0x5977F12664b4E634dFbAAD0ad4a6a81057254dA8", ], }, [CHAIN.OPTIMISM]: { DODOFeeRouteProxys: [ "0x716fcc67dcA500A91B4a28c9255262c398D8f971", "0xc7d7CC1e9f5E823887980c9C51F9c418ee3A3e28", "0x3a64Ec3606FF7310E8fAd6FcC008e39705fB496d", "0x8b09DB11ea380d6454D2592D334FFC319ce6EF3E", ], }, [CHAIN.BSC]: { DODOFeeRouteProxys: [ "0xa8b034301Bb5DD3610db585Def3e7C0d52f2319F", "0x0656fD85364d03b103CEEda192FB2D3906A6ac15", "0xb95ed7e958e196688984951f41ac2888f4b10ab9", "0x0343C5757Fb98aD9eF39824e08B852aF61C71c64", "0x701Ac6fAD7850956f966a85655348ac1B7c93368", ], }, [CHAIN.POLYGON]: { DODOFeeRouteProxys: [ "0x39E3e49C99834C9573c9FC7Ff5A4B226cD7B0E63", "0xA103206E7f19d1C1c0e31eFC4DFc7b299630F100", "0x46AFE01D758a46d64c7d8E0791314D5db3E2e683", "0x3a64Ec3606FF7310E8fAd6FcC008e39705fB496d", ], }, [CHAIN.BOBA]: { DODOFeeRouteProxys: [ "0x64842A3EbC09bB69429c1a34ae181375fea5f17F", "0xfcA520C94078b65F8237d4F566c438a9468917A1", ], }, [CHAIN.CONFLUX]: { DODOFeeRouteProxys: [ "0x3037e79FCe8817A6F21196d8D93C80F53ABB9267", "0x5a71a8524477Acd1807CFefD114Bf8904CD8dF96", ], }, [CHAIN.MOONRIVER]: { DODOFeeRouteProxys: [ "0x003B18357460e789e711849749A793c430d14f97", "0x2144BF2003bFd9Aa0950716333fBb5B7A1Caeda4", ], }, [CHAIN.MANTLE]: { DODOFeeRouteProxys: [ "0xB4E598688eC724DD00a8944E7c7b259BbB992c61", "0x70B9C57E1fF24761C1C3ced57Ddae9A3F3570698", ], }, [CHAIN.BASE]: { DODOFeeRouteProxys: [ "0x987bFBE33c9cF18cAA665B792Db66339a9c16D32", "0xA376762070F7fCE8f3646AAe90e6e375e6daF128", "0x8b09DB11ea380d6454D2592D334FFC319ce6EF3E", "0x3A7Bc5F9E41356728f037f17D88c642EE46d1Aaa", ], }, [CHAIN.AVAX]: { DODOFeeRouteProxys: [ "0xbce44767af0a53A108b3B7ba4F740E03D228Ec0A", "0x1F076a800005c758a505E759720eb6737136e893", "0x3a64Ec3606FF7310E8fAd6FcC008e39705fB496d", "0x8b09DB11ea380d6454D2592D334FFC319ce6EF3E", ], }, [CHAIN.ARBITRUM]: { DODOFeeRouteProxys: [ "0xe05dd51e4eB5636f4f0E8e7Fbe82eA31a2ecef16", "0xc4A1a152812dE96b2B1861E433f42290CDD7f113", "0x69716E51E3F8Bec9c3D4E1bB46396384AE11C594", "0x056FcE6B76AF3050F54B71Fc9B5fcb7C387BfC1A", ], }, [CHAIN.LINEA]: { DODOFeeRouteProxys: [ "0x70B9C57E1fF24761C1C3ced57Ddae9A3F3570698", "0x03e89fC55A5ad0531576E5a502c4CA52c8bf391B", ], }, [CHAIN.SCROLL]: { DODOFeeRouteProxys: [ "0xf0512872fEc0173d1d99c2dd8CDCb770054b675b", "0x4e998615aD430C1cA46A69d813edE6EB3EC55eDb", ], }, [CHAIN.MANTA]: { DODOFeeRouteProxys: [ "0x2933c0374089D7D98BA0C71c5E02E1A0e09deBEE", "0x200D866Edf41070DE251Ef92715a6Ea825A5Eb80", ], }, [CHAIN.ZERO]: { DODOFeeRouteProxys: [ "0x2aea827424f99a187A2bF056F0782E927AB2066a", "0x0e038eaEf8383dfcE2B80b6E4E3F25Fd963527C4", ], }, [CHAIN.ZIRCUIT]: { DODOFeeRouteProxys: [ "0x518Bfe0c91C1C8e9588b9218B87C38Fa6b9735D6", "0x3b0c6c0CE667844e742Ce0Ca533EaA2b6f422AA8", ], }, }; const abis = { OrderHistory: "event OrderHistory (address fromToken, address toToken, address sender, uint256 fromAmount, uint256 returnAmount)", }; const fetch = async ( { createBalances, getLogs, chain }: FetchOptions ) => { const dailyVolume = createBalances(); const blacklistTokens = getDefaultDexTokensBlacklisted(chain) const logs = (await getLogs({ targets: config[chain].DODOFeeRouteProxys, eventAbi: abis.OrderHistory, })) .filter(log => !blacklistTokens.includes(formatAddress(log.fromToken)) && !blacklistTokens.includes(formatAddress(log.toToken))) logs.forEach((log: any) => { dailyVolume.add(log.fromToken, log.fromAmount); }); return { dailyVolume }; }; const adapter_agg = { adapter: {}, }; Object.keys(config).forEach( (chain) => ((adapter_agg.adapter as any)[chain] = { fetch, start: "2024-08-01" }) ); const adapter: SimpleAdapter = { version: 2, adapter: adapter_agg.adapter, }; export default adapter; ================================================ FILE: aggregators/durianfun/index.ts ================================================ /** * Durianfun Aggregator — DEX-aggregator volume adapter. * ── Protocol ─────────────────────────────────────────────────────── * * `DurianAggregatorRouter` is a Jupiter-style atomic multi-DEX router * on Bitkub Chain. There are TWO deployed generations: * * V1 (canonical pre-V466 router, LIVE for pure-V4.5/Udonswap routes): * - Address: 0x5078cE74728bC3F1313B55A04B79E227E1181918 * - Predecessors (paused, kept for historical-continuity sum): * V3.1: 0xB85E049484f5c44A8D1407fF372081Fe3e2455BC * V4 unpatched: 0x6334f9dbC8AE789DD642a915Ce884B65A887a4aC * - Swapped event (7 fields, NO referrer): * Swapped(user, tokenIn, tokenOut, amountIn, amountOutToUser, * fee, hops) * * V2 (V4.6.6-aware aggregator, LIVE — deployed 2026-05-09): * - Address: 0xf3d6896A5dCB6896d6F2DB55D6Eb0b41496f0215 * - Swapped event (8 fields, ADDS `referrer`): * Swapped(user, tokenIn, tokenOut, amountIn, amountOutToUser, * fee, hops, referrer) * * The two ABIs share keccak-prefix `Swapped(address,...)` but the * topic-0 hashes differ because the trailing `referrer` field changes * the canonical signature string. We register BOTH ABIs against BOTH * router-address sets so DefiLlama's volume series is continuous * across the V1→V2 cutover. * */ import { Adapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from "../../helpers/prices"; import { METRIC } from "../../helpers/metrics" // V1 routers (7-arg Swapped). Include all predecessors so the // historical volume series is continuous before V2 cutover. const ROUTERS_V1: string[] = [ "0x5078cE74728bC3F1313B55A04B79E227E1181918", // V4-patched (current V1 LIVE) "0x6334f9dbC8AE789DD642a915Ce884B65A887a4aC", // V4 unpatched (paused) "0xB85E049484f5c44A8D1407fF372081Fe3e2455BC", // V3.1 (paused) ]; // V2 routers (8-arg Swapped with trailing `referrer`). const ROUTERS_V2: string[] = [ "0xf3d6896A5dCB6896d6F2DB55D6Eb0b41496f0215", // V2 LIVE (2026-05-09) ]; const SWAPPED_ABI_V1 = "event Swapped(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOutToUser, uint256 fee, uint8 hops)"; const SWAPPED_ABI_V2 = "event Swapped(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOutToUser, uint256 fee, uint8 hops, address referrer)"; const fetch = async ({ createBalances, getLogs, chain }: FetchOptions) => { const dailyVolume = createBalances(); const dailyFees = createBalances(); // Process V1 routers (predecessors + current V1). const v1Logs = await getLogs({ targets: ROUTERS_V1, eventAbi: SWAPPED_ABI_V1 }) for (const log of v1Logs) { addOneToken({ chain, balances: dailyVolume, token0: log.tokenIn, amount0: log.amountIn, token1: log.tokenOut, amount1: log.amountOutToUser }) dailyFees.add(log.tokenOut, log.fee, METRIC.SWAP_FEES) } // Process V2 routers (different event ABI / topic-0 hash). const v2Logs = await getLogs({ targets: ROUTERS_V2, eventAbi: SWAPPED_ABI_V2, }); for (const log of v2Logs) { addOneToken({ chain, balances: dailyVolume, token0: log.tokenIn, amount0: log.amountIn, token1: log.tokenOut, amount1: log.amountOutToUser }) dailyFees.add(log.tokenOut, log.fee, METRIC.SWAP_FEES) } return { dailyVolume, dailyFees, dailyRevenue: dailyFees }; }; const methodology = { Volume: "Sum of swap volume routed through Durian Aggregator Router V1 and V2.", Fees: "Router-skim fee deducted from the output token of every Swapped event, capped at 1.0% per route.", Revenue: "100% of the swap fees accrue to the protocol.", }; const breakdownMethodology = { Fees: { [METRIC.SWAP_FEES]: "Router-skim fee deducted from the output token of each swap, capped at 1.0% per route.", }, Revenue: { [METRIC.SWAP_FEES]: "Router-skim fee deducted from the output token of each swap, capped at 1.0% per route.", }, }; const adapter: Adapter = { version: 2, pullHourly: true, adapter: { [CHAIN.BITKUB]: { fetch, start: "2026-04-26", }, }, methodology, breakdownMethodology, }; export default adapter; ================================================ FILE: aggregators/dzap/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { DZAP_SUPPORTED_CHAINS, fetchChainWiseVolumeFromDZapAPI } from "../../helpers/aggregators/dzap"; import { CHAIN } from "../../helpers/chains"; const prefetch = async (options: FetchOptions) => fetchChainWiseVolumeFromDZapAPI({ ...options, txType: "swap" }); const fetch = async (_a: any, _b: any, options: FetchOptions) => { // bad data, wash trade if (options.startOfDay === 1750982400 && options.chain === CHAIN.ARBITRUM) { return { dailyVolume: 0, }; } const volume = options.preFetchedResults[options.chain] ?? 0; return { dailyVolume: volume, }; }; const adapter: SimpleAdapter = { version: 1, fetch, chains: Object.values(DZAP_SUPPORTED_CHAINS), start: "2023-01-01", prefetch, }; export default adapter; ================================================ FILE: aggregators/eisen/index.ts ================================================ import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import ADDRESSES from "../../helpers/coreAssets.json"; const event_swap = "event EisenSwapCompleted(address indexed sender, address indexed fromAssetId, address indexed toAssetId, address receiver, uint256 fromAmount, uint256 toAmount, uint256 expectedToAmount, uint256 fee)"; const chainConfig: Record = { [CHAIN.BASE]: { start: "2024-11-23", fee: '0x14C3B68e5855B60263b10eC0fCE54DE3e28AD880' }, [CHAIN.BERACHAIN]: { start: "2025-02-06", fee: '0xE53744A85a12FCC38005d180c18f04F8EF0FB719' }, [CHAIN.BLAST]: { start: "2024-05-10", fee: '0xd57Ed7F46D64Ec7b6f04E4A8409D88C55Ef8AA3b' }, [CHAIN.CORE]: { start: "2024-10-01", fee: '0x6bD912872B9e704a70f10226ab01A2Db87D0dd1C' }, [CHAIN.MODE]: { start: "2024-03-17", fee: '0x37Cb37b752DBDcd08A872e7dfec256A216C7144C' }, [CHAIN.LINEA]: { start: "2024-06-18", fee: '0x206168f099013b9eAb979d3520cA00aAD453De55' }, [CHAIN.MANTLE]: { start: "2024-05-24", fee: '0x31d6F212142D3B222EF11c9eBB6AF3569b8442EE' }, [CHAIN.SCROLL]: { start: "2023-10-16", fee: '0xA06568773A247657E7b89BBA465014CF85702093' }, [CHAIN.TAIKO]: { start: "2024-10-01", fee: '0xFA0e9251503DaE51670d10288e6962d63191731d' }, [CHAIN.ZIRCUIT]: { start: "2024-12-06", fee: '0x6bD912872B9e704a70f10226ab01A2Db87D0dd1C' }, [CHAIN.SONEIUM]: { start: "2024-12-15", fee: '0x7E36665858D17FD1CbFd4Fd464d2a3Da49aa3B9d' }, [CHAIN.HEMI]: { start: "2025-03-07", fee: '0x3E257bD80C5e73f9A5D30D3D1a734251c4809Ad4' }, [CHAIN.ROOTSTOCK]: { start: "2025-03-13", fee: '0x7D1820c87BD5e4C231310D45E5f24eb571813738' }, [CHAIN.BSC]: { start: "2025-04-03", fee: '0xf1afD3bbEeFE61042b2B29F42d65F71ac5bC881e' }, [CHAIN.ARBITRUM]: { start: "2025-04-08", fee: '0xf1afD3bbEeFE61042b2B29F42d65F71ac5bC881e' }, [CHAIN.HYPERLIQUID]: { start: "2025-05-18", fee: '0x1FA40f83c12E48e9396d12Dd08B4b4ee51C8c803' }, [CHAIN.ABSTRACT]: { start: "2025-05-22", fee: '0x82808C2F5777b816d55FCf54928567a50D18E31d' }, [CHAIN.PLUME]: { start: "2025-06-10", fee: '0x90BA9922Ae475D0DD91a6BF20dcD0FB872Bc18B0' }, [CHAIN.FLOW]: { start: "2025-08-03", fee: '0x90BA9922Ae475D0DD91a6BF20dcD0FB872Bc18B0' }, [CHAIN.KATANA]: { start: "2025-07-20", fee: '0x11145aA7EeF8A3c61fFEf3F74981755e3148D358' }, [CHAIN.BITLAYER]: { start: "2025-08-03", fee: '0x5722c0B501e7B9880F9bB13A14217851e45C454f' }, [CHAIN.CRONOS]: { start: "2025-08-03", fee: '0x0C15c845C4A970b284c0dd61Bcf01c4DC1117d0F' }, [CHAIN.MONAD]: { start: "2025-11-23", fee: '0x787C474B8A86354d0F5f19FB599a5FC7662A265f' }, [CHAIN.MEGAETH]: { start: "2026-01-19", fee: '0x91748773c5c52ba497ff4a1cf681aea9dbf4267f' }, } async function fetch(options: FetchOptions) { const feeCollectors = chainConfig[options.chain].fee; const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const logs = await options.getLogs({ targets: [feeCollectors], eventAbi: event_swap }); logs.forEach((i) => { if (i.toAssetId.toLowerCase() == ADDRESSES.GAS_TOKEN_2.toLowerCase()) { dailyVolume.addGasToken(i.toAmount); dailyFees.addGasToken(i.fee); } else { dailyVolume.add(i.toAssetId, i.toAmount); dailyFees.add(i.toAssetId, i.fee); } }); return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, dailyHoldersRevenue: '0' }; } const methodology = { Fees: "Token trading fees paid by users.", Revenue: "All fees are revenue.", ProtocolRevenue: "All fees are protocol revenue.", HoldersRevenue: "No Holders Revenue", } const adapter = { version: 2, pullHourly: true, methodology, fetch, adapter: chainConfig } export default adapter; ================================================ FILE: aggregators/enso/index.ts ================================================ import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; const chainConfig: Record = { [CHAIN.ETHEREUM]: { id: 1, start: "2023-06-22" }, [CHAIN.OPTIMISM]: { id: 10, start: "2023-09-19" }, [CHAIN.BSC]: { id: 56, start: "2023-09-20" }, [CHAIN.XDAI]: { id: 100, start: "2023-01-01" }, [CHAIN.UNICHAIN]: { id: 130, start: "2025-01-01" }, [CHAIN.POLYGON]: { id: 137, start: "2023-09-05" }, [CHAIN.MONAD]: { id: 143, start: "2025-11-01" }, [CHAIN.SONIC]: { id: 146, start: "2025-01-01" }, [CHAIN.ZKSYNC]: { id: 324, start: "2025-01-01" }, [CHAIN.WC]: { id: 480, start: "2026-03-31" }, [CHAIN.HYPERLIQUID]: { id: 999, start: "2025-01-01" }, [CHAIN.SONEIUM]: { id: 1868, start: "2026-03-31" }, [CHAIN.TEMPO]: { id: 4217, start: "2026-03-31" }, [CHAIN.BASE]: { id: 8453, start: "2023-12-24" }, [CHAIN.PLASMA]: { id: 9745, start: "2025-10-01" }, [CHAIN.ARBITRUM]: { id: 42161, start: "2023-09-11" }, [CHAIN.AVAX]: { id: 43114, start: "2023-01-01" }, [CHAIN.INK]: { id: 57073, start: "2026-03-31" }, [CHAIN.LINEA]: { id: 59144, start: "2023-12-14" }, [CHAIN.BERACHAIN]: { id: 80094, start: "2025-01-25" }, [CHAIN.PLUME]: { id: 98866, start: "2025-01-01" }, [CHAIN.KATANA]: { id: 747474, start: "2025-01-01" }, }; const prefetch = async (options: FetchOptions) => { const day = options.dateString; const url = `https://api.enso.finance/api/v1/reporting/volume/defillama?from=${day}&to=${day}`; return httpGet(url, { headers: { origin: "https://defillama.com", }, }); }; const fetch = async (_: any, _1: any, options: FetchOptions) => { const { chain } = options; const config = chainConfig[chain]; const data: any = options.preFetchedResults if (!data) throw new Error(`No data found for date ${options.dateString}`); const chainData = data.find((item) => item.chainId === config.id); return { dailyVolume: chainData?.publishedVolumeUsd ?? 0, //Empty volume chains are not included in the data }; }; const adapter: any = { version: 1, prefetch, fetch, adapter: chainConfig, }; export default adapter; ================================================ FILE: aggregators/erc-burner/index.ts ================================================ import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; // Contract addresses for each chain const BURNER_CONTRACTS = { [CHAIN.ETHEREUM]: "0x2a0AB930aB078dFEd9B5b56cd783C2C744D5d323", [CHAIN.ARBITRUM]: "0x2a0AB930aB078dFEd9B5b56cd783C2C744D5d323", [CHAIN.BASE]: "0x2a0AB930aB078dFEd9B5b56cd783C2C744D5d323", [CHAIN.BSC]: "0x25025051f8E8c2a5fAaDc25cdFD92f6d25CB0e46", [CHAIN.AVAX]: "0x2a0AB930aB078dFEd9B5b56cd783C2C744D5d323", [CHAIN.OPTIMISM]: "0x2a0AB930aB078dFEd9B5b56cd783C2C744D5d323", [CHAIN.BLAST]: "0x2a0AB930aB078dFEd9B5b56cd783C2C744D5d323", [CHAIN.POLYGON]: "0x89B6C6aed65568c3a0e5D35ADF5201Aff75117Ed", [CHAIN.ERA]: "0x4B4554bAe261f3A0660592a9E58E429Bd8b3D472", }; // ABI for the BurnSuccess event (common to all chains) const burnSuccessAbi = "event BurnSuccess(address indexed user, uint256 totalAmountOut, uint256 feeAmount)"; // Function to fetch volume and fees for a specific chain const fetch = async (options: any) => { const { createBalances, getLogs, chain } = options; const dailyVolume = createBalances() // Get logs for BurnSuccess events const logs = await getLogs({ target: BURNER_CONTRACTS[chain], eventAbi: burnSuccessAbi, }); // Process logs to calculate volume and fees logs.forEach((log: any) => { const totalAmountOut = log.totalAmountOut; // Add to volume (total amount + fee) dailyVolume.addGasToken(totalAmountOut); }); return { dailyVolume }; }; // Create adapter for each chain const adapter: SimpleAdapter = { methodology: { Volume: "Volume is calculated by tracking the total amount of native tokens (ETH, AVAX, etc.) processed through the Burner contracts' swapExactInputMultiple function" }, start: '2025-02-23', // Current date as specified fetch, version: 2, pullHourly: true, chains: Object.keys(BURNER_CONTRACTS), }; export default adapter; ================================================ FILE: aggregators/etaswap/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const fetch = async (timestamp: number) => { const res = await fetchURL(`https://api.etaswap.com/v1/statistics/volume/total?timestamp=${timestamp}`); return { dailyVolume: Number(res.volume_USD_24h) / 100, dailyFees: Number(res.fee_USD_24h) / 100 }; }; const adapter: any = { start: '2024-03-02', fetch, chains: [CHAIN.HEDERA], methodology: { Volume: 'Total token swap volume', Fees: 'Total swap fees paid by users', } }; export default adapter; ================================================ FILE: aggregators/fibrous-finance/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, FetchResult } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const chainConfig: Record = { [CHAIN.BASE]: { id: 8453, start: '2025-04-04' }, [CHAIN.HYPERLIQUID]: { id: 999, start: '2025-09-08' }, [CHAIN.STARKNET]: {id:23448594291968336, start: '2024-03-02'}, [CHAIN.CITREA]: {id:4114, start: '2026-01-27'}, [CHAIN.MONAD]: {id:143, start: '2025-11-26'} }; const URL = "https://graph.fibrous.finance/volume/daily"; interface IAPIResponse { status: number; data: { dailyVolume: string; }; message: string; } const fetch = async (_a: any, _b: any, options: FetchOptions): Promise => { const response: IAPIResponse = await fetchURL(URL + `?chainId=${chainConfig[options.chain].id}`); const dailyVolume = response.data.dailyVolume; return { dailyVolume: dailyVolume, }; }; const adapter = { adapter: chainConfig, fetch, runAtCurrTime: true, version: 1, }; export default adapter; ================================================ FILE: aggregators/flowx-aggregator/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; import { FetchOptions } from "../../adapters/types"; const fetchVolume = async ({ fromTimestamp, toTimestamp }: FetchOptions) => { const url = `https://flowx-finance-mono.vercel.app/api/defillama/aggregator-with-date?startTimestamp=${ fromTimestamp * 1000 }&endTimestamp=${toTimestamp * 1000}`; const res = await httpGet(url); return { dailyVolume: res.totalUSD, }; }; const adapter: any = { version: 2, adapter: { [CHAIN.SUI]: { fetch: fetchVolume, start: "2024-06-01", }, }, }; export default adapter; ================================================ FILE: aggregators/fluxa/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import fetchURL from "../../utils/fetchURL"; const BASE_URL = "https://api-fluxa.capylabs.io/api/v1"; const fetch = async (options: FetchOptions) => { const url = `${BASE_URL}/transactions/daily-total-volume?startTimestamp=${options.startTimestamp * 1000 }&endTimestamp=${options.endTimestamp * 1000}`; const res = await fetchURL(url); return { dailyVolume: res.totalDailyVolumeUsd, }; }; const adapter: SimpleAdapter = { version: 2, fetch, chains: [CHAIN.SEI], start: "2025-10-12", }; export default adapter; ================================================ FILE: aggregators/gluex-protocol/index.ts ================================================ import ADDRESSES from '../../helpers/coreAssets.json' import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; // Event ABIs const eventOld = `event Routed(bytes indexed uniquePID, address indexed userAddress, address outputReceiver, address inputToken, uint256 inputAmount, address outputToken, uint256 outputAmount, uint256 partnerFee, uint256 routingFee, uint256 finalOutputAmount)`; const eventNew = `event Routed(bytes32 indexed uniquePID, address indexed userAddress, address outputReceiver, address inputToken, uint256 inputAmount, address outputToken, uint256 finalOutputAmount, uint256 partnerFee, uint256 routingFee, uint256 partnerShare, uint256 protocolShare)`; // Native token identifiers (used with addGasToken) const gasTokens = new Set([ ADDRESSES.GAS_TOKEN_2, // 0xeeee...eeee ADDRESSES.null, // 0x0000...0000 '0x2222222222222222222222222222222222222222', // Hyperliquid ADDRESSES.polygon.WMATIC_1, // WMATIC on Polygon ]); // Router addresses const ROUTERS_OLD: Partial> = { [CHAIN.ETHEREUM]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.ARBITRUM]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.BASE]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.XDAI]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.BSC]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.POLYGON]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.AVAX]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.OPTIMISM]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.BLAST]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.LINEA]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.MANTLE]: "0x85fb41c470B8Dd2C9aD262F38e38E42a2f92C285", [CHAIN.SCROLL]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.TAIKO]: "0x75e74A67Bd4A76BcE60bb0546f092571c3133523", [CHAIN.BERACHAIN]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.SONIC]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.UNICHAIN]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7", [CHAIN.HYPERLIQUID]: "0x6Ec7612828B776cC746fe0Ee5381CC93878844f7" }; // Router addresses const ROUTERS_NEW: Partial> = { [CHAIN.ETHEREUM]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.ARBITRUM]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.BASE]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.XDAI]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.BSC]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.POLYGON]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.AVAX]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.OPTIMISM]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.BLAST]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.LINEA]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.MANTLE]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.SCROLL]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.TAIKO]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.BERACHAIN]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.SONIC]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.UNICHAIN]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.HYPERLIQUID]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd", [CHAIN.PLASMA]: "0xe95f6eaeae1e4d650576af600b33d9f7e5f9f7fd" }; async function fetch(options: FetchOptions) { const { getLogs, createBalances, chain } = options; const dailyVolume = createBalances(); const dailyFees = createBalances(); const dailyRevenue = createBalances(); const oldRouter = ROUTERS_OLD[chain]; const newRouter = ROUTERS_NEW[chain]; if (oldRouter) { const oldLogs = await getLogs({ targets: [oldRouter], eventAbi: eventOld }); for (const log of oldLogs) { const token = log.outputToken.toLowerCase(); const outputAmount = log.outputAmount; const fee = log.partnerFee + log.routingFee; const revenue = log.routingFee; const isNative = gasTokens.has(token); if (isNative) { dailyVolume.addGasToken(outputAmount); dailyFees.addGasToken(fee); dailyRevenue.addGasToken(revenue); } else { dailyVolume.add(token, outputAmount); dailyFees.add(token, fee); dailyRevenue.add(token, revenue); } } } if (newRouter) { const newLogs = await getLogs({ targets: [newRouter], eventAbi: eventNew }); for (const log of newLogs) { const token = log.outputToken.toLowerCase(); const outputAmount = log.finalOutputAmount; const fee = log.partnerFee + log.routingFee + log.partnerShare + log.protocolShare; const revenue = log.protocolShare; const isNative = gasTokens.has(token); if (isNative) { dailyVolume.addGasToken(outputAmount); dailyFees.addGasToken(fee); dailyRevenue.addGasToken(revenue); } else { dailyVolume.add(token, outputAmount); dailyFees.add(token, fee); dailyRevenue.add(token, revenue); } } } return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, }; } const methodology = { Fees: "Fees paid by users for swaps.", Revenue: "Revenue is calculated as the sum of routingFee for the old contract and the sum of protocolShare for the new contract.", ProtocolRevenue: "Protocol Revenue is calculated as the sum of routing fees and protocol share." } const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: {}, start: '2025-03-14', fetch, chains: Object.keys({ ...ROUTERS_OLD, ...ROUTERS_NEW }), methodology, }; export default adapter; ================================================ FILE: aggregators/grelfswap/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchUrl from "../../utils/fetchURL"; const fetch = async (_t: any, _b: any, options: FetchOptions) => { const response = await fetchUrl(`https://grelfswap.com/api/defillama/volume?startTimestamp=${options.startTimestamp}`); if (!response || response.dailyVolumeUsd === undefined) { throw new Error('No data found'); } return { dailyVolume: response.dailyVolumeUsd, }; }; const adapter: SimpleAdapter = { version: 1, chains: [CHAIN.HEDERA], fetch, start: '2025-11-07', }; export default adapter; ================================================ FILE: aggregators/groypfi/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; import { sleep } from "../../utils/utils"; /** * GroypFi — DEX Aggregator on TON * * GroypFi aggregates liquidity across DeDust, STON.fi, Tonco, and Bidask * for optimal swap routing on the TON blockchain. * * Volume sources: * - Swap Widget (web app) * - Terminal Quick Buy (web app) * - Launchpad token trading (web app) * - @groypfi_bot (Telegram trading bot) * * All swaps carry a 1% platform fee sent to the house fee wallet. * Daily volume is reverse-calculated: volume = fee_inflow / 0.01 * * Fee wallet (user-friendly): UQDu4AiT__JKuqT0Znje0RoXIQMPcj4uIGYZme3UK4hFlE_Q * Fee wallet (raw): 0:eee00893fff24abaa4f46678ded11a1721030f723e2e20661999edd42b884594 * * Website: https://groypfi.io */ const FEE_RECIPIENT = "0:eee00893fff24abaa4f46678ded11a1721030f723e2e20661999edd42b884594"; const toBigInt = (v: any) => { if (v === null || v === undefined) return 0n; if (typeof v === "string") return BigInt(v); if (typeof v === "number") return BigInt(Math.trunc(v)); return 0n; }; const fetch = async (options: FetchOptions) => { const dailyFees = options.createBalances(); const start = options.startTimestamp; const end = options.endTimestamp; let total = 0n; let before_lt: string | undefined; let before_hash: string | undefined; const seen = new Set(); while (true) { const url = `https://tonapi.io/v2/blockchain/accounts/${FEE_RECIPIENT}/transactions?limit=1000&sort_order=desc${before_lt && before_hash ? `&before_lt=${before_lt}&before_hash=${before_hash}` : ""}`; let data: any; try { data = await fetchURL(url); } catch (e) { throw new Error(`Failed to fetch transactions: ${e}`); } const txs = data.transactions; if (!txs.length) break; let reachedBeforeStart = false; for (const tx of txs) { const key = tx.hash ?? `${tx.lt}:${tx.utime}`; if (seen.has(key)) continue; seen.add(key); if (tx.utime < start) { reachedBeforeStart = true; break; } if (tx.utime >= end) continue; // exclusive upper bound if (!tx.success) continue; if (tx.in_msg.destination.address === FEE_RECIPIENT) { total += toBigInt(tx.in_msg.value); } } if (reachedBeforeStart) break; const lastTx = txs[txs.length - 1]; if (lastTx?.lt == null || lastTx?.hash == null) break; before_lt = String(lastTx.lt); before_hash = String(lastTx.hash); await sleep(120); } dailyFees.addGasToken(total.toString()); const dailyVolume = dailyFees.clone(100); return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const methodology = { Volume: "DEX aggregation volume reverse-calculated from the 1% platform fee collected at the house fee wallet."+ "Sources: Swap Widget (web app), Terminal Quick Buy (web app), Launchpad token trading (web app), @groypfi_bot (Telegram trading bot)", Fees: "All the inflows to protcol wallet is considered as fees", Revenue: "All the inflows to protcol wallet is considered as revenue", ProtocolRevenue: "All the inflows to protcol wallet is considered as protocol revenue", }; const adapter: SimpleAdapter = { version: 2, fetch, chains: [CHAIN.TON], start: "2025-01-04", methodology, //pullHourly: true }; export default adapter; ================================================ FILE: aggregators/haiku/index.ts ================================================ import { HaikuChainConfig, mappingChainToDuneChain, } from "../../helpers/aggregators/haiku"; import { Dependencies, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; import { getDefaultDexTokensBlacklisted } from "../../helpers/lists"; import { formatAddress } from "../../utils/utils"; interface IResponse { chain: string; token: string; amount: string; } // Prefetch function that will run once before any fetch calls const prefetch = async (options: FetchOptions): Promise => { let results: Array = []; // split query const chainGroups: Array> = [ Object.keys(HaikuChainConfig).slice(0 ,4), Object.keys(HaikuChainConfig).slice(4 ,8), Object.keys(HaikuChainConfig).slice(8 ,12), Object.keys(HaikuChainConfig).slice(12, -1) ]; for (const chains of chainGroups) { const unionQueries = chains .map((chain) => { const blockchainName = mappingChainToDuneChain(chain); return ` SELECT '${chain.toLowerCase()}' as chain, tokenstf.contract_address as token, SUM(tokenstf.amount_raw) as amount FROM ${blockchainName}.logs log INNER JOIN ${blockchainName}.transactions tx ON log.tx_hash = tx.hash AND tx.block_date >= from_unixtime(${options.startTimestamp}) AND tx.block_date < from_unixtime(${options.endTimestamp}) INNER JOIN tokens.transfers tokenstf ON tokenstf.tx_hash = log.tx_hash AND tokenstf.blockchain = '${blockchainName}' AND tokenstf.block_date >= from_unixtime(${options.startTimestamp}) AND tokenstf.block_date < from_unixtime(${options.endTimestamp}) AND ( tx."from" = tokenstf."from" OR tx."from" = tokenstf."to" ) WHERE log.contract_address = ${HaikuChainConfig[chain].id.toLowerCase()} AND log.topic0 = 0x8b3a3eb535e3217f5718db4d1c134d3447f392bcb89955537208f4677860e213 AND log.block_date >= from_unixtime(${options.startTimestamp}) AND log.block_date < from_unixtime(${options.endTimestamp}) GROUP BY tokenstf.contract_address HAVING SUM(tokenstf.amount_raw) IS NOT NULL `; }) .join(" UNION ALL "); results = results.concat(await queryDuneSql(options, unionQueries)); } return results; }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const dailyVolume = options.createBalances() const results: IResponse[] = options.preFetchedResults || []; const chainData = results.filter( (item) => item.chain === options.chain.toLowerCase() ); const blacklistTokens = getDefaultDexTokensBlacklisted(options.chain); chainData.forEach(row => { if (row.token && row.amount && !blacklistTokens.includes(formatAddress(row.token))) { dailyVolume.add(row.token, row.amount); } }); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 1, fetch, prefetch: prefetch, chains: Object.keys(HaikuChainConfig), isExpensiveAdapter: true, dependencies: [Dependencies.DUNE], }; export default adapter; ================================================ FILE: aggregators/hallswap/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { BaseAdapter, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; // Main API url to hit const API_URL = "https://api.seer.coinhall.org/api/hallswap/metrics"; // Map of the chain names used by defillama to the chain names used by hallswap const CHAINS: Record = { [CHAIN.ARCHWAY]: "archway", [CHAIN.CHIHUAHUA]: "chihuahua", [CHAIN.DYMENSION]: "dymension", [CHAIN.INJECTIVE]: "injective", [CHAIN.JUNO]: "juno", [CHAIN.KUJIRA]: "kujira", [CHAIN.MIGALOO]: "migaloo", [CHAIN.NEUTRON]: "neutron", [CHAIN.ORAI]: "oraichain", [CHAIN.OSMOSIS]: "osmosis", [CHAIN.SEI]: "sei", [CHAIN.SOLANA]: "solana", // terra: "terraclassic", [CHAIN.TERRA2]: "terra", }; // Number of milliseconds in a day (24 hours) const DAY_IN_MILLIS = 86_400_000; const fetch = async (options: FetchOptions) => { const chain = (CHAINS as any)[options.chain]; const timestampMillis = options.toTimestamp * 1_000; const dayBeforeMillis = timestampMillis - DAY_IN_MILLIS; const dailyVolume = await fetchURL( `${API_URL}?chains=${chain}&from=${dayBeforeMillis}&to=${timestampMillis}` ); return { dailyVolume: dailyVolume[chain], }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: Object.entries(CHAINS).reduce( (acc, [defillamaChain, _]) => { acc[defillamaChain] = { fetch, start: '2021-12-01', // The first launch of Hallswap (1st December 2021) }; return acc; }, {} as BaseAdapter), }; export default adapter; ================================================ FILE: aggregators/hinkal/index.ts ================================================ import { Adapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const fetchEthereum = async (options: FetchOptions) => { const timestampStart = options.startTimestamp; const timestampEnd = options.endTimestamp; const urlVolume = `https://ethMainnet.server.hinkal.pro/totalVolume/${timestampStart}/${timestampEnd}/1`; const responseVolume = await fetchURL(urlVolume); const dataTotal = responseVolume; const dailyVolume = dataTotal.internal_volume + dataTotal.external_volume; return { dailyVolume: dailyVolume || 0, }; }; const fetchBase = async (options: FetchOptions) => { const timestampStart = options.startTimestamp; const timestampEnd = options.endTimestamp; const urlVolume = `https://base.server.hinkal.pro/totalVolume/${timestampStart}/${timestampEnd}/8453`; const responseVolume = await fetchURL(urlVolume); const dataTotal = responseVolume; const dailyVolume = dataTotal.internal_volume + dataTotal.external_volume; return { dailyVolume: dailyVolume || 0, }; }; const fetchArbitrum = async (options: FetchOptions) => { const timestampStart = options.startTimestamp; const timestampEnd = options.endTimestamp; const urlVolume = `https://arbMainnet.server.hinkal.pro/totalVolume/${timestampStart}/${timestampEnd}/42161`; const responseVolume = await fetchURL(urlVolume); const dataTotal = responseVolume; const dailyVolume = dataTotal.internal_volume + dataTotal.external_volume; return { dailyVolume: dailyVolume || 0, }; }; const fetchPolygon = async (options: FetchOptions) => { const timestampStart = options.startTimestamp; const timestampEnd = options.endTimestamp; const urlVolume = `https://polygon.server.hinkal.pro/totalVolume/${timestampStart}/${timestampEnd}/137`; const responseVolume = await fetchURL(urlVolume); const dataTotal = responseVolume; const dailyVolume = dataTotal.internal_volume + dataTotal.external_volume; return { dailyVolume: dailyVolume || 0, }; }; const fetchBNB = async (options: FetchOptions) => { const timestampStart = options.startTimestamp; const timestampEnd = options.endTimestamp; const urlVolume = `https://bnbMainnet.server.hinkal.pro/totalVolume/${timestampStart}/${timestampEnd}/56`; const responseVolume = await fetchURL(urlVolume); const dataTotal = responseVolume; const dailyVolume = dataTotal.internal_volume + dataTotal.external_volume; return { dailyVolume: dailyVolume || 0, }; }; const fetchAVALANCHE = async (options: FetchOptions) => { const timestampStart = options.startTimestamp; const timestampEnd = options.endTimestamp; const urlVolume = `https://avalanche.server.hinkal.pro/totalVolume/${timestampStart}/${timestampEnd}/43114`; const responseVolume = await fetchURL(urlVolume); const dataTotal = responseVolume; const dailyVolume = dataTotal.internal_volume + dataTotal.external_volume; return { dailyVolume: dailyVolume || 0, }; }; const fetchOPTIMISM = async (options: FetchOptions) => { const timestampStart = options.startTimestamp; const timestampEnd = options.endTimestamp; const urlVolume = `https://optimism.server.hinkal.pro/totalVolume/${timestampStart}/${timestampEnd}/10`; const responseVolume = await fetchURL(urlVolume); const dataTotal = responseVolume; const dailyVolume = dataTotal.internal_volume + dataTotal.external_volume; return { dailyVolume: dailyVolume || 0, }; }; const adapter: Adapter = { version: 2, adapter: { [CHAIN.ETHEREUM]: { fetch: fetchEthereum, start: '2023-11-09' }, [CHAIN.BASE]: { fetch: fetchBase, start: '2024-03-21' }, [CHAIN.ARBITRUM]: { fetch: fetchArbitrum, start: '2023-11-08' }, [CHAIN.POLYGON]: { fetch: fetchPolygon, start: '2023-11-07' }, [CHAIN.BSC]: { fetch: fetchBNB, start: '2023-11-08' }, [CHAIN.AVAX]: { fetch: fetchAVALANCHE, start: '2023-11-08' }, [CHAIN.OPTIMISM]: { fetch: fetchOPTIMISM, start: '2023-11-07' }, }, }; export default adapter; ================================================ FILE: aggregators/holdstation-agg/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from "../../helpers/prices"; const contractAddress = "0x43222f934ea5c593a060a6d46772fdbdc2e2cff0"; const contractAddress2 = "0x49D02f4F1515746978A821386E559ad57D5c69fd"; const contractAddress3 = "0xa08401e6b79676fab508ca21c0c552f550e1b4fc"; const event_fillQuoteEthToToken = "event FillQuoteEthToToken(address indexed buyToken,address indexed user,address target,uint256 amountSold,uint256 amountBought,uint256 feeAmount)"; const event_fillQuoteTokenToEth = "event FillQuoteTokenToEth(address indexed sellToken,address indexed user,address target,uint256 amountSold,uint256 amountBought,uint256 feeAmount)"; const event_fillQuoteTokenToToken = "event FillQuoteTokenToToken(address indexed sellToken,address indexed buyToken,address indexed user,address target,uint256 amountSold,uint256 amountBought,uint8 feeToken,uint256 feeAmount)"; const event_swap = "event Swapped(address indexed tokenIn,address indexed receiver,address tokenOut,uint256 amountIn,uint256 amountOut)"; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances() const dailyFees = options.createBalances() const [ log_fillQuoteEthToToken, log_fillQuoteTokenToEth, log_fillQuoteTokenToToken, log_swapped, log_swapped3 ] = await Promise.all([ options.getLogs({ target: contractAddress, eventAbi: event_fillQuoteEthToToken, }), options.getLogs({ target: contractAddress, eventAbi: event_fillQuoteTokenToEth, }), options.getLogs({ target: contractAddress, eventAbi: event_fillQuoteTokenToToken, }), options.getLogs({ target: contractAddress2, eventAbi: event_swap, }), options.getLogs({ target: contractAddress3, eventAbi: event_swap, }), ]); log_fillQuoteEthToToken.forEach((log) => { dailyVolume.addGasToken(log.amountSold) dailyVolume.addGasToken(log.feeAmount) }) log_fillQuoteTokenToEth.forEach((log) => { dailyVolume.addGasToken(log.amountBought) dailyVolume.addGasToken(log.feeAmount) }) log_fillQuoteTokenToToken.forEach((log) => { addOneToken({ chain: options.chain, balances: dailyVolume, token0: log.sellToken, amount0: log.amountSold, token1: log.buyToken, amount1: log.amountBought }) const feeToken = log.feeToken === 0n ? log.sellToken : log.buyToken dailyFees.addToken(feeToken, log.feeAmount) }) log_swapped.forEach((log) => { addOneToken({ chain: options.chain, balances: dailyVolume, token0: log.tokenIn, amount0: log.amountIn, token1: log.tokenOut, amount1: log.amountOut }) dailyFees.addToken(log.tokenIn, Number(log.amountIn) * 0.006) // fixed 0.6% }) log_swapped3.forEach((log) => { addOneToken({ chain: options.chain, balances: dailyVolume, token0: log.tokenIn, amount0: log.amountIn, token1: log.tokenOut, amount1: log.amountOut }) dailyFees.addToken(log.tokenIn, Number(log.amountIn) * 0.006) // fixed 0.6% }) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, start: "2025-04-16", methodology: { Volume: "Volume is calculated by summing the token volume of all trades settled on the protocol that day.", Fees: "Users pay fees (0.6%) per swap.", UserFees: "Users pay fees (0.6%) per swap.", }, chains: [CHAIN.WC], }; export default adapter; ================================================ FILE: aggregators/houdiniswap/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; const chainConfig: Record = { [CHAIN.ETHEREUM]: 'ethereum', [CHAIN.BITCOIN]: 'bitcoin', [CHAIN.BSC]: 'bsc', [CHAIN.ARBITRUM]: 'arbitrum', [CHAIN.AVAX]: 'avalanche', [CHAIN.CARDANO]: 'cardano', [CHAIN.CRONOS]: 'cronos', [CHAIN.POLYGON]: 'polygon', [CHAIN.SOLANA]: 'solana', [CHAIN.TRON]: 'tron', [CHAIN.FANTOM]: 'fantom', [CHAIN.LITECOIN]: 'litecoin', [CHAIN.BASE]: 'base', [CHAIN.OPTIMISM]: 'optimism', [CHAIN.CELO]: 'celo', [CHAIN.AURORA]: 'aurora', [CHAIN.MOONBEAM]:'moonbeam', [CHAIN.MOONRIVER]:'moonriver', [CHAIN.HEDERA]:'hedera', [CHAIN.ALGORAND]:'algorand', [CHAIN.TELOS]:'telos', [CHAIN.THORCHAIN]:'thorchain', [CHAIN.APTOS]:'aptos', [CHAIN.PHANTASMA]:'phantasma', [CHAIN.TON]:'ton', [CHAIN.SUI]:'sui', [CHAIN.ICP]:'icp', [CHAIN.LINEA]:'linea', [CHAIN.MANTLE]:'mantle', [CHAIN.NEAR]:'near', [CHAIN.SCROLL]:'scroll', [CHAIN.TAIKO]:'taiko', [CHAIN.ZKLINK]:'zklink', // [CHAIN.ERA]: "zksync-era", // [CHAIN.SEI]:'sei', // [CHAIN.MORPH]:'morph', // [CHAIN.BOUNCE_BIT]: "bounce-bit", // [CHAIN.GRAVITY]:'gravity', [CHAIN.SONIC]:'sonic', [CHAIN.HYPERLIQUID]:'hype', [CHAIN.BERACHAIN]:'bera', [CHAIN.IOTAEVM]:'iota', [CHAIN.HEMI]:'hemi', } const URL = "https://api.houdiniswap.com/api/aggregator-vol?"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const startTimestamp = options.startOfDay; const endTimestamp = startTimestamp + 86400; // 24 hours in seconds // Find the Houdini chain key for the given DefiLlama chain const houdiniChain = chainConfig[options.chain]; const url = `${URL}startTimestamp=${startTimestamp}&endTimestamp=${endTimestamp}&chain=${houdiniChain}`; const defaultRes = { dailyVolume: 0, } const res = await fetchURL(url); const targetDay = startTimestamp; const dailyData = res.find((item: any) => item.timestamp === targetDay); if (!dailyData) { return defaultRes } let dailyVolume = dailyData.totalUSD; if ((options.chain == CHAIN.ARBITRUM) && (dailyVolume > 1000000)) { dailyVolume = 0 } return { dailyVolume }; }; const adapter = { version: 1, start: '2021-01-01', // 2021-01-01 fetch, chains: Object.keys(chainConfig) }; export default adapter; ================================================ FILE: aggregators/hyperbloom/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const TransformedERC20Event = "event TransformedERC20(address indexed taker, address inputToken, address outputToken, uint256 inputTokenAmount, uint256 outputTokenAmount)"; const HYPERBLOOM_ADDRESSES = [ "0x4212a77e4533eca49643d7b731f5fb1b2782fe94", // new "0x74cddb25b3f230200b28d79ce85c43991648954a", // old ]; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const logs: any[] = await options.getLogs({ targets: HYPERBLOOM_ADDRESSES, eventAbi: TransformedERC20Event, flatten: true, }); for (const log of logs) { dailyVolume.add(log.inputToken, log.inputTokenAmount); dailyFees.add(log.inputToken, Number(log.inputTokenAmount) * 0.00025); // 0.025% } return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, start: "2025-05-31", methodology: { Volume: "Total trading volume aggregated via Hyperbloom routers.", Fees: "Flat 0.025% amount of trading fees on all trades.", Revenue: "Flat 0.025% amount of trading fees on all trades are revenue.", ProtocolRevenue: "Flat 0.025% amount of trading fees on all trades are revenue.", }, chains: [CHAIN.HYPERLIQUID], }; export default adapter; ================================================ FILE: aggregators/hyperflow/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; const STATS_API = "https://api.hyperflow.fun/v1/aggregator/stats/daily" const chainConfig: Record = { [CHAIN.HYPERLIQUID]: { id: 999, start: '2025-06-08' }, }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const url = `${STATS_API}?chainId=${chainConfig[options.chain].id}×tamps=${options.startOfDay}`; const dailyVolume = (await httpGet(url)).data?.volumes?.[0].value; return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 1, fetch, adapter: chainConfig }; export default adapter; ================================================ FILE: aggregators/injex/index.ts ================================================ import { CHAIN } from '../../helpers/chains'; import fetchURL from '../../utils/fetchURL'; const fetch = async (_a: any, _b: any, options: any) => { const res = await fetchURL(`https://inj-api-78847b1b16a1.herokuapp.com/api/volume-stats/usd?timestamp=${options.startOfDay}`); return { dailyVolume: res.dailyVolume, }; }; const adapter: any = { version: 1, adapter: { [CHAIN.INJECTIVE]: { fetch, start: '2024-05-22', }, }, }; export default adapter; ================================================ FILE: aggregators/inoswap/index.ts ================================================ import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addTokensReceived } from "../../helpers/token"; const ROUTERS = [ '0xf514ec27666f2e9669837f4f9eca6405ba38ac64', // current prod router '0x025f45a3ec6e90e8e1db1492554c9b10539ef2fc', // previous v2 router '0x95e8f3227ecc2f35213b6fd6fece6b8854a77db5', // legacy router ] const FEE_RECIPIENT = '0x53a7fcdbb5d9a8d6a9f2b83d6e70cd1efdaf76c6' const PROTOCOL_FEE_BPS = 10 // 0.10% const fetch = async (options: FetchOptions) => { const dailyFees = await addTokensReceived({ options, target: FEE_RECIPIENT, fromAdddesses: ROUTERS, }) const dailyVolume = dailyFees.clone(10000 / PROTOCOL_FEE_BPS) return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, dailyUserFees: dailyFees, dailySupplySideRevenue: 0, } } const methodology = { Fees: "Onchain Transfer accounting: sum ERC20 transfers sent from InoSwap routers to feeRecipient.", Revenue: "Mirrors fee stream collected in feeRecipient wallet.", ProtocolRevenue: "Mirrors fee stream collected in feeRecipient wallet.", SupplySideRevenue: "Set to 0 until explicit partner/supply-side distribution events are emitted.", UserFees: "Protocol fees paid by users, inferred from feeRecipient inflows.", Volume: "Inferred from feeRecipient inflows using fixed protocol fee 0.10% (volume = fees / 0.001).", } const adapter: any = { version: 2, pullHourly: true, fetch, chains: [CHAIN.CRONOS], start: "2026-02-01", methodology, } export default adapter; ================================================ FILE: aggregators/jeton/index.ts ================================================ import { Adapter, FetchResultVolume } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const url = "https://api.echooo.xyz/tenant/defillama/data/v2"; const chains = [ CHAIN.ETHEREUM, CHAIN.POLYGON, CHAIN.OPTIMISM, CHAIN.BSC, CHAIN.ARBITRUM, CHAIN.AVAX, CHAIN.SCROLL, CHAIN.ERA, CHAIN.BASE, ]; type Responce = { timestamp: number; protocol: { daily: { revenue: string; volume: string; }; total: { revenue: string; volume: string; }; }; chains: { [chain: string]: { daily: { revenue: string; volume: string; }; total: { revenue: string; volume: string; }; }; }; }; const fetch = (chain: string) => async (timestamp: number): Promise => { const resp: Responce = await fetchURL(`${url}?timestamp=${timestamp}`); const data = resp.chains[chain]; if (!data || !data.daily || !data.total) { return {} as FetchResultVolume; } return { dailyVolume: data.daily.volume, }; }; const adapter: Adapter = { adapter: { ...Object.entries(chains).reduce((acc, chain) => { const key = chain[1]; return { ...acc, [key]: { fetch: fetch(key), start: '2023-09-04', deadFrom: "2026-01-16", }, }; }, {}), }, }; export default adapter; ================================================ FILE: aggregators/joe-agg/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const contract = '0x45A62B090DF48243F12A21897e7ed91863E2c86b'; const event_swapIn = 'event SwapExactIn(address indexed sender,address to,address tokenIn,address tokenOut,uint256 amountIn,uint256 amountOut)'; const event_swapOut = 'event SwapExactOut(address indexed sender,address to,address tokenIn,address tokenOut,uint256 amountIn,uint256 amountOut)'; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const logs_swapIn = await options.getLogs({ target: contract, eventAbi: event_swapIn, }); const logs_swapOut = await options.getLogs({ target: contract, eventAbi: event_swapOut, }); logs_swapIn.forEach(log => { dailyVolume.add(log.tokenIn, log.amountIn); }); logs_swapOut.forEach(log => { dailyVolume.add(log.tokenOut, log.amountOut); }); return { dailyVolume, } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.AVAX]: { fetch, }, [CHAIN.ARBITRUM]: { fetch, }, } } export default adapter; ================================================ FILE: aggregators/jumper-exchange/index.ts ================================================ import { Chain } from "../../adapters/types"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getDefaultDexTokensBlacklisted } from "../../helpers/lists"; import { formatAddress } from "../../utils/utils"; type IContract = { [c: string | Chain]: string; } const contract: IContract = { [CHAIN.AURORA]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.ARBITRUM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.OPTIMISM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.BASE]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.ETHEREUM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.AVAX]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.BSC]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.LINEA]: '0xde1e598b81620773454588b85d6b5d4eec32573e', [CHAIN.MANTA]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.POLYGON]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.POLYGON_ZKEVM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.FANTOM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.MODE]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.SCROLL]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.ERA]: '0x341e94069f53234fe6dabef707ad424830525715', [CHAIN.METIS]: '0x24ca98fb6972f5ee05f0db00595c7f68d9fafd68', [CHAIN.XDAI]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.TAIKO]: '0x3a9a5dba8fe1c4da98187ce4755701bca182f63b', [CHAIN.BLAST]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.BOBA]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.FUSE]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.CRONOS]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.GRAVITY]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', } const fetch = async ({ chain, getLogs, createBalances, }: FetchOptions) => { const dailyVolume = createBalances(); let data: any[] = await getLogs({ target: contract[chain], eventAbi: 'event LiFiGenericSwapCompleted(bytes32 indexed transactionId, string integrator, string referrer, address receiver, address fromAssetId, address toAssetId, uint256 fromAmount, uint256 toAmount)' }); const blacklistedTokens = getDefaultDexTokensBlacklisted(chain) if (blacklistedTokens.length > 0) { data = data.filter(log => !blacklistedTokens.includes(formatAddress(log.fromAssetId)) && !blacklistedTokens.includes(formatAddress(log.toAssetId))) } data.forEach((e: any) => { if (e.integrator === 'jumper.exchange' || e.integrator === 'jumper.exchange.gas') { dailyVolume.add(e.toAssetId, e.toAmount); } }); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, adapter: Object.keys(contract).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2023-08-10', } } }, {}) }; export default adapter; ================================================ FILE: aggregators/jupiter-aggregator/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { Dependencies, FetchOptions } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; // 1800 1022 777 const fetch = async (_a: any, _b: any, options: FetchOptions) => { // https://dune.com/queries/4187430 const data = await queryDuneSql(options, ` SELECT sum(COALESCE(input_usd,output_usd)) as volume_24 FROM jupiter_solana.aggregator_swaps WHERE block_time >= from_unixtime(${options.startTimestamp}) AND block_time < from_unixtime(${options.endTimestamp}) `); const chainData = data[0]; if (!chainData) throw new Error(`Dune query failed: ${JSON.stringify(data)}`); return { dailyVolume: chainData.volume_24 }; }; const adapter: any = { version: 1, dependencies: [Dependencies.DUNE], fetch, start: '2023-04-16', methodology: { Volume: "Volume is calculated by summing the token volume of all trades settled on the protocol that day.", }, chains: [CHAIN.SOLANA], }; export default adapter; ================================================ FILE: aggregators/kame-aggregator/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = "https://api.kame.ag/api/statistics"; const fetch = async ({ fromTimestamp, toTimestamp }: FetchOptions) => { const response = await fetchURL(`${URL}/?startTime=${fromTimestamp}&endTime=${toTimestamp}`); const volume = response.volume > 25_000_000 ? 0 : response.volume; // quick fix to avoid random api inflated issue return { dailyVolume: volume }; }; export default { version: 2, adapter: { [CHAIN.SEI]: { fetch, start: "2025-04-14", }, }, } ================================================ FILE: aggregators/kanalabs/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { request, gql } from "graphql-request"; const URL = "https://stats.kanalabs.io/transaction/volume"; const TRADE_URL = "https://stats.kanalabs.io/trade/volume"; const GRAPHQL_URL = "https://api-mainnet.kanalabs.io/graphql"; export enum KanaChainID { "solana" = 1, "aptos" = 2, "polygon" = 3, "bsc" = 4, "sui" = 5, "ethereum" = 6, "base" = 7, "klaytn" = 8, "zkSync" = 9, "Avalanche" = 10, "Arbitrum" = 11, "optimistic" = 12, } const fetch = (chain: KanaChainID) => async (timestamp: number, t: any, options: FetchOptions) => { const dayTimestamp = options.startOfDay + 86400; const data = await fetchURL( `${URL}?timestamp=${dayTimestamp - 1}&chainId=${chain}` ); return { dailyVolume: data.today.volume, }; }; const fetchAptos = async (timestamp: number, t: any, options: FetchOptions) => { const dayTimestamp = options.startOfDay + 86400; const query = gql` query getTransactionVolumesForTransactions($timestamp: Float!, $chainId: Float!) { getTransactionVolumesForTransactions(timestamp: $timestamp, chainId: $chainId) } `; const variables = { timestamp: dayTimestamp - 1, chainId: KanaChainID.aptos, }; const data = await request(GRAPHQL_URL, query, variables); const result = data.getTransactionVolumesForTransactions; return { dailyVolume: result.today.volume, }; }; const start = '2023-09-08'; const adapter: SimpleAdapter = { adapter: { [CHAIN.ETHEREUM]: { fetch: fetch(KanaChainID.ethereum), start: start, }, [CHAIN.BSC]: { fetch: fetch(KanaChainID.bsc), start: start, }, [CHAIN.AVAX]: { fetch: fetch(KanaChainID.Avalanche), start: start, }, [CHAIN.ARBITRUM]: { fetch: fetch(KanaChainID.Arbitrum), start: start, }, [CHAIN.POLYGON]: { fetch: fetch(KanaChainID.polygon), start: start, }, [CHAIN.ERA]: { fetch: fetch(KanaChainID.zkSync), start: start, }, [CHAIN.APTOS]: { fetch: async (timestamp: number, t: any, options: FetchOptions) => { const swap = await fetchAptos(options.startOfDay, t, options); return { dailyVolume: swap.dailyVolume.toString(), }; }, start: start, }, [CHAIN.SUI]: { fetch: fetch(KanaChainID.sui), start: start, }, [CHAIN.SOLANA]: { fetch: fetch(KanaChainID.solana), start: start, }, }, }; export default adapter; ================================================ FILE: aggregators/kuru/index.ts ================================================ import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const abis = { "KuruFlowSwap": "event KuruFlowSwap(address indexed user,address indexed referrer,address tokenIn,address tokenOut,bool isFeeInInput,uint256 amountIn,uint256 amountOut,uint256 referrerFeeBps,uint256 totalFeeBps)", "FeeCollected": "event FeeCollected(address feeCollector, uint256 amount, address referrer, uint256 referrerAmount, address user, address token)", } const KuruFlowEntrypoint = '0xb3e6778480b2E488385E8205eA05E20060B813cb' const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances() const dailyFees = options.createBalances() const dailyRevenue = options.createBalances() const dailySupplySideRevenue = options.createBalances() // Get swap events for volume const swapLogs = await options.getLogs({ target: KuruFlowEntrypoint, eventAbi: abis.KuruFlowSwap, }) swapLogs.forEach((log: any) => { dailyVolume.add(log.tokenIn, log.amountIn) }) // Get fee collection events const feeLogs = await options.getLogs({ target: KuruFlowEntrypoint, eventAbi: abis.FeeCollected, }) // Calculate total fees = amount + referrerAmount feeLogs.forEach((log: any) => { dailyFees.add(log.token, log.amount) dailyFees.add(log.token, log.referrerAmount) dailyRevenue.add(log.token, log.amount) dailySupplySideRevenue.add(log.token, log.referrerAmount) }) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, dailySupplySideRevenue, } }; const adapter: any = { version: 2, pullHourly: true, fetch, adapter: { [CHAIN.MONAD]: { start: '2025-11-17' }, }, methodology: { Volume: "Sum of all token swaps routed through KURU Aggregator", Fees: "Total fees collected from users (protocol fee + referrer fee)", UserFees: "All fees are paid by users", Revenue: "All fees collected go to protocol.", ProtocolRevenue: "All fees collected by protocol (exclude referrer portion).", SupplySideRevenue: "All fees collected by referrers.", } }; export default adapter; ================================================ FILE: aggregators/kyberswap/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; const chainConfig: Record = { [CHAIN.ETHEREUM]: { id: 1, start: '2021-06-01' }, [CHAIN.ARBITRUM]: { id: 42161, start: '2021-09-22' }, [CHAIN.AVAX]: { id: 43114, start: '2021-06-01' }, [CHAIN.BSC]: { id: 56, start: '2021-06-01' }, // [CHAIN.FANTOM]: {id: 250, start: '2021-06-01'}, [CHAIN.OPTIMISM]: { id: 10, start: '2021-12-16' }, [CHAIN.POLYGON]: { id: 137, start: '2021-06-01' }, [CHAIN.LINEA]: { id: 59144, start: '2023-07-11' }, // [CHAIN.SCROLL]: {id: 534352, start: '2021-09-22'}, // [CHAIN.ERA]: {id: 324, start: '2023-03-24'}, // [CHAIN.CRONOS]: { id: 25, start: '2021-06-01' }, [CHAIN.BASE]: { id: 8453, start: '2023-08-09' }, [CHAIN.MANTLE]: { id: 5000, start: '2023-07-17', deadFrom: '2026-02-16' }, // [CHAIN.BLAST]: {id: 81457, start: '2024-02-29'}, // [CHAIN.POLYGON_ZKEVM]: { id: 1101, start: '2023-03-27' }, // [CHAIN.BITTORRENT]: {id: 199, start: '2021-06-01'}, [CHAIN.SONIC]: { id: 146, start: '2024-12-18' }, [CHAIN.BERACHAIN]: { id: 80094, start: '2025-02-06' }, [CHAIN.UNICHAIN]: { id: 130, start: '2025-02-11' }, [CHAIN.HYPERLIQUID]: { id: 999, start: '2025-07-09' }, [CHAIN.PLASMA]: { id: 9745, start: '2025-09-24' }, [CHAIN.ETHERLINK]: { id: 42793, start: '2025-10-02', deadFrom: '2026-02-16' }, [CHAIN.MONAD]: { id: 143, start: '2025-11-23' }, [CHAIN.MEGAETH]: { id: 4326, start: '2026-02-09' }, }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const headers = { origin: "https://common-service.kyberswap.com" }; const url = `https://common-service.kyberswap.com/api/v1/aggregator/volume/daily?chainId=${chainConfig[options.chain].id}×tamps=${options.startOfDay}`; const dailyVolume = (await httpGet(url, { headers })).data?.volumes?.[0].value; return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 1, fetch, adapter: chainConfig }; export default adapter; ================================================ FILE: aggregators/kyoag/index.ts ================================================ import { ethers } from "ethers"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import ADDRESSES from "../../helpers/coreAssets.json"; const LEGACY_ROUTERS: Record = { [CHAIN.HYPERLIQUID]: [ "0x5d78854510a2d008E2E21c2fAB4Cc78582B0F2Ce", "0x91B81ACd2Ee2D8F26518139Af632c56Fad28Dcb4", ], [CHAIN.SONEIUM]: [ "0xD2dFd922fd6bBAe0399F68F99CD444adbd80d255", "0xf4087AFfE358c1f267Cca84293abB89C4BD10712", ], }; // Router delegates execution to logic contracts passed in calldata, so keep a small // manual allowlist of known logic contracts per chain and index inflows to both. const LOGICS: Record = { [CHAIN.HYPERLIQUID]: [ "0x775f533c082a466156bd0e771957853375c96265", "0xE34E1A6b31D90ED63E1e8EB0640495978b4eB172", "0xD3027e4869da32d3c295271E4c8d4c4f6C170464", "0xcb7a9dF8074c2a2c06496b8Bee28372051f3abd7", "0x69E896668A0dDe9450C8EdD8c1D2Cee2bF99A9a9", "0xC049cA5Fa95CdE6Fd4ADCeaFaaf331A6bb33C435", "0xF8A773940Dee10144D5204c44749220e8FFa7b49", "0x7A34F2C757589825aa795aa98B72F301A8980be0", "0x0cB398DE0616c8E7b2b737fF715ACcDc888e99ce", "0x484408554626d420DE940f91786Ffb4913A78000", "0x734b73B13594638a11f59B35257390738D08543d", ], [CHAIN.SONEIUM]: [ "0xB3f8F67230CbAcD5Adf297BE3F1884A845c9c3C0", "0xd118e1c57d347D13BF2b14Bd665B74b7B56AF563", "0xC049cA5Fa95CdE6Fd4ADCeaFaaf331A6bb33C435", "0x36af20bc2d7F1B3cBd9cADC61395a3c5c56A75D0", "0x26Dd7F2672C96761280DC2f7Ad9D431e518002e9", "0xf582CBB0788323FAaCB00a6677caF4890ed19aCF", "0xaec97346c8d562EccfBa46325d00Af3fFB7246d0", "0x23120352144E920dbAC60bcDa2d78dE4845A084f", ], }; const EVENT_ROUTERS: Record = { [CHAIN.HYPERLIQUID]: ["0x463E176246c4fF727153a8b98381531df1B66b80"], [CHAIN.SONEIUM]: ["0x206D7FBBD740780D7eFf488D40744276e8dAf077"], [CHAIN.MONAD]: ["0x852a57ae203fec9c96c7ac9a774db048cbe4e34e"], }; const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; const DEPOSIT_TOPIC = "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"; const NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; const SWAP_EXECUTED_EVENT = "event SwapExecuted(address indexed sender, address indexed srcToken, address indexed dstToken, address logic, uint256 amountIn, uint256 amountOut)"; const WRAPPED_NATIVE_TOKENS: Record = { [CHAIN.HYPERLIQUID]: [ADDRESSES.hyperliquid.WHYPE], [CHAIN.SONEIUM]: [ADDRESSES.soneium.WETH], [CHAIN.MONAD]: [ADDRESSES.monad.WMON, ADDRESSES.monad.WETH], }; const isPositiveAmount = (amount?: string) => { if (!amount || amount === "0x") return false; try { return BigInt(amount) > 0n; } catch { return false; } }; const addVolume = ( dailyVolume: ReturnType, token?: string, amount?: string, ) => { if (!token || !isPositiveAmount(amount)) return; if (token.toLowerCase() === NATIVE_TOKEN.toLowerCase()) dailyVolume.addGasToken(amount); else dailyVolume.add(token, amount); }; const fetch = async ({ createBalances, getLogs, chain }: FetchOptions) => { const dailyVolume = createBalances(); const eventRouters = EVENT_ROUTERS[chain] ?? []; const trackedTargets = [...eventRouters, ...(LEGACY_ROUTERS[chain] ?? []), ...(LOGICS[chain] ?? [])]; const trackedSet = new Set(trackedTargets.map((r) => r.toLowerCase())); const wrappedNativeSet = new Set((WRAPPED_NATIVE_TOKENS[chain] ?? []).map((a) => a.toLowerCase())); const allLogs: any[] = []; const eventTxs = new Set(); if (eventRouters.length) { const eventLogs = await getLogs({ targets: eventRouters, eventAbi: SWAP_EXECUTED_EVENT, onlyArgs: false, }); for (const log of eventLogs) { const txHash = (log.transactionHash as string | undefined)?.toLowerCase(); if (txHash) eventTxs.add(txHash); addVolume( dailyVolume, log.srcToken ?? log.args?.srcToken, log.amountIn ?? log.args?.amountIn, ); } } for (const target of trackedTargets) { const padded = ethers.zeroPadValue(target, 32); const [transferLogs, depositLogs] = await Promise.all([ getLogs({ topics: [TRANSFER_TOPIC, null as any, padded], noTarget: true, eventAbi: "event Transfer(address indexed from, address indexed to, uint256 value)", entireLog: true, }), getLogs({ topics: [DEPOSIT_TOPIC, padded], noTarget: true, eventAbi: "event Deposit(address indexed dst, uint256 wad)", entireLog: true, }), ]); for (const log of transferLogs) { if (!isPositiveAmount(log.data)) continue; const txHash = (log.transactionHash as string | undefined)?.toLowerCase(); if (!txHash) continue; if (eventTxs.has(txHash)) continue; // Exclude transfers from other tracked contracts (router/logic internal routing) if (!log.topics?.[1]) continue; const from = "0x" + log.topics[1].slice(26).toLowerCase(); if (trackedSet.has(from)) continue; allLogs.push(log); } for (const log of depositLogs) { if (!isPositiveAmount(log.data)) continue; const txHash = (log.transactionHash as string | undefined)?.toLowerCase(); if (!txHash) continue; if (eventTxs.has(txHash)) continue; const emitter = (log.address as string | undefined)?.toLowerCase(); if (!emitter || !wrappedNativeSet.has(emitter)) continue; allLogs.push(log); } } // Per transaction: keep only the first inbound transfer/deposit (lowest log index). // This is the sell-token inflow before DEX routing, internal hops, or fee payouts. const firstByTx: Record = {}; for (const log of allLogs) { const txHash = (log.transactionHash as string | undefined)?.toLowerCase(); if (!txHash) continue; const idx = log.logIndex ?? log.index ?? 0; const prev = firstByTx[txHash]; if (!prev || idx < (prev.logIndex ?? prev.index ?? 0)) { firstByTx[txHash] = log; } } for (const log of Object.values(firstByTx)) { addVolume(dailyVolume, log.address, log.data); } return { dailyVolume }; }; const methodology = { Volume: "New KYO AG routers are indexed from SwapExecuted events using the srcToken " + "amountIn side when present. Routers or methods that do not emit a swap event " + "(including legacy routers and swapMulti flows) are indexed via the earliest " + "inbound ERC-20 Transfer or wrapped-native Deposit to the router or allowlisted " + "logic contract; internal hops and fee payouts are excluded.", }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.HYPERLIQUID]: { fetch, start: "2026-02-03" }, [CHAIN.MONAD]: { fetch, start: "2026-03-23" }, [CHAIN.SONEIUM]: { fetch, start: "2025-12-30" }, }, methodology, }; export default adapter; ================================================ FILE: aggregators/lamboo/index.ts ================================================ import { Dependencies, FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { queryDuneSql } from "../../helpers/dune"; const INTEGRATOR_ADDRESS = "0xc6cc6a4f294c4cab2b749721afc56e9f7e4ad695d44d470cdfa57321fe7205a1"; const ROUTER_FEE_EVENT = "0x1cb4fd7144568b4eae2b0d32aaf51fe87fc729eb498295b0a976d91f1692522d::router::FeeEvent"; const PANORA_INTEGRATOR_FEE_EVENT = "0x1c3206329806286fd2223647c9f9b130e66baeb6d7224a18c1f642ffe48f3b4c::panora_fees_structure::FeeEventIntegrator"; const BOOSTER_FEE_EVENT = "0xd5864a543c1d6dbf4f6f3b0a2c660746366cb65fc340d593b966495fdf03a0b::b::FeeEvent"; const LAMBOO_FEE_EVENT = "0xd5864a543c1d6dbf4f6f3b0a2c660746366cb65fc340d593b966495fdf03a0b::lamboo::FeeEvent"; const WITHDRAW_EVENT = "0x1::fungible_asset::Withdraw"; const DEPOSIT_EVENT = "0x1::fungible_asset::Deposit"; const FEE_EVENT_TYPE_LIST = [ ROUTER_FEE_EVENT, PANORA_INTEGRATOR_FEE_EVENT, BOOSTER_FEE_EVENT, LAMBOO_FEE_EVENT, ]; const FEE_EVENT_TYPES = FEE_EVENT_TYPE_LIST.map((eventType) => `'${eventType}'`).join(",\n "); const APT_CANONICAL = "0x1::aptos_coin::AptosCoin"; const APT_SHORT = "0xa"; const APT_TOKEN = "0x000000000000000000000000000000000000000000000000000000000000000a"; const USD1_SHORT = "0x5fabd1b12e39967a3c24e91b7b8f67719a6dacee74f3c8b9fb7d93e855437d2"; const USD1_TOKEN = "0x05fabd1b12e39967a3c24e91b7b8f67719a6dacee74f3c8b9fb7d93e855437d2"; const APT_TOKEN_VARIANTS = [APT_CANONICAL, APT_SHORT, APT_TOKEN]; const USD1_TOKEN_VARIANTS = [USD1_SHORT, USD1_TOKEN]; const TRACKED_TOKEN_VARIANTS = [...APT_TOKEN_VARIANTS, ...USD1_TOKEN_VARIANTS]; const TRACKED_TOKEN_TYPES = TRACKED_TOKEN_VARIANTS.map((token) => `'${token}'`).join(",\n "); const APT_TOKEN_TYPES = APT_TOKEN_VARIANTS.map((token) => `'${token}'`).join(", "); const USD1_TOKEN_TYPES = USD1_TOKEN_VARIANTS.map((token) => `'${token}'`).join(", "); const fetch = async (_: any, __: any, options: FetchOptions): Promise => { const volumeQuery = ` WITH date_filter AS ( SELECT from_unixtime(${options.startTimestamp}) AS start_ts, from_unixtime(${options.endTimestamp}) AS end_ts ), filtered_events AS ( SELECT e.tx_version, JSON_EXTRACT_SCALAR(e.data, '$.fee_receiver') AS fee_receiver, JSON_EXTRACT_SCALAR(e.data, '$.integrator_address') AS integrator_address FROM aptos.events e CROSS JOIN date_filter d WHERE e.block_date >= d.start_ts AND e.block_date < d.end_ts AND e.event_type IN (${FEE_EVENT_TYPES}) ), fee_events AS ( SELECT DISTINCT tx_version FROM filtered_events WHERE fee_receiver = '${INTEGRATOR_ADDRESS}' OR integrator_address = '${INTEGRATOR_ADDRESS}' ), fee_transactions AS ( SELECT ut.version AS tx_version, ut.sender FROM aptos.user_transactions ut INNER JOIN fee_events fe ON ut.version = fe.tx_version CROSS JOIN date_filter d WHERE ut.block_date >= d.start_ts AND ut.block_date < d.end_ts ), event_flows AS ( SELECT e.tx_version, e.block_date, JSON_EXTRACT_SCALAR(e.data, '$.store') AS store_address, CAST(JSON_EXTRACT_SCALAR(e.data, '$.amount') AS DOUBLE) AS amount, e.event_type FROM aptos.events e INNER JOIN fee_events fe ON e.tx_version = fe.tx_version CROSS JOIN date_filter d WHERE e.block_date >= d.start_ts AND e.block_date < d.end_ts AND e.event_type IN ('${DEPOSIT_EVENT}', '${WITHDRAW_EVENT}') ), distinct_stores AS ( SELECT DISTINCT store_address FROM event_flows ), store_metadata AS ( SELECT mr.move_address AS store_address, MAX( CASE WHEN move_resource_module = 'fungible_asset' AND move_resource_name = 'FungibleStore' THEN json_extract_scalar(move_data, '$.metadata.inner') END ) AS token, MAX( CASE WHEN move_resource_module = 'object' AND move_resource_name = 'ObjectCore' THEN json_extract_scalar(move_data, '$.owner') END ) AS owner FROM aptos.move_resources mr INNER JOIN distinct_stores ds ON ltrim(regexp_replace(CAST(mr.move_address AS VARCHAR), '^0x', ''), '0') = ltrim(regexp_replace(ds.store_address, '^0x', ''), '0') CROSS JOIN date_filter d WHERE mr.block_date >= d.start_ts AND mr.block_date < d.end_ts AND ( (move_resource_module = 'object' AND move_resource_name = 'ObjectCore') OR (move_resource_module = 'fungible_asset' AND move_resource_name = 'FungibleStore') ) GROUP BY mr.move_address ), final_volume AS ( SELECT date_trunc('day', ef.block_date) AS day, CASE WHEN sm.token IN (${APT_TOKEN_TYPES}) THEN '${APT_CANONICAL}' WHEN sm.token IN (${USD1_TOKEN_TYPES}) THEN '${USD1_TOKEN}' ELSE sm.token END AS token, ABS(SUM( CASE WHEN ef.event_type = '${DEPOSIT_EVENT}' THEN ef.amount WHEN ef.event_type = '${WITHDRAW_EVENT}' THEN -ef.amount ELSE 0 END )) AS amount FROM event_flows ef INNER JOIN store_metadata sm ON ltrim(regexp_replace(ef.store_address, '^0x', ''), '0') = ltrim(regexp_replace(CAST(sm.store_address AS VARCHAR), '^0x', ''), '0') INNER JOIN fee_transactions ft ON ef.tx_version = ft.tx_version AND ltrim(regexp_replace(sm.owner, '^0x', ''), '0') = ltrim(regexp_replace(CAST(ft.sender AS VARCHAR), '^0x', ''), '0') WHERE sm.token IN (${TRACKED_TOKEN_TYPES}) GROUP BY 1, 2, ef.tx_version HAVING ABS(SUM( CASE WHEN ef.event_type = '${DEPOSIT_EVENT}' THEN ef.amount WHEN ef.event_type = '${WITHDRAW_EVENT}' THEN -ef.amount ELSE 0 END )) > 0.0001 ) SELECT day, token, SUM(amount) AS amount FROM final_volume GROUP BY 1, 2 `; const volumeRows = await queryDuneSql(options, volumeQuery) const dailyVolume = options.createBalances(); for (const row of volumeRows ?? []) { const token = String(row.token ?? ""); const amount = Number(row.amount ?? 0); if (!token || !Number.isFinite(amount) || amount <= 0) continue; dailyVolume.add(token, amount); } return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 1, dependencies: [Dependencies.DUNE], adapter: { [CHAIN.APTOS]: { fetch, start: "2026-01-01", }, }, methodology: { Volume: "Volume is calculated by summing the amounts from fee-related transactions involving the integrator address.", }, }; export default adapter; ================================================ FILE: aggregators/lifi/index.ts ================================================ import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { LifiDiamonds, fetchVolumeFromLIFIAPI } from "../../helpers/aggregators/lifi"; import { CHAIN } from "../../helpers/chains"; import { getDefaultDexTokensBlacklisted, getDefaultDexTokensWhitelisted } from "../../helpers/lists"; import { formatAddress } from "../../utils/utils"; const LifiSwapEvent = "event LiFiGenericSwapCompleted(bytes32 indexed transactionId, string integrator, string referrer, address receiver, address fromAssetId, address toAssetId, uint256 fromAmount, uint256 toAmount)" const integrators = ['jumper.exchange', 'transferto.xyz', 'jumper.exchange.gas', 'lifi-gasless-jumper'] const fetch: any = async (options: FetchOptions): Promise => { if (options.chain === CHAIN.BITCOIN || options.chain === CHAIN.SOLANA) { const dailyVolume = await fetchVolumeFromLIFIAPI(options.chain, options.startTimestamp, options.endTimestamp, integrators, [], 'same-chain'); return { dailyVolume: dailyVolume }; } const dailyVolume = options.createBalances(); let logs: any[] = await options.getLogs({ target: LifiDiamonds[options.chain].id, topic: '0x38eee76fd911eabac79da7af16053e809be0e12c8637f156e77e1af309b99537', eventAbi: LifiSwapEvent, }) // count volune only from whitelisted tokens const blacklistedTokens = getDefaultDexTokensBlacklisted(options.chain) const whitelistedTokens = await getDefaultDexTokensWhitelisted({chain: options.chain}) if (whitelistedTokens.length > 0) { logs = logs.filter(log => (whitelistedTokens.includes(formatAddress(log.fromAssetId)) || whitelistedTokens.includes(formatAddress(log.toAssetId))) && !blacklistedTokens.includes(formatAddress(log.fromAssetId)) && !blacklistedTokens.includes(formatAddress(log.toAssetId)) ) } logs.forEach((log: any) => { if (!integrators.includes(log.integrator)) { dailyVolume.add(log.fromAssetId, log.fromAmount); } }); return { dailyVolume } as any; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: Object.keys(LifiDiamonds).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: LifiDiamonds[chain].startTime, } } }, {}) }; export default adapter; ================================================ FILE: aggregators/lilswap/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const chainAliases: Record = { [CHAIN.ETHEREUM]: "ethereum", [CHAIN.BSC]: "bnb", [CHAIN.POLYGON]: "polygon", [CHAIN.BASE]: "base", [CHAIN.ARBITRUM]: "arbitrum", [CHAIN.AVAX]: "avalanche", [CHAIN.OPTIMISM]: "optimism", [CHAIN.XDAI]: "gnosis", [CHAIN.SONIC]: "sonic", } const BASE_URL = 'https://api.lilswap.xyz/v1/metrics/daily'; const LABELS = { FEES: "Explicit Swap Fees", REVENUE: "Explicit Swap Fees To Protocol", SUPPLY_SIDE: "Explicit Swap Fees To External Partners", } async function fetch(_a: any, _b: any, options: FetchOptions) { const dailyFees = options.createBalances(); const dailyRevenue = options.createBalances(); const dailySupplySideRevenue = options.createBalances(); const dailyVolume = options.createBalances(); const chainAlias = chainAliases[options.chain]; const response = await fetchURL(`${BASE_URL}?start=${options.fromTimestamp}&end=${options.toTimestamp}&chain=${chainAlias}`); if (!response.data) { throw new Error(`No data found for chain ${options.chain} on ${options.dateString}`); } const todaysData = response.data.find((item: any) => item.date === options.dateString); if (todaysData) { dailyFees.addUSDValue(Number(todaysData.feesUsd), LABELS.FEES); dailyRevenue.addUSDValue(Number(todaysData.revenueUsd), LABELS.REVENUE); dailySupplySideRevenue.addUSDValue(Number(todaysData.supplySideRevenueUsd), LABELS.SUPPLY_SIDE); dailyVolume.addUSDValue(Number(todaysData.volumeUsd)); } return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, dailySupplySideRevenue }; } const methodology = { Fees: "Includes explicit LilSwap fees from confirmed swaps sourced from LilSwap's public daily metrics endpoint.", UserFees: "Users pay LilSwap's explicit swap fees on confirmed swaps, sourced from LilSwap's public daily metrics endpoint.", Revenue: "LilSwap retained explicit swap fees, sourced from LilSwap's public daily metrics and computed as total explicit fees minus the external partner fee share.", ProtocolRevenue: "Same as daily revenue, computed from the explicit fee split as dailyFees minus dailySupplySideRevenue.", SupplySideRevenue: "External partner fee share sourced from LilSwap's public daily metrics endpoint.", } const breakdownMethodology = { Fees: { [LABELS.FEES]: "Explicit LilSwap fees from confirmed swaps.", }, UserFees: { [LABELS.FEES]: "Explicit LilSwap fees from confirmed swaps.", }, Revenue: { [LABELS.REVENUE]: "Explicit LilSwap fees minus external partner fee share.", }, ProtocolRevenue: { [LABELS.REVENUE]: "Explicit LilSwap fees minus external partner fee share.", }, SupplySideRevenue: { [LABELS.SUPPLY_SIDE]: "External partner fee share.", }, } const adapter: SimpleAdapter = { fetch, start: '2026-02-25', chains: Object.keys(chainAliases), methodology, breakdownMethodology, } export default adapter; ================================================ FILE: aggregators/liquidmesh/index.ts ================================================ import { Dependencies, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { queryDuneSql } from "../../helpers/dune"; import { FetchOptions } from "../../adapters/types"; import { getDefaultDexTokensBlacklisted, getDefaultDexTokensWhitelisted } from "../../helpers/lists"; import { formatAddress } from "../../utils/utils"; interface IData { chain: string; token: string; amount: number; } const chainsMap: Record = { "ethereum": CHAIN.ETHEREUM, "base": CHAIN.BASE, "bnb": CHAIN.BSC, "sonic": CHAIN.SONIC, "tron": CHAIN.TRON, }; const prefetch = async (options: FetchOptions): Promise => { // must exclude all blacklisted tokens const ethereumBlacklistedTokens = getDefaultDexTokensBlacklisted(CHAIN.ETHEREUM) const bscBlacklistedTokens = getDefaultDexTokensBlacklisted(CHAIN.BSC) const allBlacklistedTokens = ethereumBlacklistedTokens.concat(bscBlacklistedTokens) const data: IData[] = await queryDuneSql(options, ` SELECT chain, fromToken as token, SUM(fromAmount) as amount FROM liquidmesh_multichain.liquidmeshrouter_evt_orderrecord WHERE evt_block_time >= from_unixtime(${options.startTimestamp}) AND evt_block_time < from_unixtime(${options.endTimestamp}) AND fromToken NOT IN (${allBlacklistedTokens.toString()}) AND toToken NOT IN (${allBlacklistedTokens.toString()}) AND fromAmount < UINT256 '115792089237316195423570985008687907853269984665640564039457584007913129639935' GROUP BY chain, fromToken `) return data; }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const dailyVolume = options.createBalances() const tokensAndAmounts: Array = options.preFetchedResults || [] const blacklistedTokens = getDefaultDexTokensBlacklisted(options.chain) const whitesliedTokens = await getDefaultDexTokensWhitelisted({ chain: options.chain }) for (const token of tokensAndAmounts.filter(item => options.chain === chainsMap[item.chain] && item.token !== '0x0000000000000000000000000000000000000000')) { if (options.chain === CHAIN.BSC) { if (whitesliedTokens.includes(formatAddress(token.token))) { dailyVolume.add(token.token, token.amount); } } else { if (!blacklistedTokens.includes(formatAddress(token.token))) { dailyVolume.add(token.token, token.amount); } } } return { dailyVolume, }; }; const fetchSolana = async (_a: any, _b: any, options: FetchOptions) => { const dailyVolume = options.createBalances() const blacklistTokens = ['2xaPstY4XqJ2gUA1mpph3XmvmPZGuTuJ658AeqX3gJ6F'] const tokensAndAmounts: Array = await queryDuneSql(options, ` SELECT 'solana' AS chain, (CASE WHEN source_token_mint = '11111111111111111111111111111111' THEN 'So11111111111111111111111111111111111111112' ELSE source_token_mint END) AS token, SUM(amount_in) as amount FROM liquidmesh_solana.liquid_mesh_router_evt_liquidmeshswapevent WHERE evt_block_time >= from_unixtime(${options.startTimestamp}) AND evt_block_time < from_unixtime(${options.endTimestamp}) GROUP BY source_token_mint `) for (const item of tokensAndAmounts) { dailyVolume.add(item.token, item.amount); } for (const t of blacklistTokens) { dailyVolume.removeTokenBalance(t) } return { dailyVolume, }; }; const adapter: SimpleAdapter = { version: 1, dependencies: [Dependencies.DUNE], start: '2025-08-01', adapter: Object.values(chainsMap).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: fetch, }, }; }, { [CHAIN.SOLANA]: { fetch: fetchSolana, } }), prefetch: prefetch, methodology: { Volume: "Tracks the trading volume across all supported chains through LiquidMesh aggregator", }, isExpensiveAdapter: true, } export default adapter ================================================ FILE: aggregators/liquidswap/index.ts ================================================ import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const SwapExecutedEvent = "event SwapExecuted(address indexed sender, address input_token_address, uint256 input_token_amount, address output_token_address, uint256 output_token_amount, uint256 timestamp)"; const PositiveSlippageCapturedEvent = "event PositiveSlippageCaptured(address indexed sender, address protocolRecipient, address feeRecipient, address token, uint256 expectedAmount, uint256 actualAmount, uint256 totalCapturedAmount, uint256 capturedToProtocol, uint256 capturedToFeeRecipient, uint256 timestamp)"; const FeeCapturedEvent = "event FeeCaptured(address indexed sender, address feeRecipient, address protocolFeeRecipient, address token, uint256 totalFee, uint256 feeToRecipient, uint256 feeToProtocolRecipient, uint256 timestamp)"; const LIQUIDSWAP_ADDRESS = "0x744489ee3d540777a66f2cf297479745e0852f7a"; // const PROTOCOL_FEE_ADDRESS = "0xaC7d51dB236fae22Ceb6453443da248F3A53f94d"; const METRICS = { SwapFees: 'Swap Fees', PositiveSlippageCaptured: 'Positive Slippage Captured', SwapFeesToIntergators: 'Swap Fees To Intergators', SwapFeesToProtocol: 'Swap Fees To Protocol', PositiveSlippageCapturedToIntergators: 'Positive Slippage Captured To Intergators', PositiveSlippageCapturedToProtocol: 'Positive Slippage Captured To Protocol', } const fetch: any = async (options: FetchOptions): Promise => { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const dailyRevenue = options.createBalances(); const dailySupplySideRevenue = options.createBalances(); // Get SwapExecuted events for volume const swapLogs = await options.getLogs({ target: LIQUIDSWAP_ADDRESS, eventAbi: SwapExecutedEvent, }); for (const swapLog of swapLogs) { dailyVolume.add(swapLog.input_token_address, swapLog.input_token_amount); } // Get PositiveSlippageCaptured events for positive slippage revenue const slippageLogs = await options.getLogs({ target: LIQUIDSWAP_ADDRESS, eventAbi: PositiveSlippageCapturedEvent, }); for (const slippageLog of slippageLogs) { // Add positive slippage to fees and revenue dailyFees.add(slippageLog.token, slippageLog.totalCapturedAmount, METRICS.PositiveSlippageCaptured); const revenueToIntergators = BigInt(slippageLog.totalCapturedAmount) - BigInt(slippageLog.capturedToProtocol) dailyRevenue.add(slippageLog.token, slippageLog.capturedToProtocol, METRICS.PositiveSlippageCapturedToProtocol); dailySupplySideRevenue.add(slippageLog.token, revenueToIntergators, METRICS.PositiveSlippageCapturedToIntergators); } // Get FeeCaptured events for fees const feeLogs = await options.getLogs({ target: LIQUIDSWAP_ADDRESS, eventAbi: FeeCapturedEvent, }); for (const feeLog of feeLogs) { // Add total fees to fees and revenue dailyFees.add(feeLog.token, feeLog.totalFee, METRICS.SwapFees); const revenueToIntergators = BigInt(feeLog.totalFee) - BigInt(feeLog.feeToProtocolRecipient) dailyRevenue.add(feeLog.token, feeLog.feeToProtocolRecipient, METRICS.SwapFeesToProtocol); dailySupplySideRevenue.add(feeLog.token, revenueToIntergators, METRICS.SwapFeesToProtocol); } return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, dailySupplySideRevenue, dailyHoldersRevenue: 0, // no revenue shared to holders }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, start: "2025-04-02", methodology: { Volume: "Volume is calculated from SwapExecuted events emitted by the LiquidSwap aggregator contract.", Fees: "Fees are tracked from PositiveSlippageCaptured and FeeCaptured events.", Revenue: "Revenue represents the protocol share of captured positive slippage and fees.", ProtocolRevenue: "Revenue represents the protocol share of captured positive slippage and fees.", SupplySideRevenue: "The share of captured positive slippage and fees to integrators.", HoldersRevenue: 'No revenue shared to LIQD token holders', }, breakdownMethodology: { Fees: { [METRICS.SwapFees]: 'Total swap fees paid by users per swap.', [METRICS.PositiveSlippageCaptured]: 'Profit from possitive slippage captured.', }, Revenue: { [METRICS.SwapFeesToProtocol]: 'Swap fees share to protocol.', [METRICS.PositiveSlippageCapturedToProtocol]: 'Profit from possitive slippage shared to protocol.', }, SupplySideRevenue: { [METRICS.SwapFeesToIntergators]: 'Swap fees share to intergators.', [METRICS.PositiveSlippageCapturedToIntergators]: 'Profit from possitive slippage shared to intergators.', }, ProtocolRevenue: { [METRICS.SwapFeesToProtocol]: 'Swap fees share to protocol.', [METRICS.PositiveSlippageCapturedToProtocol]: 'Profit from possitive slippage shared to protocol.', }, }, chains: [CHAIN.HYPERLIQUID], }; export default adapter; ================================================ FILE: aggregators/llamaswap/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = "https://api.llama.fi/"; const chains = [ CHAIN.ETHEREUM, CHAIN.BSC, CHAIN.POLYGON, CHAIN.OPTIMISM, CHAIN.ARBITRUM, CHAIN.AVAX, "gnosis", CHAIN.FANTOM, CHAIN.KLAYTN, CHAIN.AURORA, CHAIN.CELO, CHAIN.CRONOS, CHAIN.DOGECHAIN, CHAIN.MOONRIVER, "bttc", CHAIN.OASIS, CHAIN.VELAS, CHAIN.HECO, CHAIN.HARMONY, CHAIN.BOBA, CHAIN.OKEXCHAIN, CHAIN.FUSE, CHAIN.MOONBEAM, CHAIN.CANTO, CHAIN.ZKSYNC, "polygonzkevm", "ontology", CHAIN.KAVA, CHAIN.PULSECHAIN, CHAIN.METIS, CHAIN.BASE, ]; const fetch = async (timestamp: number, _: any, options: FetchOptions): Promise => { const chain = options.chain if (chain === CHAIN.HECO) { return {} } // skip HECO for now const dailyVolume = await fetchURL( `${URL}getSwapDailyVolume/?timestamp=${timestamp}&chain=${chain}` ); return { dailyVolume: dailyVolume.volume, }; } const adapter: SimpleAdapter = { version: 1, adapter: {}, }; chains.map((chain) => { adapter.adapter[chain] = { fetch, start: '2023-01-04', }; }); export default adapter; ================================================ FILE: aggregators/lunar-finance/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const LUNA_API_BASE = "https://api.lunarfinance.io"; const SWAP_ANALYTICS_ENDPOINT = `${LUNA_API_BASE}/api/analytics/dexs`; interface LunaAnalyticsResponse { success: boolean; data: { dailySwapVolume?: { usd: string; }; dailyFees?: { usd: string; }; dailyRevenue?: { usd: string; }; }; } const fetch = async (options: FetchOptions) => { const url = `${SWAP_ANALYTICS_ENDPOINT}?startTime=${options.startTimestamp + 1}&endTime=${options.endTimestamp}`; const data: LunaAnalyticsResponse = await fetchURL(url); const { dailySwapVolume, dailyFees, dailyRevenue } = data.data; return { dailyVolume: Number(dailySwapVolume?.usd) / 1e18 || 0, dailyFees: Number(dailyFees?.usd) / 1e18 || 0, dailyRevenue: Number(dailyRevenue?.usd) / 1e18 || 0, dailyProtocolRevenue: Number(dailyRevenue?.usd) / 1e18 || 0, }; }; const adapter: SimpleAdapter = { version: 2, chains: [CHAIN.SOLANA], fetch, start: '2025-05-01', methodology: { Fees: "Swap fees include protocol fees charged by Luna Finance plus underlying DEX protocol fees paid by users.", Revenue: "Revenue represents fees collected by Luna Finance protocol from swap transactions, typically 0.1-0.3% of transaction value.", ProtocolRevenue: "Protocol revenue is the portion of fees that goes to Luna Finance treasury.", } }; export default adapter; ================================================ FILE: aggregators/madhouse/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; const CONTRACTS: Record = { [CHAIN.MONAD]: '0x6017684Bea9Cb6e9874fC6DBA4438271eBF9F5DA' } const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances() const swapLogs = await options.getLogs({ target: CONTRACTS[options.chain], eventAbi: 'event SwapExecuted(address tokenIn, uint256 amountIn, address tokenOut, uint256 amountOut)', }) for (const log of swapLogs) { dailyVolume.add(log.tokenIn, log.amountIn); } return { dailyVolume, }; }; const adapter: any = { version: 2, pullHourly: true, adapter: { [CHAIN.MONAD]: { fetch, start: '2025-11-23', }, }, }; export default adapter; ================================================ FILE: aggregators/magpie/index.ts ================================================ import { postURL } from "../../utils/fetchURL"; import { ChainBlocks, FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { getTimestampAtStartOfDayUTC } from "../../utils/date" import { CHAIN } from "../../helpers/chains"; const inflatedVolumes = { [CHAIN.ETHEREUM]: ["2026-04-18","2026-04-19", "2026-04-28"], } const fetch = async (_t: number, _: ChainBlocks, { chain, startOfDay, dateString }: FetchOptions): Promise => { if (inflatedVolumes[chain] && inflatedVolumes[chain].includes(dateString)) { return { dailyVolume: 0, }; } const unixTimestamp = getTimestampAtStartOfDayUTC(startOfDay) const data = await postURL(`https://prewimvk04.execute-api.us-west-1.amazonaws.com/prod/llama`, { timestamp: unixTimestamp, chain: chain }, 10); const chainData = data.result if (chainData === undefined) { return { dailyVolume: 0, }; } else { return { dailyVolume: chainData.dailyVolume, }; } }; const adapter: SimpleAdapter = { version: 1, adapter: { [CHAIN.ETHEREUM]: { fetch, start: '2022-09-08', }, [CHAIN.ARBITRUM]: { fetch, start: '2022-09-08', }, [CHAIN.POLYGON]: { fetch, start: '2022-09-08', }, [CHAIN.AVAX]: { fetch, start: '2022-09-08', }, [CHAIN.BSC]: { fetch, start: '2022-09-08', }, [CHAIN.OPTIMISM]: { fetch, start: '2022-09-08', }, [CHAIN.BASE]: { fetch, start: '2022-09-08', }, [CHAIN.SCROLL]: { fetch, start: '2022-09-08', }, [CHAIN.MANTA]: { fetch, start: '2022-09-08', }, [CHAIN.TAIKO]: { fetch, start: '2022-09-08', }, [CHAIN.POLYGON_ZKEVM]: { fetch, start: '2022-09-08', }, // [CHAIN.BLAST]: { // fetch, // start: '2022-09-08', // }, [CHAIN.METIS]: { fetch, start: '2022-09-08', }, [CHAIN.FANTOM]: { fetch, start: '2022-09-08', }, [CHAIN.SONIC]: { fetch, start: '2024-12-26', }, [CHAIN.ERA]: { fetch, start: '2022-09-08', }, [CHAIN.BERACHAIN]: { fetch, start: '2025-02-10', }, [CHAIN.LINEA]: { fetch, start: '2025-02-11', }, [CHAIN.INK]: { fetch, start: '2025-02-11', }, [CHAIN.ABSTRACT]: { fetch, start: '2025-07-01', }, [CHAIN.UNICHAIN]: { fetch, start: '2025-07-01', }, [CHAIN.HYPERLIQUID]: { fetch, start: '2025-10-01', }, [CHAIN.PLASMA]: { fetch, start: '2025-10-01', }, [CHAIN.SOLANA]: { fetch, start: '2025-11-15', }, [CHAIN.MONAD]: { fetch, start: '2025-11-22', }, [CHAIN.MEGAETH]: { fetch, start: '2026-01-30', }, [CHAIN.MORPH]: { fetch, start: '2026-01-13', }, [CHAIN.FOGO]: { fetch, start: '2026-04-01', }, [CHAIN.KATANA]: { fetch, start: '2026-04-01', }, [CHAIN.TELOS]: { fetch, start: '2026-04-01', }, }, }; export default adapter; ================================================ FILE: aggregators/metamask.ts ================================================ import * as sdk from "@defillama/sdk"; import { Chain, FetchResultV2 } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { Adapter, FetchOptions } from "../adapters/types"; import { formatAddress, sleep } from "../utils/utils"; import { getDefaultDexTokensBlacklisted } from "../helpers/lists"; type IConfig = { [s: string | Chain]: { routerAddress: string; getTrasnactionLimit: number; start: string; }; } export const configs: IConfig = { [CHAIN.ETHEREUM]: { routerAddress: '0x881d40237659c251811cec9c364ef91dc08d300c', getTrasnactionLimit: 5000, start: '2023-01-01', }, [CHAIN.POLYGON]: { routerAddress: '0x1a1ec25dc08e98e5e93f1104b5e5cdd298707d31', getTrasnactionLimit: 5000, start: '2023-01-01', }, [CHAIN.BSC]: { routerAddress: '0x1a1ec25dc08e98e5e93f1104b5e5cdd298707d31', getTrasnactionLimit: 5000, start: '2023-01-01', }, [CHAIN.ARBITRUM]: { routerAddress: '0x9dda6ef3d919c9bc8885d5560999a3640431e8e6', getTrasnactionLimit: 10000, start: '2023-01-01', }, [CHAIN.OPTIMISM]: { routerAddress: '0x9dda6ef3d919c9bc8885d5560999a3640431e8e6', getTrasnactionLimit: 10000, start: '2023-01-01', }, [CHAIN.BASE]: { routerAddress: '0x9dda6ef3d919c9bc8885d5560999a3640431e8e6', getTrasnactionLimit: 5000, start: '2023-11-18', }, [CHAIN.LINEA]: { routerAddress: '0x9dda6ef3d919c9bc8885d5560999a3640431e8e6', getTrasnactionLimit: 10000, start: '2023-10-03', }, [CHAIN.AVAX]: { routerAddress: '0x1a1ec25dc08e98e5e93f1104b5e5cdd298707d31', getTrasnactionLimit: 10000, start: '2023-01-01', }, [CHAIN.MONAD]: { routerAddress: '0x962287c9d5b8a682389e61edae90ec882325d08b', getTrasnactionLimit: 10000, start: '2025-10-01', }, [CHAIN.HYPERLIQUID]: { routerAddress: '0xb165c4d4b8044d4a9276c3d75f08cd6a2874a3b2', getTrasnactionLimit: 10000, start: '2026-01-13', }, } async function retry(chain: string, fromBlock: number, toBlock: number, address: string): Promise> { for (let i = 0; i < 5; i++) { try { return (await sdk.indexer.getTransactions({ chain: chain, from_block: fromBlock, to_block: toBlock, transactionType: 'to', addresses: [address], })) as Array; } catch (e: any) { if (i === 4) { throw e; } } await sleep(5000); // sleep 5 secs } return []; } export const fetch = async (options: FetchOptions): Promise => { const dailyVolume = options.createBalances() const blacklistTokens: Array = getDefaultDexTokensBlacklisted(options.chain) const limit = configs[options.chain].getTrasnactionLimit let blockNumber = Number(options.fromApi.block); for (blockNumber; blockNumber <= Number(options.toApi.block); blockNumber += limit + 1) { const toBlock = blockNumber + limit > Number(options.toApi.block) ? Number(options.toApi.block) : blockNumber + limit; const transactions = await retry(options.chain, blockNumber, toBlock, configs[options.chain].routerAddress); if (!transactions) continue; // no transactions found for (const transaction of transactions.filter(tx => tx.status === 1)) { const data = transaction.input.replace('0x5f575529', ''); const address = data.slice(64, 128); const amount = Number('0x' + data.slice(128, 192)); const tokenAddress = '0x' + address.slice(24, address.length); if (!blacklistTokens.includes(formatAddress(tokenAddress))) { dailyVolume.add(tokenAddress, amount); } } } const dailyFees = dailyVolume.clone(0.0085) return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, } } const adapter: Adapter = { version: 2, pullHourly: true, fetch, adapter: configs, } export default adapter; ================================================ FILE: aggregators/mimboku-aggregator/index.ts ================================================ import { gql, request } from "graphql-request"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL_V3 = 'https://graph-api.tentou.tech/subgraphs/name/mimboku' const URL_V2 = 'https://graph-api.tentou.tech/subgraphs/name/mimboku-v2' async function getTotalVolumeV3(block: number): Promise { const query = gql` query GetVolumeUsdV3 { factories(block: {number: ${block}}) { totalVolumeUSD } } `; let totalVolumeUSD = 0; // try { // const resp = await request(URL_V3, query, { block }); // resp.factories.forEach((factory: any) => { // totalVolumeUSD += Math.round(parseFloat(factory.totalVolumeUSD)); // }); // return totalVolumeUSD; // } catch (error) { // console.log(error) // return totalVolumeUSD; // } const resp = await request(URL_V3, query, { block }); resp.factories.forEach((factory: any) => { totalVolumeUSD += Math.round(parseFloat(factory.totalVolumeUSD)); }); return totalVolumeUSD; } async function getTotalVolumeV2(block: number): Promise { const query = gql` query GetVolumeUsdV2 { uniswapFactories(block: {number: ${block}}) { totalVolumeUSD } } `; let totalVolumeUSD = 0; try { const resp = await request(URL_V2, query, { block }); resp.uniswapFactories.forEach((factory: any) => { totalVolumeUSD += Math.round(parseFloat(factory.totalVolumeUSD)); }); return totalVolumeUSD; } catch (error) { console.log(error) return totalVolumeUSD; } } const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const startBlock = await options.getStartBlock(); const endBlock = await options.getEndBlock(); const currentVolumeV3 = await getTotalVolumeV3(endBlock); const startVolumeV3 = await getTotalVolumeV3(startBlock); const dailyVolumeV3 = currentVolumeV3 - startVolumeV3; const currentVolumeV2 = await getTotalVolumeV2(endBlock); const startVolumeV2 = await getTotalVolumeV2(startBlock); const dailyVolumeV2 = currentVolumeV2 - startVolumeV2; dailyVolume.addUSDValue(dailyVolumeV3 + dailyVolumeV2); return { dailyVolume } }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.STORY]: { fetch, start: '2025-05-08', }, }, }; export default adapter; ================================================ FILE: aggregators/minswap/index.ts ================================================ import fetchURL from '../../utils/fetchURL'; import { FetchV2, SimpleAdapter } from '../../adapters/types'; import { CHAIN } from '../../helpers/chains'; const URL = 'https://api-mainnet-prod.minswap.org/defillama/v2/aggregator-volume-series'; const fetch: FetchV2 = async ({ fromTimestamp, toTimestamp }) => { const res = await fetchURL( `${URL}?from_timestamp=${fromTimestamp}&to_timestamp=${toTimestamp}`, ); return { dailyVolume: res.dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.CARDANO]: { fetch, start: '2025-05-21', }, }, }; export default adapter; ================================================ FILE: aggregators/monbridgedex/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; const CONTRACTS: Record = { [CHAIN.MONAD]: "0x7dD7FC9380e3107028a158f49Bd25A8A8D48b225", }; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); // SwapExecuted logs const swapLogs = await options.getLogs({ target: CONTRACTS[options.chain], eventAbi: "event SwapExecuted(address indexed user, address indexed router, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, uint256 fee, uint256 actualSlippage, uint8 swapType)", }); for (const log of swapLogs) { dailyVolume.add(log.tokenIn, log.amountIn); dailyFees.add(log.tokenIn, log.fee); } return { dailyVolume, dailyFees, dailyUserFees: dailyFees, }; }; const adapter: any = { version: 2, pullHourly: true, methodology: { Fees: 'Swap fees paid by users.', UserFees: 'Users pay fees per swap.', }, adapter: { [CHAIN.MONAD]: { fetch, start: "2025-11-28", }, }, }; export default adapter; ================================================ FILE: aggregators/monorail.ts ================================================ import { FetchOptions, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const logs = await options.getLogs({ target: '0xA68A7F0601effDc65C64d9C47cA1b18D96B4352c', topic: '0x6e4c3aa29fc5ed6dc56aa0a95d8ac6660b6bf4e9c2ab49a0ea79b9cdafbcd7eb' }) for (const log of logs) { const tokenIn = '0x' + log.topics[2].slice(26); const amountIn = BigInt('0x' + log.data.slice(2, 66)); dailyVolume.add(tokenIn, amountIn); } return { dailyVolume }; } const adapter: SimpleAdapter = { version: 2, fetch, chains: [CHAIN.MONAD], start: '2025-10-27' } export default adapter; ================================================ FILE: aggregators/mosaic/index.ts ================================================ import { FetchOptions } from "../../adapters/types" import { CHAIN } from "../../helpers/chains" import fetchURL from "../../utils/fetchURL" const STATS_BASE_URL = "https://stats.mosaic.ag" const fetch = async (_timestamp: number, _: any, options: FetchOptions) => { const dateVolumeData = await fetchURL( `${STATS_BASE_URL}/v1/public/volume?from_date=${options.dateString}&to_date=${options.dateString}` ) const volumeData = dateVolumeData.data return { dailyVolume: volumeData.data[0]?.volume, } } export default { adapter: { [CHAIN.MOVE]: { fetch: fetch, start: "2025-03-10", }, }, } ================================================ FILE: aggregators/nanoport/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { Dependencies, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; const EXECUTOR = "0xF0E9286CfCB75c94ac19E99bCD93D814da55e304"; const chains: Record = { [CHAIN.ETHEREUM]: { duneChain: "ethereum" }, [CHAIN.ARBITRUM]: { duneChain: "arbitrum" }, [CHAIN.OPTIMISM]: { duneChain: "optimism" }, [CHAIN.BASE]: { duneChain: "base" }, [CHAIN.POLYGON]: { duneChain: "polygon" }, [CHAIN.BSC]: { duneChain: "bnb" }, [CHAIN.AVAX]: { duneChain: "avalanche_c" }, }; const prefetch = async (options: FetchOptions) => { return queryDuneSql(options, ` SELECT blockchain, COALESCE(SUM(amount_usd), 0) AS volume FROM dex.trades WHERE tx_from = ${EXECUTOR} AND block_time >= from_unixtime(${options.startTimestamp}) AND block_time < from_unixtime(${options.endTimestamp}) GROUP BY blockchain `); }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const chainConfig = chains[options.chain]; if (!chainConfig) return { dailyVolume: 0 }; const data = options.preFetchedResults || []; const chainData = data.find( (item: any) => item.blockchain === chainConfig.duneChain ); return { dailyVolume: chainData?.volume || 0, }; }; const methodology = { Volume: "Volume is calculated by summing the USD value of all swaps executed through the NanoPort executor wallet across supported DEX aggregators.", }; const adapter: SimpleAdapter = { prefetch, version: 1, isExpensiveAdapter: true, dependencies: [Dependencies.DUNE], fetch, start: "2026-02-10", adapter: chains, methodology, }; export default adapter; ================================================ FILE: aggregators/navi/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; import { httpPost } from "../../utils/fetchURL"; const sentioApiKey = "l3ruhon4MonUTvfCHMYVGsK6Axp0KyjMM"; //Read Only const API_URL = "https://app.sentio.xyz/api/v1/analytics/navi/astros/sql/execute"; const HEADERS = { "api-key": sentioApiKey, "Content-Type": "application/json", }; // we need to resync the history data of this aggregator const fetchDailyVolume = async (options: FetchOptions) => { const res = await httpPost( API_URL, JSON.stringify({ sqlQuery: { sql: `SELECT SUM(GREATEST(amount_in_usd, amount_out_usd)) AS usdValue FROM 'swapEvent' WHERE timestamp >= ${options.fromTimestamp} AND timestamp <= ${options.toTimestamp};`, }, }), { headers: HEADERS, } ); return { dailyVolume: res.result.rows[0].usdValue, }; }; //NAVI Aggregator Volume const navi_aggregator: any = { version: 2, adapter: { [CHAIN.SUI]: { fetch: fetchDailyVolume, start: "2024-10-05", }, }, }; export default navi_aggregator; ================================================ FILE: aggregators/neptune-swap/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; const AGGREGATOR_CONTRACT = "0xb3f2B217B024700b6B85bB0941d4958EF17214C1"; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const logs = await options.getLogs({ target: AGGREGATOR_CONTRACT, eventAbi: "event SwapExecuted(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, uint256 taxCollected, uint256 timestamp)", }); for (const log of logs) { dailyVolume.add(log.tokenOut, log.amountOut); dailyFees.add(log.tokenIn, log.taxCollected); } return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const methodology = { Volume: "Total volume of swaps executed by the aggregator.", Fees: "Fees collected from the input token (0.3% of amountIn).", UserFees: "User pays 0.3% of the volume as fees(tax).", Revenue: "All the fees are revenue", ProtocolRevenue: "All the revenue goes to protocol treasury", } const adapter: any = { version: 2, pullHourly: true, fetch, chains: [CHAIN.CRONOS], methodology, start: "2026-02-06", }; export default adapter; ================================================ FILE: aggregators/nordstern-finance/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = 'https://volume-tracking.icecreamswap.dev'; interface IAPIResponse { dailyVolume: string; } const commonStartTime = '2025-08-01' const chainConfig: Record = { [CHAIN.ETHEREUM]: { id: 1, start: commonStartTime }, [CHAIN.HEMI]: { id: 43111, start: commonStartTime }, [CHAIN.ARBITRUM]: { id: 42161, start: commonStartTime }, [CHAIN.CELO]: { id: 42220, start: commonStartTime }, [CHAIN.ROOTSTOCK]: { id: 30, start: commonStartTime }, [CHAIN.XDC]: { id: 50, start: commonStartTime }, [CHAIN.TELOS]: { id: 40, start: commonStartTime }, [CHAIN.AVAX]: { id: 43114, start: commonStartTime }, [CHAIN.SONIC]: { id: 146, start: commonStartTime }, [CHAIN.SCROLL]: { id: 534352, start: commonStartTime }, [CHAIN.TAIKO]: { id: 167000, start: commonStartTime }, [CHAIN.CORE]: { id: 1116, start: commonStartTime }, [CHAIN.IMMUTABLEX]: { id: 13371, start: commonStartTime }, [CHAIN.MORPH]: { id: 2818, start: commonStartTime }, [CHAIN.OPTIMISM]: { id: 10, start: commonStartTime }, [CHAIN.LINEA]: { id: 59144, start: commonStartTime }, [CHAIN.ZIRCUIT]: { id: 48900, start: commonStartTime }, [CHAIN.BOB]: { id: 60808, start: commonStartTime }, [CHAIN.BOBA]: { id: 288, start: commonStartTime }, [CHAIN.BASE]: { id: 8453, start: commonStartTime }, [CHAIN.MANTLE]: { id: 5000, start: commonStartTime }, [CHAIN.BSC]: { id: 56, start: commonStartTime }, [CHAIN.POLYGON]: { id: 137, start: commonStartTime }, [CHAIN.CRONOS]: { id: 25, start: commonStartTime }, [CHAIN.BLAST]: { id: 81457, start: commonStartTime }, [CHAIN.POLYGON_ZKEVM]: { id: 1101, start: commonStartTime }, [CHAIN.BITTORRENT]: { id: 199, start: commonStartTime }, [CHAIN.BERACHAIN]: { id: 80094, start: commonStartTime }, [CHAIN.UNICHAIN]: { id: 130, start: commonStartTime }, [CHAIN.HYPERLIQUID]: { id: 999, start: commonStartTime }, [CHAIN.SEI]: { id: 1329, start: commonStartTime }, [CHAIN.BITGERT]: { id: 32520, start: commonStartTime }, [CHAIN.ULTRON]: { id: 1231, start: commonStartTime }, [CHAIN.EOS]: { id: 17777, start: commonStartTime }, [CHAIN.KAVA]: { id: 2222, start: commonStartTime }, [CHAIN.MOONRIVER]: { id: 1285, start: commonStartTime }, [CHAIN.XLAYER]: { id: 196, start: commonStartTime }, [CHAIN.METIS]: { id: 1088, start: commonStartTime }, [CHAIN.LIGHTLINK_PHOENIX]: { id: 1890, start: commonStartTime }, [CHAIN.MINT]: { id: 185, start: commonStartTime }, [CHAIN.GRAVITY]: { id: 1625, start: commonStartTime }, [CHAIN.OKEXCHAIN]: { id: 66, start: commonStartTime }, [CHAIN.AURORA]: { id: 1313161554, start: commonStartTime }, [CHAIN.ZORA]: { id: 7777777, start: commonStartTime }, [CHAIN.DUCKCHAIN]: { id: 5545, start: commonStartTime }, [CHAIN.MANTA]: { id: 169, start: commonStartTime }, [CHAIN.PULSECHAIN]: { id: 369, start: commonStartTime }, [CHAIN.EOS_EVM]: { id: 17777, start: commonStartTime }, [CHAIN.THUNDERCORE]: { id: 108, start: commonStartTime }, [CHAIN.ASTAR]: { id: 592, start: commonStartTime }, [CHAIN.METER]: { id: 82, start: commonStartTime }, [CHAIN.SONEIUM]: { id: 1868, start: commonStartTime }, [CHAIN.SHIMMER_EVM]: { id: 148, start: commonStartTime }, [CHAIN.SANKO]: { id: 1996, start: commonStartTime }, [CHAIN.BITLAYER]: { id: 200901, start: commonStartTime }, [CHAIN.ZETA]: { id: 7000, start: commonStartTime }, [CHAIN.RONIN]: { id: 2020, start: commonStartTime }, [CHAIN.BSQUARED]: { id: 223, start: commonStartTime }, [CHAIN.ETHERLINK]: { id: 42793, start: commonStartTime }, [CHAIN.FLARE]: { id: 14, start: commonStartTime }, [CHAIN.INK]: { id: 57073, start: commonStartTime }, [CHAIN.FRAXTAL]: { id: 252, start: commonStartTime }, [CHAIN.IOTAEVM]: { id: 8822, start: commonStartTime }, [CHAIN.STORY]: { id: 1514, start: commonStartTime }, [CHAIN.BOUNCE_BIT]: { id: 6001, start: commonStartTime }, [CHAIN.SWELLCHAIN]: { id: 1923, start: commonStartTime }, [CHAIN.VANA]: { id: 1480, start: commonStartTime }, [CHAIN.CORN]: { id: 21000000, start: commonStartTime }, [CHAIN.FLOW]: { id: 747, start: commonStartTime }, [CHAIN.CONFLUX]: { id: 1030, start: commonStartTime }, [CHAIN.CHILIZ]: { id: 88888, start: commonStartTime }, [CHAIN.OP_BNB]: { id: 204, start: commonStartTime }, [CHAIN.WAN]: { id: 888, start: commonStartTime }, [CHAIN.MERLIN]: { id: 4200, start: commonStartTime }, [CHAIN.LISK]: { id: 1135, start: commonStartTime }, [CHAIN.TARA]: { id: 841, start: commonStartTime }, [CHAIN.DOGECHAIN]: { id: 2000, start: commonStartTime }, [CHAIN.APECHAIN]: { id: 33139, start: commonStartTime }, [CHAIN.RARI]: { id: 1380012617, start: commonStartTime }, [CHAIN.FILECOIN]: { id: 314, start: commonStartTime }, [CHAIN.SUPERPOSITION]: { id: 55244, start: commonStartTime }, [CHAIN.FUSE]: { id: 122, start: commonStartTime }, [CHAIN.MEER]: { id: 813, start: commonStartTime }, [CHAIN.KROMA]: { id: 255, start: commonStartTime }, [CHAIN.MODE]: { id: 34443, start: commonStartTime }, }; const fetch = async (_a: any, _b: any, options: FetchOptions): Promise => { const chainId = chainConfig[options.chain].id; const endpoint = `/api/v1/statistics/${chainId}/${options.dateString}`; const response: IAPIResponse = await fetchURL(`${URL}${endpoint}`); return { dailyVolume: response.dailyVolume }; }; const adapter: SimpleAdapter = { fetch, adapter: chainConfig }; export default adapter; ================================================ FILE: aggregators/obsidian/index.ts ================================================ import { ethers, getAddress, id, zeroPadValue } from "ethers"; import { BaseAdapter, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getTransactions } from "../../helpers/getTxReceipts"; const contracts: Record = { [CHAIN.CRONOS]: [ getAddress("0xeb02A792A9a85c00498A72b13B9aA5c486bC6cA1"), getAddress("0x1189331089b6ca8beA989C1F2fFd0EfAdCd33a69"), getAddress("0x505dC8145B878B3B04c2f6cB3E88716dF27208C2"), ], [CHAIN.CRONOS_ZKEVM]: [ getAddress("0xDb0837D207708F55549a425638de3E2f53Eea141"), getAddress("0x6c40b752be1cAa3695D0e9a2Ef54Cd295c3e89dd"), ], }; const fetch = async ({ createBalances, getLogs, chain }: FetchOptions) => { const routerAddresses = contracts[chain].map((addr) => addr.toLowerCase()); const dailyVolume = createBalances(); const allLogs = await Promise.all( routerAddresses.map((routerAddress) => getLogs({ topics: [ id("Swap(address,uint256,uint256,uint256,uint256,address)"), null as any, zeroPadValue(routerAddress, 32), ], noTarget: true, entireLog: true, }) ) ); const logs = allLogs.flat(); if (!logs.length) return { dailyVolume }; const logsByTx: Record = {}; for (const log of logs) { const txHash = log.transactionHash.toLowerCase(); (logsByTx[txHash] ||= []).push(log); } const txHashes = Object.keys(logsByTx); const txs = await getTransactions(chain, txHashes, { cacheKey: "obsidian-swaps", }); const multicallInterface = new ethers.Interface([ "function multicall(uint256 deadline, bytes[] data)", ]); for (const tx of txs) { if (!tx || !tx.hash) continue; const txHash = tx.hash.toLowerCase(); const input = (tx as any).input; const isMulticall = input?.startsWith("0x5ae401dc"); const isDirectSwap = input?.startsWith("0x2823d42"); if (!isMulticall && !isDirectSwap) continue; let destinationToken: string | undefined; try { const multicallData = isMulticall ? multicallInterface.decodeFunctionData("multicall", input).data : [input]; if (!multicallData.length) continue; for (const callData of multicallData) { try { const selector = callData.slice(0, 10); if (selector === "0xebfd80e2" || selector.startsWith("0x2823d42")) { const params = callData.slice(10); const chunks: string[] = []; for (let i = 0; i < params.length; i += 64) { chunks.push(params.slice(i, i + 64)); } if (chunks.length >= 6) { const tokenOut = "0x" + chunks[4].slice(24); destinationToken = tokenOut; break; } } } catch (innerErr) { continue; } } } catch (err) { console.error(`Error decoding ${txHash}:`, err); continue; } if (!destinationToken) continue; for (const log of logsByTx[txHash]) { try { const data = log.data.slice(2); const chunks: string[] = []; for (let i = 0; i < data.length; i += 64) { chunks.push(data.slice(i, i + 64)); } if (chunks.length >= 4) { const amount0Out = BigInt("0x" + chunks[2]); const amount1Out = BigInt("0x" + chunks[3]); const amountOut = amount0Out > 0n ? amount0Out : amount1Out; if (amountOut > 0n) { dailyVolume.add(destinationToken, amountOut.toString()); } } } catch (logErr) { console.error(`Error decoding log for ${txHash}:`, logErr); continue; } } } return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: Object.keys(contracts).reduce((acc, chain) => { acc[chain] = { fetch, start: "2024-07-25", }; return acc; }, {} as BaseAdapter), }; export default adapter; ================================================ FILE: aggregators/odos/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getDefaultDexTokensBlacklisted } from "../../helpers/lists"; import { formatAddress } from "../../utils/utils"; const event_swap = 'event Swap (address sender, uint256 inputAmount, address inputToken, uint256 amountOut, address outputToken, int256 slippage, uint32 referralCode)'; const event_multiswap = 'event SwapMulti(address sender, uint256[] amountsIn, address[] tokensIn, uint256[] amountsOut, address[] tokensOut, uint32 referralCode)'; const ODOS_ROUTER_V3 = "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05" const event_swap_v3 = 'event Swap (address sender, uint256 inputAmount, address inputToken, uint256 amountOut, address outputToken, int256 slippage, uint64 referralCode, uint64 referralFee, address referralFeeRecipient)'; const event_multiswap_v3 = 'event SwapMulti(address sender, uint256[] amountsIn, address[] tokensIn, uint256[] amountsOut, address[] tokensOut, int256[] slippage, uint64 referralCode, uint64 referralFee, address referralFeeRecipient)'; type TPool = { [c: string]: string[]; } const ODOS_V2_ROUTERS: TPool = { [CHAIN.ETHEREUM]: ['0xCf5540fFFCdC3d510B18bFcA6d2b9987b0772559',], [CHAIN.ARBITRUM]: ['0xa669e7A0d4b3e4Fa48af2dE86BD4CD7126Be4e13',], [CHAIN.OPTIMISM]: ['0xCa423977156BB05b13A2BA3b76Bc5419E2fE9680',], [CHAIN.BASE]: ['0x19cEeAd7105607Cd444F5ad10dd51356436095a1',], [CHAIN.POLYGON]: ['0x4E3288c9ca110bCC82bf38F09A7b425c095d92Bf',], [CHAIN.AVAX]: ['0x88de50B233052e4Fb783d4F6db78Cc34fEa3e9FC',], [CHAIN.BSC]: ['0x89b8AA89FDd0507a99d334CBe3C808fAFC7d850E',], [CHAIN.FANTOM]: ['0xd0c22a5435f4e8e5770c1fafb5374015fc12f7cd',], [CHAIN.ERA]: ['0x4bBa932E9792A2b917D47830C93a9BC79320E4f7',], [CHAIN.MODE]: ['0x7E15EB462cdc67Cf92Af1f7102465a8F8c784874',], [CHAIN.LINEA]: ['0x2d8879046f1559E53eb052E949e9544bCB72f414',], [CHAIN.MANTLE]: ['0xD9F4e85489aDCD0bAF0Cd63b4231c6af58c26745',], [CHAIN.SCROLL]: ['0xbFe03C9E20a9Fc0b37de01A172F207004935E0b1',], [CHAIN.FRAXTAL]: ['0x56c85a254DD12eE8D9C04049a4ab62769Ce98210'], [CHAIN.SONIC]: ['0xaC041Df48dF9791B0654f1Dbbf2CC8450C5f2e9D'], [CHAIN.UNICHAIN]: ['0x6409722F3a1C4486A3b1FE566cBDd5e9D946A1f3'], } async function fetch({ getLogs, createBalances, chain }: FetchOptions) { const routers = ODOS_V2_ROUTERS[chain]; const blacklistedTokens = getDefaultDexTokensBlacklisted(chain) const isBlacklisted = (token: string) => blacklistedTokens.includes(formatAddress(token)) const dailyVolume = createBalances() const dailyFees = createBalances() let logs = (await getLogs({ targets: routers, eventAbi: event_swap, })) .filter(i => !isBlacklisted(i.outputToken) && !isBlacklisted(i.inputToken)) let multiswapLogs = (await getLogs({ targets: routers, eventAbi: event_multiswap, })) .filter(i => !i.tokensIn.some(isBlacklisted) && !i.tokensOut.some(isBlacklisted)) // add volume logs.forEach(i => dailyVolume.add(i.outputToken, i.amountOut)) multiswapLogs.forEach(i => dailyVolume.add(i.tokensOut, i.amountsOut)) // add fees logs.forEach(i => dailyFees.add(i.outputToken, Number(i.slippage) > 0 ? i.slippage : 0)) multiswapLogs.forEach(i => dailyFees.add(i.tokensOut, i.amountsOut.map((a: any) => Number(a) * .01 / 100))) // 0.01% fixed fee let logs_v3 = (await getLogs({ targets: [ODOS_ROUTER_V3], eventAbi: event_swap_v3, })) .filter(i => !isBlacklisted(i.outputToken) && !isBlacklisted(i.inputToken)) let multiswapLogs_v3 = (await getLogs({ targets: [ODOS_ROUTER_V3], eventAbi: event_multiswap_v3, })) .filter(i => !i.tokensIn.some(isBlacklisted) && !i.tokensOut.some(isBlacklisted)) // add v3 volume logs_v3.forEach(i => dailyVolume.add(i.outputToken, i.amountOut)) multiswapLogs_v3.forEach(i => dailyVolume.add(i.tokensOut, i.amountsOut)) // add V3 Odos fees function addV3Fees(entry: any) { // FE fees will use referral code 1 and keep the funds in the router as revenue const isFrontendFee = Number(entry.referralCode) == 1 && entry.referralFeeRecipient == ODOS_ROUTER_V3 // Single-output case if (entry.outputToken) { const slippageFee = Number(entry.slippage) > 0 ? Number(entry.slippage) : 0 const frontendFee = isFrontendFee ? Number(entry.referralFee) * Number(entry.amountOut) / 1e18 : 0 dailyFees.add(entry.outputToken, slippageFee + frontendFee) } // Multi-output case if (entry.tokensOut && entry.amountsOut) { entry.tokensOut.forEach((token: string, idx: number) => { const tokenSlippage = Number(entry.slippage[idx]) const slippageFee = tokenSlippage > 0 ? tokenSlippage : 0 const frontendFee = isFrontendFee ? Number(entry.referralFee) * Number(entry.amountsOut[idx]) / 1e18 : 0 dailyFees.add(token, slippageFee + frontendFee) }) } } logs_v3.forEach(addV3Fees) multiswapLogs_v3.forEach(addV3Fees) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, dailyHoldersRevenue: 0, dailySupplySideRevenue: 0, }; } const start = '2023-07-14' const adapter: SimpleAdapter = { version: 2, pullHourly: true, methodology: { Fees: "All fees paid by users for using Odos services.", UserFees: "All fees paid by users for using Odos services.", Revenue: "Revenue is equal to the fees collected.", HoldersRevenue: "No revenue distributed to ODOS holders.", SupplySideRevenue: "No revenue distributed to supply side.", ProtocolRevenue: "Revenue is equal to the fees collected.", }, fetch, start, chains: Object.keys(ODOS_V2_ROUTERS), }; export default adapter; /* Fees adapter for odos.xyz > what? swaps (trading) generate fees, taken in the bought token. > how? - swaps - single-swap - Calculate directly from the positive `slippage` param in the Swap event as raw `outputToken` amount. - multi-swap - delta (increase) of held balances of `tokensOut` in the router. - referral comissions - flat 20% of referral's fee tier. each referral code has its own fee tier. a delta comparision would cover all of the above as all kinds of fees are held inside the router. but make sure to only consider txns excluding the `transferRouterFunds` function calls > which? - for now, we include only v2 - of that, we include only single swaps > pls help! To do: - add v1 fees, - add multi-swap fees, - add fee from referrals > notes? - v2 started at 1699121600 (2023-jul-13) */ ================================================ FILE: aggregators/okx/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; import { getEnv } from "../../helpers/env"; import axios from "axios"; import { createHmac } from "crypto"; import { getTimestampAtStartOfDayUTC } from "../../utils/date"; import { sleep } from "../../utils/utils"; const plimit = require('p-limit'); const limits = plimit(1); type TChain = { [key: string]: number; }; const CHAINS: TChain = { // evm [CHAIN.ETHEREUM]: 1, [CHAIN.SONIC]: 146, [CHAIN.ERA]: 324, [CHAIN.OPTIMISM]: 10, [CHAIN.BSC]: 56, [CHAIN.POLYGON]: 137, [CHAIN.AVAX]: 43114, [CHAIN.ARBITRUM]: 42161, [CHAIN.LINEA]: 59144, [CHAIN.BASE]: 8453, [CHAIN.MANTLE]: 5000, [CHAIN.BLAST]: 81457, [CHAIN.UNICHAIN]: 130, [CHAIN.PLASMA]: 9745, [CHAIN.METIS]: 1088, // using OKX API [CHAIN.FANTOM]: 250, [CHAIN.CRONOS]: 25, [CHAIN.CONFLUX]: 1030, [CHAIN.POLYGON_ZKEVM]: 1101, [CHAIN.SEI]: 70000029, [CHAIN.SCROLL]: 534352, [CHAIN.XLAYER]: 196, [CHAIN.MANTA]: 169, [CHAIN.ZETA]: 7000, [CHAIN.MERLIN]: 4200, [CHAIN.MODE]: 34443, [CHAIN.TON]: 607, [CHAIN.STARKNET]: 9004, [CHAIN.STACKS]: 5757, [CHAIN.SUI]: 784, [CHAIN.APTOS]: 637, [CHAIN.SOLANA]: 501, [CHAIN.OSMOSIS]: 706, [CHAIN.TRON]: 195, // [CHAIN.OKEXCHAIN]: 66, // [CHAIN.FLARE]: 14, // broken // [CHAIN.BITCOIN]: 0, // broken }; interface ISwapRouter { addresses: Array; } const SwapRouters: Record = { // [CHAIN.ETHEREUM]: { // addresses: [ // '0x2E1Dee213BA8d7af0934C49a23187BabEACa8764', // ], // }, // [CHAIN.SONIC]: { // addresses: [ // '0x8feB9E84b7E9DC86adc6cD6Eb554C5B4355c8405', // ], // }, // [CHAIN.ERA]: { // addresses: [ // '0x010BC6B1014E5ed8284ab0667b116AAb99588159', // ], // }, // [CHAIN.OPTIMISM]: { // addresses: [ // '0x86F752f1F662f39BFbcBeF95EE56B6C20d178969', // ], // }, // [CHAIN.POLYGON]: { // addresses: [ // '0xF5402CCC5fC3181B45D7571512999D3Eea0257B6', // ], // }, // [CHAIN.BSC]: { // addresses: [ // '0x6015126d7D23648C2e4466693b8DeaB005ffaba8', // ], // }, // [CHAIN.AVAX]: { // addresses: [ // '0x79f7C6C6dc16Ed3154E85A8ef9c1Ef31CEFaEB19', // ], // }, // [CHAIN.ARBITRUM]: { // addresses: [ // '0x5e2F47bD7D4B357fCfd0Bb224Eb665773B1B9801', // ], // }, // [CHAIN.LINEA]: { // addresses: [ // '0x6f7c20464258c732577c87a9B467619e03e5C158', // ], // }, // [CHAIN.BASE]: { // addresses: [ // '0x5e2F47bD7D4B357fCfd0Bb224Eb665773B1B9801', // ], // }, // [CHAIN.MANTLE]: { // addresses: [ // '0x69C236E021F5775B0D0328ded5EaC708E3B869DF', // ], // }, // [CHAIN.BLAST]: { // addresses: [ // '0x69C236E021F5775B0D0328ded5EaC708E3B869DF', // ], // }, // [CHAIN.UNICHAIN]: { // addresses: [ // '0x411d2C093e4c2e69Bf0D8E94be1bF13DaDD879c6', // ], // }, // [CHAIN.PLASMA]: { // addresses: [ // '0xd30D8CA2E7715eE6804a287eB86FAfC0839b1380', // ], // }, // [CHAIN.METIS]: { // addresses: [ // '0xcF76984119C7f6ae56fAfE680d39C08278b7eCF4', // ], // }, } async function queryOkxApi(timestamp:string, path:string){ const [secretKey, passphrase] = getEnv("OKX_API_KEY").split(":") const data = await axios.get(`https://www.okx.com${path}`, { headers: { 'OK-ACCESS-PROJECT': 'be0ee327bbc230c3977c6868a77cd894', 'OK-ACCESS-KEY': 'feb1a319-69e0-4c00-96df-d1188d8a616a', 'OK-ACCESS-SIGN': createHmac('sha256', secretKey) .update(timestamp + 'GET' + path) .digest('base64'), 'OK-ACCESS-PASSPHRASE': passphrase, 'OK-ACCESS-TIMESTAMP': timestamp } }); await sleep(200) return data } const fetch = async (_a: number, _b: any, options: FetchOptions) => { if (SwapRouters[options.chain]) { const dailyVolume = options.createBalances() const swapLogs = await options.getLogs({ targets: SwapRouters[options.chain].addresses, eventAbi: 'event OrderRecord(address fromToken, address toToken, address sender, uint256 fromAmount, uint256 returnAmount)', flatten: true, }) for (const log of swapLogs) { dailyVolume.add(log.fromToken, log.fromAmount); } return { dailyVolume } } else { // using API const timestamp = new Date().toISOString() const startOfDay = getTimestampAtStartOfDayUTC(options.startOfDay) const path = `/api/v5/dex/aggregator/volume?timestamp=${startOfDay* 1e3}&chainId=${CHAINS[options.chain]}` const data = await limits(() => queryOkxApi(timestamp, path)) return { dailyVolume: data.data.data.volumeUsdLast24hour, }; } }; const adapter: any = { version: 1, // api supports other timestamps but if you try using current timestamps, it breaks, so sticking to v1 even though it should be able to support v2 adapter: Object.keys(CHAINS).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: fetch, start: '2022-05-17', }, }; }, {}), }; export default adapter; ================================================ FILE: aggregators/oogabooga/index.ts ================================================ import type { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const swapEvent = "event Swap(address indexed sender,uint256 inputAmount,address indexed inputToken,uint256 amountOut,address indexed outputToken,int256 slippage,uint32 referralCode,address to)"; const quoteEvent = "event Fee(address feeToken, uint256 feeAmount, uint256 obQuote, uint256 bexQuote, uint256 kodiakQuote)"; const OBEXECUTOR_FEE_MODULE: Record = { [CHAIN.BERACHAIN]: [ "0xF83ECD5511cf190764Be32D2F9eCeD57a8676cdc", "0xCE33Ec5E1BA85EB9485dDB2DF3610186cA3b6a35", ], [CHAIN.HYPERLIQUID]: ["0x53A8EC5a42106FC8B2AB1468c3DA363F1bA49266"], [CHAIN.MONAD]: ["0x8577D77C67A77E5C55592Ede1fa117306E7C0757"], [CHAIN.BOTANIX]: ["0xdF90E29d435E492f26CAc53a52fc4cDe6327E63E"], }; const OBROUTER: Record = { [CHAIN.BERACHAIN]: "0xFd88aD4849BA0F729D6fF4bC27Ff948Ab1Ac3dE7", [CHAIN.HYPERLIQUID]: "0x5fbD1B5AA82d09359C05428647871fe9aDd3F411", [CHAIN.MONAD]: "0x5fbD1B5AA82d09359C05428647871fe9aDd3F411", [CHAIN.BOTANIX]: "0x417fBC387fa853AEd674d62Ca1b21E3cE54C0F85", }; const fetch = async ({ getLogs, createBalances, chain }: FetchOptions) => { const dailyVolume = createBalances(); const dailyFees = createBalances(); const swapEvents = await getLogs({ targets: [OBROUTER[chain]], eventAbi: swapEvent, }); for (const l of swapEvents) { dailyVolume.add(l.outputToken, l.amountOut); } // Positive slippage for (const l of swapEvents) { if (l.slippage > 0n) { dailyFees.add(l.outputToken, l.slippage); } } // Swap fees const feeEvents = await getLogs({ targets: OBEXECUTOR_FEE_MODULE[chain], eventAbi: quoteEvent, }); for (const l of feeEvents) { if (l.feeAmount > 0n) { dailyFees.add(l.feeToken, l.feeAmount); } } return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const methodology = { Fees: "All trading fees paid by users.", UserFees: "All trading fees paid by users.", Revenue: "100% fees collected by the protocol.", ProtocolRevenue: "100% fees collected by the protocol.", }; export default { version: 2, pullHourly: true, methodology, adapter: { [CHAIN.BERACHAIN]: { fetch, start: "2025-01-27" }, [CHAIN.HYPERLIQUID]: { fetch, start: "2025-08-01" }, [CHAIN.MONAD]: { fetch, start: "2025-11-24" }, [CHAIN.BOTANIX]: { fetch, start: "2025-10-16" }, }, }; ================================================ FILE: aggregators/ooia/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const url = "https://apiprod662ba0315.ooia.art/api/v1/collections/defillama/analytics/volumes"; const currency = "USDT"; interface IAPIResponse { dailyVolume: string; } const fromMicro = (value: string) => { return (parseFloat(value) / 1e6).toString(); }; const fetch = async (_a: any, _b: any, { startOfDay }: FetchOptions) => { const { dailyVolume }: IAPIResponse = await fetchURL( `${url}?timestamp=${startOfDay}¤cy=${currency}` ); return { dailyVolume: fromMicro(dailyVolume), }; }; const adapters: SimpleAdapter = { version: 1, adapter: { [CHAIN.TON]: { fetch, start: "2024-11-01", }, }, }; export default adapters; ================================================ FILE: aggregators/openocean/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import fetchURL from "../../utils/fetchURL"; const URL = "https://open-api.openocean.finance/v3"; const CHAINS: Record = { [CHAIN.ETHEREUM]: "2022-01-01", [CHAIN.BSC]: "2022-01-01", [CHAIN.POLYGON]: "2022-01-01", [CHAIN.AVAX]: "2022-01-01", [CHAIN.FANTOM]: "2022-01-01", [CHAIN.ARBITRUM]: "2022-01-01", [CHAIN.OPTIMISM]: "2022-01-01", [CHAIN.ERA]: "2022-01-01", [CHAIN.BASE]: "2022-01-01", [CHAIN.OP_BNB]: "2022-01-01", [CHAIN.LINEA]: "2022-01-01", [CHAIN.MANTLE]: "2022-01-01", [CHAIN.MANTA]: "2022-01-01", [CHAIN.TELOS]: "2022-01-01", [CHAIN.SCROLL]: "2022-01-01", [CHAIN.XDAI]: "2022-01-01", [CHAIN.CRONOS]: "2022-01-01", [CHAIN.HARMONY]: "2022-01-01", [CHAIN.BLAST]: "2022-01-01", [CHAIN.MODE]: "2022-01-01", // [CHAIN.ROOTSTOCK]: "2022-01-01", // [CHAIN.SEI]: "2022-01-01", [CHAIN.GRAVITY]: "2022-01-01", [CHAIN.KAVA]: "2022-01-01", [CHAIN.METIS]: "2022-01-01", [CHAIN.CELO]: "2022-01-01", [CHAIN.POLYGON_ZKEVM]: "2022-01-01", [CHAIN.MOONRIVER]: "2022-01-01", [CHAIN.AURORA]: "2022-01-01", [CHAIN.APECHAIN]: "2022-01-01", [CHAIN.SONIC]: "2022-01-01", [CHAIN.BERACHAIN]: "2022-01-01", [CHAIN.UNICHAIN]: "2022-01-01", [CHAIN.FLARE]: "2022-01-01", [CHAIN.SWELLCHAIN]: "2022-01-01", [CHAIN.HYPERLIQUID]: "2022-01-01", [CHAIN.MONAD]: "2025-05-17", [CHAIN.SOLANA]: "2025-05-17", [CHAIN.APTOS]: "2025-05-17", [CHAIN.SUI]: "2025-05-17", [CHAIN.NEAR]: "2025-05-17", [CHAIN.STARKNET]: "2025-05-17", }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const { data } = await fetchURL(`${URL}/${options.chain}/getDailyVolume?timestamp=${options.startOfDay}`); const { dailyVolume } = data || { dailyVolume: 0 }; return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 1, adapter: { ...Object.entries(CHAINS).reduce((acc, [chain, _]) => { return { ...acc, [chain]: { fetch, start: CHAINS[chain], }, }; }, {}) } }; export default adapter; ================================================ FILE: aggregators/opensea/index.ts ================================================ import { Dependencies, FetchOptions } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; import { CHAIN } from "../../helpers/chains"; import { SimpleAdapter } from "../../adapters/types"; import { getSolanaReceived } from "../../helpers/token"; const chainConfig: any = { [CHAIN.ETHEREUM]: { dune_chain: 'ethereum' }, // [CHAIN.ABSTRACT]: {dune_chain: 'abstract'}, [CHAIN.APECHAIN]: { dune_chain: 'apechain' }, [CHAIN.ARBITRUM]: { dune_chain: 'arbitrum' }, [CHAIN.AVAX]: { dune_chain: 'avalanche_c' }, [CHAIN.BLAST]: { dune_chain: 'blast' }, [CHAIN.BASE]: { dune_chain: 'base' }, [CHAIN.BERACHAIN]: { dune_chain: 'berachain' }, // [CHAIN.FLOW]: {dune_chain: 'flow'}, [CHAIN.OPTIMISM]: { dune_chain: 'optimism' }, [CHAIN.POLYGON]: { dune_chain: 'polygon' }, // [CHAIN.SEI]: {dune_chain: 'sei'}, [CHAIN.UNICHAIN]: { dune_chain: 'unichain' }, // [CHAIN.ZORA]: {dune_chain: 'zora'}, [CHAIN.SOLANA]: { dune_chain: 'solana' }, [CHAIN.MONAD]: { dune_chain: 'monad' }, } const prefetch = async (options: FetchOptions) => { return await queryDuneSql(options, ` SELECT blockchain, SUM(amount_usd) as dailyVolume FROM dex_aggregator.trades WHERE tx_hash IN ( SELECT DISTINCT hash FROM evms.transactions WHERE block_time >= FROM_UNIXTIME(${options.startTimestamp}) AND block_time <= FROM_UNIXTIME(${options.endTimestamp}) AND varbinary_substring(data, varbinary_length(data) - 3, 4) = from_hex('865d8597') ) GROUP BY 1 `); }; const fetchSolana = async (options: FetchOptions) => { const dailyFees = await getSolanaReceived({ options, target: 'FEwxLZ64Wdh1VFP53jfA37yDVnD8gL3FgzsZNuQ6pCC9', }) const dailyVolume = dailyFees.clone(100 / 0.85) return { dailyVolume, } } const fetch = async (_a: any, _b: any, options: FetchOptions) => { if (options.chain === CHAIN.SOLANA) { return await fetchSolana(options) } const results = options.preFetchedResults || []; const chainData = results.find( (item: any) => chainConfig[options.chain].dune_chain === item.blockchain ); return { dailyVolume: chainData?.dailyVolume || 0, } } const adapter: SimpleAdapter = { version: 1, fetch, chains: Object.keys(chainConfig), prefetch, dependencies: [Dependencies.DUNE, Dependencies.ALLIUM], doublecounted: true } export default adapter; ================================================ FILE: aggregators/opt-agg/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = "https://api.opt.finance/stat/vol"; const fetch = async (timestamp: number): Promise => { const dailyVolume = (await fetchURL(URL)).data.total_24h; return { dailyVolume, timestamp, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.WEMIX]: { fetch, start: '2024-01-12', runAtCurrTime: true }, }, deadFrom: "2026-01-23" }; export default adapter; ================================================ FILE: aggregators/orbiter-finance/index.ts ================================================ import type { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const DEFAULT_AGGREGATOR = '0xe530d28960d48708ccf3e62aa7b42a80bc427aef' const SWAP_ROUTER: Record = { [CHAIN.UNICHAIN]: '0x70f6060fc8b01b56869feba8361df468f98c2900', } const swapEvent = "event SwapExecuted(address indexed sender, address indexed recipient, address inputToken, address outputToken, uint256 inputAmount, uint256 outputAmount, bytes extData)"; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const target = SWAP_ROUTER[options.chain] || DEFAULT_AGGREGATOR; const logs = await options.getLogs({ target, eventAbi: swapEvent, }); for (const l of logs) { dailyVolume.add(l.inputToken, l.inputAmount); } return { dailyVolume }; } const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, chains: [CHAIN.ETHEREUM, CHAIN.ARBITRUM, CHAIN.POLYGON, CHAIN.OPTIMISM, CHAIN.BSC, CHAIN.BASE, CHAIN.SCROLL, CHAIN.LINEA, CHAIN.UNICHAIN, CHAIN.BERACHAIN, CHAIN.SONIC, CHAIN.INK, CHAIN.BLAST, CHAIN.HEMI, CHAIN.POLYGON_ZKEVM, CHAIN.SCROLL, CHAIN.MANTLE, CHAIN.MODE, CHAIN.FRAXTAL, CHAIN.FUSE, CHAIN.GRAVITY, CHAIN.WC, CHAIN.SONEIUM, CHAIN.CELO] }; export default adapter; ================================================ FILE: aggregators/paraswap/index.ts ================================================ import { FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getTimestampAtStartOfDayUTC } from "../../utils/date"; import { httpGet } from "../../utils/fetchURL"; import { FetchOptions } from "../../adapters/types"; import { sleep } from "../../utils/utils"; interface IResponse { daily: any[]; allTime: any; } const feesMMURL = "https://api.paraswap.io/stk/volume-stats/breakdown-by-chain"; const mapChainId: Record = { [CHAIN.ETHEREUM]: '1', [CHAIN.OPTIMISM]: '10', [CHAIN.BSC]: '56', [CHAIN.POLYGON]: '137', [CHAIN.FANTOM]: '250', [CHAIN.POLYGON_ZKEVM]: '1101', [CHAIN.BASE]: '8453', [CHAIN.ARBITRUM]: '42161', [CHAIN.AVAX]: '43114', } const prefetch = async (_: any) => { const headers: any = { "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "accept-language": "en-US,en;q=0.9", "cache-control": "max-age=0", "priority": "u=0, i", "upgrade-insecure-requests": "1", "referrerPolicy": "strict-origin-when-cross-origin", }; // sometime paraswap api return unknown 500 error // need to retry if it failed for (let i = 0; i < 5; i++) { try { return await httpGet(feesMMURL, { headers }); } catch(e: any) { if (i === 4) { throw e; } } await sleep(5000); // sleep 5 secs for next try } } const fetch = async (timestamp: number, _: any, options: FetchOptions): Promise => { const chain = options.chain; if (chain == CHAIN.FANTOM && timestamp > 1744416000) return {} as FetchResult; // fantom delisted at 2025-04-12 const timestampToday = getTimestampAtStartOfDayUTC(timestamp) const response: IResponse = options.preFetchedResults || []; const dailyResultFees: any[] = response.daily; const [dailyVolume, partnerRev, protocolRev]: number[] = dailyResultFees.filter(([time]: any) => time === timestampToday) .map(([_, data]: any) => data[mapChainId[chain]]).flat() const dailyFees = options.createBalances(); const dailyRevenue = options.createBalances(); const dailySupplySideRevenue = options.createBalances(); const dailyProtocolRevenue = options.createBalances(); const dailyHoldersRevenue = options.createBalances(); dailyFees.addUSDValue((partnerRev || 0) + (protocolRev || 0), 'Token Swap Fees'); dailySupplySideRevenue.addUSDValue(partnerRev || 0, 'Fees To Partners'); const revenue = protocolRev || 0; const revenueToVelora = revenue * 0.85; const revenueToDAO = revenue * 0.15 * 0.8; const revenueToStakers = revenue * 0.15 * 0.2; dailyRevenue.addUSDValue(revenueToVelora, 'Fees To Velora Foundation'); dailyRevenue.addUSDValue(revenueToDAO, 'Fees To Velora DAO'); dailyRevenue.addUSDValue(revenueToStakers, 'Fees To Velora Token Stakers'); dailyProtocolRevenue.addUSDValue(revenueToVelora, 'Fees To Velora Foundation'); dailyProtocolRevenue.addUSDValue(revenueToDAO, 'Fees To Velora DAO'); dailyHoldersRevenue.addUSDValue(revenueToStakers, 'Fees To Velora Token Stakers'); return { dailyVolume: dailyVolume || 0, dailyFees, dailyUserFees: dailyFees, dailyRevenue, dailyProtocolRevenue, dailyHoldersRevenue, } } const adapter: SimpleAdapter = { version: 1, start: '2022-03-22', chains: Object.keys(mapChainId), fetch, prefetch, methodology: { Fees: "All trading fees paid by users", UserFees: "All trading fees paid by users", Revenue: "Share of 80% trading fees to Velora, DAO, and token stakers.", ProtocolRevenue: "Trading fees shared to Velora and DAO.", HoldersRevenue: "Trading fees to stakers as part of PSP 2.0 staking rewards.", }, breakdownMethodology: { Fees: { 'Token Swap Fees': 'Users pay flat fee 0.15% while trading using Velora.', }, Revenue: { 'Fees To Velora Foundation': 'Share of 85% swap fees to Velora Foudation.', 'Fees To Velora DAO': 'Share of 80% from 15% total swap fees to Velora DAO.', 'Fees To Velora Token Stakers': 'Share of 20% from 15% total swap fees to Velora Token Stakers.', }, ProtocolRevenue: { 'Fees To Velora Foundation': 'Share of 85% swap fees to Velora Foudation.', 'Fees To Velora DAO': 'Share of 80% from 15% total swap fees to Velora DAO.', }, HoldersRevenue: { 'Fees To Velora Token Stakers': 'Share of 20% from 15% total swap fees to Velora Token Stakers.', }, SupplySideRevenue: { 'Fees To Partners': 'Fees paid to partnerships and integrators with Velora.', }, } } export default adapter; ================================================ FILE: aggregators/rainbow-swap/index.ts ================================================ import { Fetch, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const url = 'https://api.rainbow.ag/analytics/volumes'; interface IAPIResponse { dailyVolume: string; } const fetch: Fetch = async (timestamp: number) => { const { dailyVolume }: IAPIResponse = await fetchURL(`${url}?timestamp=${timestamp * 1000}`); return { dailyVolume, }; }; const adapters: SimpleAdapter = { version: 1, adapter: { [CHAIN.TON]: { fetch, start: '2024-07-11', } } } export default adapters ================================================ FILE: aggregators/rango/index.ts ================================================ import { Adapter, FetchOptions } from '../../adapters/types'; import { httpGet } from '../../utils/fetchURL'; import { CHAIN } from '../../helpers/chains'; type ChainInfo = { code: string; start: string }; const DEFAULT_START = '2021-08-01' const RangoChains: Record = { [CHAIN.ETHEREUM]: { code: 'ETH', start: '2021-08-01' }, [CHAIN.SOLANA]: { code: 'SOLANA', start: '2022-04-01' }, [CHAIN.BSC]: { code: 'BSC', start: '2021-08-01' }, [CHAIN.SCROLL]: { code: 'SCROLL', start: '2024-01-01' }, [CHAIN.BASE]: { code: 'BASE', start: '2023-11-01' }, [CHAIN.BITCOIN]: { code: 'BTC', start: '2021-09-01' }, [CHAIN.ARBITRUM]: { code: 'ARBITRUM', start: '2022-01-01' }, [CHAIN.POLYGON]: { code: 'POLYGON', start: '2021-08-01' }, [CHAIN.OPTIMISM]: { code: 'OPTIMISM', start: '2022-04-01' }, [CHAIN.LINEA]: { code: 'LINEA', start: '2023-07-01' }, [CHAIN.CELO]: { code: 'CELO', start: '2024-04-01' }, [CHAIN.AVAX]: { code: 'AVAX_CCHAIN', start: '2021-09-01' }, [CHAIN.ERA]: { code: 'ZKSYNC', start: '2023-04-01' }, [CHAIN.MODE]: { code: 'MODE', start: '2024-06-01' }, [CHAIN.TRON]: { code: 'TRON', start: '2023-02-01' }, [CHAIN.ZORA]: { code: 'ZORA', start: '2024-12-01' }, [CHAIN.BLAST]: { code: 'BLAST', start: '2024-04-01' }, [CHAIN.OSMOSIS]: { code: 'OSMOSIS', start: '2021-08-01' }, [CHAIN.COSMOS]: { code: 'COSMOS', start: '2021-08-01' }, [CHAIN.FANTOM]: { code: 'FANTOM', start: '2021-11-01' }, [CHAIN.MOONRIVER]: { code: 'MOONRIVER', start: '2022-05-01' }, [CHAIN.TAIKO]: { code: 'TAIKO', start: '2024-12-01' }, [CHAIN.STARKNET]: { code: 'STARKNET', start: '2023-02-01' }, [CHAIN.POLYGON_ZKEVM]: { code: 'POLYGONZK', start: '2023-06-01' }, [CHAIN.SUI]: { code: 'SUI', start: '2025-04-01' }, [CHAIN.CRONOS]: { code: 'CRONOS', start: '2022-05-01' }, [CHAIN.NOBLE]: { code: 'NOBLE', start: '2023-09-01' }, [CHAIN.BOBA]: { code: 'BOBA', start: '2022-06-01' }, [CHAIN.THORCHAIN]: { code: 'THOR', start: '2021-08-01' }, [CHAIN.FUSE]: { code: 'FUSE', start: '2022-04-01' }, [CHAIN.XDAI]: { code: 'GNOSIS', start: '2022-06-01' }, [CHAIN.HARMONY]: { code: 'HARMONY', start: '2021-09-01' }, [CHAIN.MOONBEAM]: { code: 'MOONBEAM', start: '2022-06-01' }, [CHAIN.TERRA]: { code: 'TERRA', start: '2021-08-01' }, [CHAIN.SONIC]: { code: 'SONIC', start: '2025-04-01' }, [CHAIN.TON]: { code: 'TON', start: '2024-11-01' }, [CHAIN.BERACHAIN]: { code: 'BERACHAIN', start: '2025-04-01' }, [CHAIN.AURORA]: { code: 'AURORA', start: '2022-08-01' }, [CHAIN.RIPPLE]: { code: 'XRPL', start: '2025-09-01' }, [CHAIN.HYPERLIQUID]: { code: 'HYPERLIQUID', start: '2025-10-01' }, [CHAIN.MONAD]: { code: 'MONAD', start: '2025-11-01' }, [CHAIN.UNICHAIN]: { code: 'UNICHAIN', start: '2025-08-01' }, [CHAIN.SONEIUM]: { code: 'SONEIUM', start: '2025-09-01' }, [CHAIN.KATANA]: { code: 'KATANA', start: '2025-11-01' }, [CHAIN.PLASMA]: { code: 'PLASMA', start: '2025-12-01' } }; const fetch: any = async (timestamp: number, _: any, options: FetchOptions) => { const prefetchData = options.preFetchedResults as Record; const chainInfo = RangoChains[options.chain]; const statsForChain = prefetchData[chainInfo.code] || []; const date = new Date(timestamp * 1000).toISOString().split('T')[0]; const statEntry = statsForChain.find(item => { const itemDate = item.date.split('T')[0]; return itemDate === date; }); return { dailyVolume: Number(statEntry?.volume || 0) } } const prefetch = async (_: FetchOptions) => { const API_KEY = '4a624ab5-16ff-4f96-90b7-ab00ddfc342c' const BREAKDOWN = 'SOURCE' const fromTs = new Date(`${DEFAULT_START}T00:00:00Z`).getTime(); const url = `https://api.rango.exchange/scanner/summary/daily` + `?from=${fromTs}` + `&to=${Date.now()}` + `&breakDownBy=${BREAKDOWN}` + `&apiKey=${API_KEY}` + `&txType=DEX`; const response = await httpGet(url); const resultsByChain: Record = {}; for (const stat of response.stats) { const bucket = stat.bucket; if (!resultsByChain[bucket]) { resultsByChain[bucket] = []; } resultsByChain[bucket].push(stat); } return resultsByChain; } const adapter: Adapter = { adapter: Object.fromEntries( Object.keys(RangoChains).map(chain => { const start = RangoChains[chain].start || DEFAULT_START; return [ chain, { fetch, start } ]; }) ), prefetch: prefetch, }; export default adapter; ================================================ FILE: aggregators/rheon/index.ts ================================================ import type { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const AGGREGATOR = "0x311D2A611C59F11516256e14683fB6d9Bc3A97a4"; const swapEvent = "event SwapExecuted(address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, address indexed recipient)"; const fetch = async ({ getLogs, createBalances }: FetchOptions) => { const dailyVolume = createBalances(); const logs = await getLogs({ target: AGGREGATOR, eventAbi: swapEvent, }); for (const log of logs) { dailyVolume.add(log.tokenIn, log.amountIn); } return { dailyVolume }; }; export default { version: 2, pullHourly: true, fetch, chains: [CHAIN.AVAX], start: "2026-04-13", }; ================================================ FILE: aggregators/rubic/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const chains: Record = { [CHAIN.SOLANA]: 'solana', [CHAIN.ETHEREUM]: 'ethereum', [CHAIN.BSC]: 'binance-smart-chain', [CHAIN.AVAX]: 'avalanche', [CHAIN.POLYGON]: 'polygon', [CHAIN.ARBITRUM]: 'arbitrum', [CHAIN.ZKSYNC]: 'zksync', [CHAIN.BLAST]: 'blast', [CHAIN.LINEA]: 'linea', [CHAIN.SCROLL]: 'scroll', [CHAIN.ZETA]: 'zetachain', [CHAIN.MANTLE]: 'mantle', [CHAIN.MANTA]: 'manta-pacific', [CHAIN.POLYGON_ZKEVM]: 'polygon-zkevm', [CHAIN.PULSECHAIN]: 'pulsechain', [CHAIN.BASE]: 'base', [CHAIN.FANTOM]: 'fantom', [CHAIN.BOBA]: 'boba', [CHAIN.TELOS]: 'telos-evm', [CHAIN.KAVA]: 'kava', [CHAIN.OPTIMISM]: 'optimistic-ethereum', [CHAIN.AURORA]: 'aurora', [CHAIN.METIS]: 'metis', [CHAIN.MOONRIVER]: 'moonriver', [CHAIN.TRON]: 'tron', [CHAIN.MOONBEAM]: 'moonbeam', [CHAIN.FUSE]: 'fuse', [CHAIN.CELO]: 'celo', // [CHAIN.OKEXCHAIN]: 'oke-x-chain', [CHAIN.CRONOS]: 'cronos', [CHAIN.MODE]: 'mode', [CHAIN.MERLIN]: 'merlin', [CHAIN.CORE]: 'core', [CHAIN.TAIKO]: 'taiko', [CHAIN.ZKLINK]: 'zklink', [CHAIN.BITLAYER]: 'bitlayer', [CHAIN.BERACHAIN]: 'berachain', [CHAIN.TON]: 'ton', [CHAIN.SUI]: 'sui', [CHAIN.UNICHAIN]: 'unichain', [CHAIN.MORPH]: 'morph', [CHAIN.FRAXTAL]: 'fraxtal', [CHAIN.SONIC]: 'sonic', [CHAIN.SONEIUM]: 'soneium', [CHAIN.GRAVITY]: 'gravity', [CHAIN.ROOTSTOCK]: 'rootstock', // [CHAIN.KROMA]: 'kroma', [CHAIN.XLAYER]: 'xlayer', [CHAIN.SEI]: 'sei', // [CHAIN.EON]: 'horizen-eon', // chain is dead [CHAIN.BAHAMUT]: 'bahamut', [CHAIN.KLAYTN]: 'klaytn', // [CHAIN.ASTAR_ZKEVM]: 'astar-evm', [CHAIN.VELAS]: 'velas', [CHAIN.SYSCOIN]: 'syscoin', // [CHAIN.BOBA_BNB]: 'boba-bsc', [CHAIN.FLARE]: 'flare', [CHAIN.HEMI]: 'hemi', [CHAIN.MONAD]: 'monad', [CHAIN.MEGAETH]: 'megaeth', [CHAIN.PLASMA]: 'plasma', [CHAIN.HYPERLIQUID]: 'hyper-evm', }; interface ApiResponse { daily_volume_in_usd: string; daily_transaction_count: string; total_volume_in_usd: string; total_transaction_count: string; } async function sleep(time: number) { return new Promise((resolve) => setTimeout(resolve, time * 1000)) } const fetch = async (_a: any, _b: any, options: FetchOptions): Promise => { await sleep(Math.floor(Math.random() * 5) + 1) const data: ApiResponse = await fetchURL(`https://api.rubic.exchange/api/stats/defilama_onchain?date=${options.startTimestamp}&network=${chains[options.chain]}`); return { dailyVolume: data?.daily_volume_in_usd || '0', }; }; const adapter: SimpleAdapter = { version: 1, adapter: { ...Object.entries(chains).reduce((acc, [key]) => { return { ...acc, [key]: { fetch, start: '2023-01-01', }, }; }, {}), }, }; export default adapter; ================================================ FILE: aggregators/scallop/index.ts ================================================ import fetchURL from '../../utils/fetchURL'; import { FetchV2, SimpleAdapter } from '../../adapters/types'; import { CHAIN } from '../../helpers/chains'; const fetch: FetchV2 = async ({ startTimestamp, endTimestamp }) => { const dailyVolume = await fetchURL( `https://sui.apis.scallop.io/statistic/swap/daily-volume?fromTimestamp=${startTimestamp}&toTimestamp=${endTimestamp}`, ); return { dailyVolume: dailyVolume.swapVolume }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.SUI]: { fetch, start: '2024-08-05', }, }, }; export default adapter; ================================================ FILE: aggregators/stackit/index.ts ================================================ import { FetchOptions, FetchResultV2, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const CONTRACT = "0xE31eE34E37752d90dF52E251069352ba67284807"; const DEPLOY_BLOCK = 455464291; const sipCreatedAbi = "event SIPCreated(address indexed user, uint256 planIndex, uint256 planId, uint256 amount, uint256 frequency, address stablecoin, address targetToken)"; const basketCreatedAbi = "event BasketSIPCreated(address indexed user, uint256 planIndex, uint256 planId, uint256 amount, uint256 frequency, address stablecoin, uint256 basketSize)"; const investmentExecutedAbi = "event InvestmentExecuted(address indexed user, uint256 planIndex, uint256 planId, uint256 amountIn, uint256 amountOut, uint256 feeAmount)"; const basketInvestmentExecutedAbi = "event BasketInvestmentExecuted(address indexed user, uint256 planIndex, uint256 planId, uint256 amountIn, uint256 feeAmount)"; const fetch = async (options: FetchOptions): Promise => { const { getLogs, createBalances, getToBlock } = options; const toBlock = await getToBlock() // Fetch ALL creation events from deploy to end of current slice so plans // created in earlier hours are always in the map. const [createdLogs, basketCreatedLogs] = await Promise.all([ getLogs({ target: CONTRACT, eventAbi: sipCreatedAbi, fromBlock: DEPLOY_BLOCK, cacheInCloud: true, toBlock }), getLogs({ target: CONTRACT, eventAbi: basketCreatedAbi, fromBlock: DEPLOY_BLOCK, cacheInCloud: true, toBlock }), ]); const stablecoinMap = new Map(); for (const l of createdLogs) stablecoinMap.set(l.planId.toString(), l.stablecoin); for (const l of basketCreatedLogs) stablecoinMap.set(l.planId.toString(), l.stablecoin); const dailyVolume = createBalances(); const dailyFees = createBalances(); const [execLogs, basketExecLogs] = await Promise.all([ getLogs({ target: CONTRACT, eventAbi: investmentExecutedAbi }), getLogs({ target: CONTRACT, eventAbi: basketInvestmentExecutedAbi }), ]); for (const l of [...execLogs, ...basketExecLogs]) { const stablecoin = stablecoinMap.get(l.planId.toString()); if (stablecoin) { dailyVolume.add(stablecoin, l.amountIn); dailyFees.add(stablecoin, l.feeAmount, "Swap Fees"); } } return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, dailyUserFees: dailyFees }; }; const methodology = { Volume: "Total stablecoin value of all DCA swaps executed through Stackit on Arbitrum, aggregated from InvestmentExecuted and BasketInvestmentExecuted on-chain events.", Fees: "0.5% platform fee collected on every DCA swap executed through Stackit on Arbitrum.", Revenue: "Stackit retains 100% of platform fees — no liquidity providers to share with.", ProtocolRevenue: "All fees go directly to the Stackit protocol (feeCollector address).", UserFees: "Fees paid directly by users as a percentage of each scheduled investment swap.", }; const breakdownMethodology = { Fees: { "Swap Fees": "0.5% of each DCA swap amount, from InvestmentExecuted and BasketInvestmentExecuted events." }, Revenue: { "Swap Fees": "Platform retains all swap fees — no LP revenue share." }, ProtocolRevenue: { "Swap Fees": "All swap fees sent to feeCollector address." }, UserFees: { "Swap Fees": "End-users pay 0.5% of each scheduled investment." } }; const adapter: SimpleAdapter = { version: 2, fetch, pullHourly: true, chains: [CHAIN.ARBITRUM], start: "2026-04-23", methodology, breakdownMethodology, }; export default adapter; ================================================ FILE: aggregators/superboring/index.ts ================================================ import { request, gql } from 'graphql-request' import { CHAIN } from '../../helpers/chains' import { FetchOptions, SimpleAdapter } from '../../adapters/types' const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' // Subgraph endpoints for fetching torex contract addresses const TOREX_GRAPHQL_ENDPOINTS: Record = { [CHAIN.BASE]: 'https://api.goldsky.com/api/public/project_clsnd6xsoma5j012qepvucfpp/subgraphs/superboring_base-mainnet/prod/gn', [CHAIN.OPTIMISM]: 'https://api.goldsky.com/api/public/project_clsnd6xsoma5j012qepvucfpp/subgraphs/superboring_optimism-mainnet/prod/gn', [CHAIN.ARBITRUM]: 'https://api.goldsky.com/api/public/project_clsnd6xsoma5j012qepvucfpp/subgraphs/superboring_arbitrum-one/prod/gn', } // GraphQL query to fetch torex contracts and their input tokens const TOREXES_QUERY = gql` query Torexes { torexes { id name inToken { id underlyingTokenAddress } } } ` const LIQUIDITY_MOVED_EVENT = 'event LiquidityMoved(address indexed liquidityMover, uint256 durationSinceLastLME, uint256 twapSinceLastLME, uint256 inAmount, uint256 minOutAmount, uint256 outAmount, uint256 actualOutAmount)' const SUPERTOKEN_ABI = { getUnderlyingToken: 'function getUnderlyingToken() view returns (address)', getUnderlyingDecimals: 'function getUnderlyingDecimals() view returns (uint8)', decimals: 'function decimals() view returns (uint8)', } type TorexData = { address: string inTokenAddress: string } async function fetchTorexes(chain: string): Promise { const endpoint = TOREX_GRAPHQL_ENDPOINTS[chain] if (!endpoint) return [] try { const res = await request<{ torexes: any[] }>(endpoint, TOREXES_QUERY) return (res.torexes || []) .filter(t => t?.id && t?.inToken?.id) .map(t => ({ address: t.id, inTokenAddress: t.inToken.id })) } catch (e) { console.warn(`Failed to fetch torexes from subgraph for chain ${chain}:`, e) return [] } } async function fetchLiquidityMovedAmount( torexAddress: string, options: FetchOptions ): Promise { try { const logs = await options.getLogs({ target: torexAddress, eventAbi: LIQUIDITY_MOVED_EVENT }) let totalInAmount = 0n for (const log of logs) { const inAmount = BigInt(log.inAmount || '0') totalInAmount += inAmount } return totalInAmount } catch (e) { console.warn(`Failed to fetch LiquidityMoved events for torex ${torexAddress}:`, e) return 0n } } async function getSuperTokenMetadata(superTokenAddress: string, options: FetchOptions): Promise<{ underlyingToken: string | null, underlyingDecimals: number, isNativeAssetSuperToken: boolean }> { try { let underlyingToken: string | null = null let underlyingDecimals = 18 // Default for SuperTokens let isNativeAssetSuperToken = false const NATIVE_ASSET_ADDRESSES: Record = { [CHAIN.BASE]: '0x46fd5cfb4c12d87acd3a13e92baa53240c661d93', [CHAIN.OPTIMISM]: '0x4ac8bd1bdae47beef2d1c6aa62229509b962aa0d', [CHAIN.ARBITRUM]: '0xe6c8d111337d0052b9d88bf5d7d55b7f8385acd3' } try { underlyingToken = await options.api.call({ target: superTokenAddress, abi: SUPERTOKEN_ABI.getUnderlyingToken }) if (underlyingToken === ZERO_ADDRESS) { isNativeAssetSuperToken = superTokenAddress.toLowerCase() === NATIVE_ASSET_ADDRESSES[options.chain].toLowerCase() underlyingToken = null } else { underlyingDecimals = await options.api.call({ target: superTokenAddress, abi: SUPERTOKEN_ABI.getUnderlyingDecimals }) } } catch (e) { underlyingToken = null } return { underlyingToken, underlyingDecimals: Number(underlyingDecimals), isNativeAssetSuperToken } } catch (e) { console.warn(`Failed to get SuperToken metadata for ${superTokenAddress}:`, e) return { underlyingToken: null, underlyingDecimals: 18, isNativeAssetSuperToken: false } } } async function fetchDailyVolume(options: FetchOptions) { const { chain } = options const torexes = await fetchTorexes(chain) const dailyVolumeBalances = options.createBalances() if (!torexes.length) { return { dailyVolume: dailyVolumeBalances } } for (const torex of torexes) { const amount = await fetchLiquidityMovedAmount(torex.address, options) if (amount === 0n) continue const tokenMetadata = await getSuperTokenMetadata(torex.inTokenAddress, options) if (tokenMetadata.isNativeAssetSuperToken) { // Native SuperToken (ETHx) - use zero address for native token pricing dailyVolumeBalances.add(ZERO_ADDRESS, amount.toString()) } else if (!tokenMetadata.underlyingToken) { // Pure SuperToken (no underlying) - use SuperToken address itself dailyVolumeBalances.add(torex.inTokenAddress.toLowerCase(), amount.toString()) } else { // Wrapped SuperToken - use underlying token address const underlyingDecimals = tokenMetadata.underlyingDecimals // SuperTokens have 18 decimals, but underlying tokens may have different decimals for tokens like USDC, so scaling down here if necessary const scaled = amount / (10n ** BigInt(18 - underlyingDecimals)) if (scaled > 0n) { dailyVolumeBalances.add(tokenMetadata.underlyingToken.toLowerCase(), scaled.toString()) } } } return { dailyVolume: dailyVolumeBalances } } const adapter: SimpleAdapter = { version: 2, fetch: fetchDailyVolume, chains: [CHAIN.BASE, CHAIN.OPTIMISM, CHAIN.ARBITRUM], adapter: { [CHAIN.BASE]: { start: 1720080031 }, [CHAIN.OPTIMISM]: { start: 1723454131 }, [CHAIN.ARBITRUM]: { start: 1750045591 }, }, methodology: 'Volume represents the USD value of SuperTokens DCAed through SuperBoring Torexes during each day', } export default adapter ================================================ FILE: aggregators/superswap/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types" import { CHAIN } from "../../helpers/chains" import ADDRESSES from '../../helpers/coreAssets.json' const event_route = 'event Route(address indexed from,address to,address indexed tokenIn,address indexed tokenOut,uint256 amountIn,uint256 amountOutMin,uint256 amountOut)' type ChainConfig = { start: string v1Routers: string[] v2Routers: string[] portal: string } const FEES = { inchain: 0.25, //0.25% crosschain: 0.35, //0.35% } const SWAP_FEES = 'Swap Fees' const SWAP_FEES_TO_PROTOCOL = 'Swap Fees To Protocol' // V1 routers are included for volume only. V2 routers use the same Route event and are the only routers with inferred fees. const chainConfig: Record = { [CHAIN.ARBITRUM]: { start: '2026-02-10', v1Routers: ['0x8b9Ffff3d567cc578752D455BCb7BE86fa60F5b8'], v2Routers: ['0x5E0DD34FB6C74552A1FFF089090375A508c1ead3'], portal: '0x025f28177dBc77A7134f76C0498467b3ea3aa2A2' }, [CHAIN.BASE]: { start: '2026-02-10', v1Routers: ['0x19FD96207f7B5c55403BE736897f7C1109C8314E'], v2Routers: ['0xCb26DE359b51BDd87b8D054F260307b5EEfc0212'], portal: '0xfe76Ad9679932acb2dbB3eD76283F03f7D80006e' }, [CHAIN.BLAST]: { start: '2026-02-10', v1Routers: ['0x756d003c2aacFBAB59C29aFC49933B952bd9E600'], v2Routers: ['0xBafbbCe0c1a7e540291225724D35ba00d91370Ef'], portal: '0xDa69f96C1d2DF824a11354d423dc84106AAA411a' }, [CHAIN.BSC]: { start: '2026-02-10', v1Routers: ['0x51abC29C7b7611333Ba56cfe6B10dC1ff089786E'], v2Routers: ['0xFa227a80e8358c9794D425E87Fb81F828Eb9A052'], portal: '0xc3fBfe30fBD27774018f2D125FC195f799A375Bf' }, [CHAIN.ETHEREUM]: { start: '2026-02-10', v1Routers: ['0x50b1E6ab68E6BeD281C27810dEd0c293C3a20B4D'], v2Routers: ['0x660e5bd52C1Be2b078eC886Ea2463C9b2ba5feB8'], portal: '0x8a6a5990Dd8D8781D3c15Be2E8C36720C9A453D2' }, [CHAIN.INK]: { start: '2026-02-10', v1Routers: ['0x5839389261D1F38aac7c8E91DcDa85646bEcB414', '0x9f64D99eA5BA69d2E6a5f19a923A26fbdfB370B9'], v2Routers: ['0x8d3cAe434bA71F195400672A9F4b8838C6A96712'], portal: '0x92E8C76e9058BC0cb68a88eFAB9dB37c9A70Bb9e' }, [CHAIN.LINEA]: { start: '2026-02-10', v1Routers: ['0x20b46e8b753093cFf78276832b92DE1A952dcF74'], v2Routers: ['0x7bf555d749895b6f5d70506AD6D62b6E1Cfb8015'], portal: '0x7C085CB54F82F0dcf6Ac66057BB6125c6279a324' }, [CHAIN.LISK]: { start: '2026-02-10', v1Routers: ['0x756d003c2aacFBAB59C29aFC49933B952bd9E600'], v2Routers: ['0xBafbbCe0c1a7e540291225724D35ba00d91370Ef'], portal: '0xDa69f96C1d2DF824a11354d423dc84106AAA411a' }, [CHAIN.MODE]: { start: '2026-02-10', v1Routers: ['0x919150CC162573d9BdCa1887E557b3208b536C99'], v2Routers: ['0x3216F0aaF5e0d30b6b4B4a79DA2f49e6db68d881'], portal: '0xBafbbCe0c1a7e540291225724D35ba00d91370Ef' }, [CHAIN.MONAD]: { start: '2026-02-10', v1Routers: ['0xDa69f96C1d2DF824a11354d423dc84106AAA411a'], v2Routers: ['0xdFE1Fc6738ef169eA175c665A060b4a268B84724'], portal: '0x69f571C93D055CB8096d0D8F591F9e9293a83d31' }, [CHAIN.OPTIMISM]: { start: '2026-02-10', v1Routers: ['0x5ECcD3f2eB245d20Db0e26934961576C1D1B0438'], v2Routers: ['0xa49bea83Fc71Cc430Bf95d51039E2464d5A1814a'], portal: '0x514302FCbaC5a65E09fFD7d68cf4F9F490A000CE' }, [CHAIN.PLASMA]: { start: '2026-02-10', v1Routers: ['0x2b7279D1227CC4838e15f473b8e1718ACBEc4292'], v2Routers: ['0xBafbbCe0c1a7e540291225724D35ba00d91370Ef'], portal: '0xDa69f96C1d2DF824a11354d423dc84106AAA411a' }, [CHAIN.POLYGON]: { start: '2026-02-10', v1Routers: ['0xb511c2CF878e950e5598C1c3e47e546930A1AEa5'], v2Routers: ['0xD001Cec33Ff94B1d41437d9c458c14242787cB24'], portal: '0xDc61B3Be0c2e9709589d0bb7086F28f962dfB959' }, [CHAIN.REDSTONE]: { start: '2026-02-10', v1Routers: [], v2Routers: ['0x9dF7c388b90f79855D523E4fd03633Fc6BAB5378'], portal: '0x248B7A18b3E9C4D61fD41B475575DADcaE2BbC29' }, [CHAIN.SCROLL]: { start: '2026-02-10', v1Routers: ['0x9326cA5FdDc0B6F758BE54Cfe0Ea39eDa56B1459'], v2Routers: ['0xBafbbCe0c1a7e540291225724D35ba00d91370Ef'], portal: '0xDa69f96C1d2DF824a11354d423dc84106AAA411a' }, [CHAIN.SONEIUM]: { start: '2026-02-10', v1Routers: ['0x756d003c2aacFBAB59C29aFC49933B952bd9E600'], v2Routers: ['0xDa69f96C1d2DF824a11354d423dc84106AAA411a'], portal: '0x32c674ACCCF7f98702b276361C2510b5Db349437' }, [CHAIN.UNICHAIN]: { start: '2026-02-10', v1Routers: ['0xB4f358117356E63761537316a4Fdbc0bFCFAA070'], v2Routers: ['0xC4fd90f2f2B1D12256A0459C888Ecd1d4d0f9A87'], portal: '0xAE65c7cA6897728cF6d5Fb38Cf6f8Fe53d74f0eE' }, [CHAIN.WC]: { start: '2026-02-10', v1Routers: ['0x2b7279D1227CC4838e15f473b8e1718ACBEc4292'], v2Routers: ['0x248B7A18b3E9C4D61fD41B475575DADcaE2BbC29'], portal: '0x049A2ADD1211Aa25F8e9BAeA5F69094ceB1e2A99' }, [CHAIN.ZORA]: { start: '2026-02-10', v1Routers: ['0x919150CC162573d9BdCa1887E557b3208b536C99'], v2Routers: ['0xb3eD19a22b6e1Ee92166a0d6BD7033037A32803E'], portal: '0x3216F0aaF5e0d30b6b4B4a79DA2f49e6db68d881' }, [CHAIN.ERA]: { start: '2026-02-10', v1Routers: ['0xec598F086899eD1EE56F8666a31ed19e57453725'], v2Routers: [], portal: '' }, [CHAIN.MEGAETH]: { start: '2026-02-10', v1Routers: ['0x3A735e9A60304A59EB4492A90D6d0C529631b50e'], v2Routers: [], portal: '' }, [CHAIN.HYPERLIQUID]: { start: '2026-02-10', v1Routers: ['0x2b7279D1227CC4838e15f473b8e1718ACBEc4292'], v2Routers: [], portal: '' }, } const fetch = async (options: FetchOptions) => { const config = chainConfig[options.chain] const v1Logs = config.v1Routers.length ? await options.getLogs({ targets: config.v1Routers, eventAbi: event_route }) : [] const v2Logs = config.v2Routers.length ? await options.getLogs({ targets: config.v2Routers, eventAbi: event_route }) : [] const dailyVolume = options.createBalances() const dailyFees = options.createBalances() const dailyUserFees = options.createBalances() const dailyRevenue = options.createBalances() const dailyProtocolRevenue = options.createBalances() const portal = config.portal.toLowerCase() ;[...v1Logs, ...v2Logs].forEach(log => { if (log.tokenIn.toLowerCase() === ADDRESSES.GAS_TOKEN_2.toLowerCase()) dailyVolume.addGasToken(log.amountIn) else dailyVolume.add(log.tokenIn, log.amountIn) }) v2Logs.forEach(log => { const fee = log.from.toLowerCase() === portal || log.to.toLowerCase() === portal ? FEES.crosschain : FEES.inchain const feeAmount = (BigInt(log.amountIn) * BigInt(fee * 100)) / 10_000n if (feeAmount === 0n) return const amount = feeAmount.toString() if (log.tokenIn.toLowerCase() === ADDRESSES.GAS_TOKEN_2.toLowerCase()) { dailyFees.addGasToken(amount, SWAP_FEES) dailyUserFees.addGasToken(amount, SWAP_FEES) dailyRevenue.addGasToken(amount, SWAP_FEES_TO_PROTOCOL) dailyProtocolRevenue.addGasToken(amount, SWAP_FEES_TO_PROTOCOL) } else { dailyFees.add(log.tokenIn, amount, SWAP_FEES) dailyUserFees.add(log.tokenIn, amount, SWAP_FEES) dailyRevenue.add(log.tokenIn, amount, SWAP_FEES_TO_PROTOCOL) dailyProtocolRevenue.add(log.tokenIn, amount, SWAP_FEES_TO_PROTOCOL) } }) return { dailyVolume, dailyFees, dailyUserFees, dailyRevenue, dailyProtocolRevenue, } } const methodology = { Volume: "Sum of amountIn from Route events on SuperSwap v1 and v2 routers.", Fees: "V2 swaps charge 0.25% for in-chain swaps and 0.35% for cross-chain portal swaps.", UserFees: "V2 swaps charge 0.25% for in-chain swaps and 0.35% for cross-chain portal swaps.", Revenue: "All fees are retained by SuperSwap.", ProtocolRevenue: "All fees are retained by SuperSwap.", } const breakdownMethodology = { Fees: { [SWAP_FEES]: "Swap fees charged on v2 SuperSwap routes: 0.25% for in-chain swaps and 0.35% for cross-chain portal swaps.", }, UserFees: { [SWAP_FEES]: "Fees paid by users on v2 SuperSwap routes.", }, Revenue: { [SWAP_FEES_TO_PROTOCOL]: "Swap fees retained by SuperSwap.", }, ProtocolRevenue: { [SWAP_FEES_TO_PROTOCOL]: "Swap fees retained by SuperSwap.", }, } const adapter: SimpleAdapter = { version: 2, fetch, methodology, breakdownMethodology, adapter: chainConfig, methodology, } export default adapter; ================================================ FILE: aggregators/sushiswap-agg.ts ================================================ import ADDRESSES from '../helpers/coreAssets.json' import { FetchResultV2, FetchV2 } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { httpGet } from "../utils/fetchURL"; import { getDefaultDexTokensBlacklisted, getDefaultDexTokensWhitelisted } from '../helpers/lists'; import { formatAddress } from '../utils/utils'; const ROUTE_RP45_EVENT = 'event Route(address indexed from, address to, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOutMin,uint256 amountOut)' const ROUTE_RP6_EVENT = 'event Route(address indexed from, address to, address indexed tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMin, uint256 amountOut, int256 slippage, uint32 indexed referralCode)' const ROUTE_RP7_EVENT = 'event Route(address indexed from, address to, address indexed tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, int256 slippage, uint32 indexed referralCode)' const ROUTE_RP9_EVENT = 'event Route(address indexed from, address to, address indexed tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, int256 slippage, uint32 indexed referralCode, bytes32 diagnosticsFirst32)' const CHAIN_ID: any = { [CHAIN.ETHEREUM]: 1, [CHAIN.ARBITRUM]: 42161, [CHAIN.OPTIMISM]: 10, [CHAIN.BASE]: 8453, [CHAIN.POLYGON]: 137, [CHAIN.AVAX]: 43114, [CHAIN.BSC]: 56, [CHAIN.LINEA]: 59144, [CHAIN.ARBITRUM_NOVA]: 42170, [CHAIN.XDAI]: 100, [CHAIN.FANTOM]: 250, [CHAIN.BITTORRENT]: 199, [CHAIN.CELO]: 42220, [CHAIN.FILECOIN]: 314, [CHAIN.HAQQ]: 11235, [CHAIN.KAVA]: 2222, [CHAIN.METIS]: 1088, [CHAIN.THUNDERCORE]: 108, [CHAIN.SCROLL]: 534352, [CHAIN.ZETA]: 7000, [CHAIN.MOONBEAM]: 1284, [CHAIN.MOONRIVER]: 1285, [CHAIN.POLYGON_ZKEVM]: 1101, [CHAIN.FUSE]: 122, [CHAIN.HARMONY]: 1666600000, [CHAIN.TELOS]: 40, [CHAIN.BOBA]: 288, [CHAIN.BOBA_BNB]: 56288, [CHAIN.CORE]: 1116, [CHAIN.CRONOS]: 81457, [CHAIN.BLAST]: 81457, [CHAIN.SKALE_EUROPA]: 2046399126, [CHAIN.ROOTSTOCK]: 30, [CHAIN.MANTLE]: 5000, [CHAIN.ERA]: 324, [CHAIN.MANTA]: 169, [CHAIN.MODE]: 34443, [CHAIN.TAIKO]: 167000, [CHAIN.ZKLINK]: 810180, [CHAIN.APECHAIN]: 33139, [CHAIN.SONIC]: 146, [CHAIN.HEMI]: 43111, [CHAIN.KATANA]: 747474, [CHAIN.HYPERLIQUID]: 999, [CHAIN.BERACHAIN]: 80094, [CHAIN.PLASMA]: 9745, [CHAIN.MONAD]: 143, [CHAIN.MEGAETH]: 4326, [CHAIN.XLAYER]: 196, } const RP4_ADDRESS: any = { [CHAIN.ETHEREUM]: '0xe43ca1Dee3F0fc1e2df73A0745674545F11A59F5', [CHAIN.ARBITRUM]: '0x544bA588efD839d2692Fc31EA991cD39993c135F', [CHAIN.OPTIMISM]: '0x1f2FCf1d036b375b384012e61D3AA33F8C256bbE', [CHAIN.BASE]: '0x0389879e0156033202c44bf784ac18fc02edee4f', [CHAIN.POLYGON]: '0x46B3fDF7b5CDe91Ac049936bF0bDb12c5d22202e', [CHAIN.AVAX]: '0xCdBCd51a5E8728E0AF4895ce5771b7d17fF71959', [CHAIN.BSC]: '0x33d91116e0370970444B0281AB117e161fEbFcdD', [CHAIN.LINEA]: '0x46b3fdf7b5cde91ac049936bf0bdb12c5d22202e', [CHAIN.ARBITRUM_NOVA]: '0xCdBCd51a5E8728E0AF4895ce5771b7d17fF71959', [CHAIN.XDAI]: '0x46b3fdf7b5cde91ac049936bf0bdb12c5d22202e', [CHAIN.FANTOM]: '0x46b3fdf7b5cde91ac049936bf0bdb12c5d22202e', [CHAIN.BITTORRENT]: '0x93c31c9C729A249b2877F7699e178F4720407733', [CHAIN.CELO]: '0xCdBCd51a5E8728E0AF4895ce5771b7d17fF71959', [CHAIN.FILECOIN]: '0x1f2FCf1d036b375b384012e61D3AA33F8C256bbE', [CHAIN.HAQQ]: '0xc3Ec4e1511c6935ed2F92b9A61881a1B95bB1566', [CHAIN.KAVA]: '0xB45e53277a7e0F1D35f2a77160e91e25507f1763', [CHAIN.METIS]: '0xB45e53277a7e0F1D35f2a77160e91e25507f1763', [CHAIN.THUNDERCORE]: '0x57bfFa72db682f7eb6C132DAE03FF36bBEB0c459', [CHAIN.SCROLL]: '0x734583f62Bb6ACe3c9bA9bd5A53143CA2Ce8C55A', [CHAIN.ZETA]: '0x640129e6b5C31B3b12640A5b39FECdCa9F81C640', [CHAIN.MOONBEAM]: '0xB45e53277a7e0F1D35f2a77160e91e25507f1763', [CHAIN.MOONRIVER]: '0x46B3fDF7b5CDe91Ac049936bF0bDb12c5d22202e', [CHAIN.POLYGON_ZKEVM]: '0x57bfFa72db682f7eb6C132DAE03FF36bBEB0c459', [CHAIN.FUSE]: '0x46B3fDF7b5CDe91Ac049936bF0bDb12c5d22202e', [CHAIN.HARMONY]: '0x9B3336186a38E1b6c21955d112dbb0343Ee061eE', [CHAIN.TELOS]: '0x1400feFD6F9b897970f00Df6237Ff2B8b27Dc82C', [CHAIN.BOBA]: '0xe43ca1Dee3F0fc1e2df73A0745674545F11A59F5', [CHAIN.BOBA_BNB]: '0xCdBCd51a5E8728E0AF4895ce5771b7d17fF71959', [CHAIN.CORE]: '0x0389879e0156033202C44BF784ac18fC02edeE4f', [CHAIN.CRONOS]: '0xCdBCd51a5E8728E0AF4895ce5771b7d17fF71959', [CHAIN.BLAST]: '0xCdBCd51a5E8728E0AF4895ce5771b7d17fF71959', [CHAIN.SKALE_EUROPA]: '0xbA61F775730C0a3E3361717195ee86785ee33055', [CHAIN.ROOTSTOCK]: '0xb46e319390De313B8cc95EA5aa30C7bBFD79Da94', } const RP5_ADDRESS: any = { [CHAIN.ETHEREUM]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.ARBITRUM]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.OPTIMISM]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.BASE]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.POLYGON]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.AVAX]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.BSC]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.LINEA]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.ARBITRUM_NOVA]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.XDAI]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.FANTOM]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.BITTORRENT]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.CELO]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.FILECOIN]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.HAQQ]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.KAVA]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.METIS]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.THUNDERCORE]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.SCROLL]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.ZETA]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.MOONBEAM]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.MOONRIVER]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.POLYGON_ZKEVM]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.FUSE]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.HARMONY]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.TELOS]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.BOBA]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.BOBA_BNB]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.CORE]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.CRONOS]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.BLAST]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.SKALE_EUROPA]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.ROOTSTOCK]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.MANTLE]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.ERA]: '0x9e55e562D40FD01f38cD4057e632352fE0758F16', [CHAIN.MANTA]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.MODE]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.TAIKO]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', [CHAIN.ZKLINK]: '0x9e55e562D40FD01f38cD4057e632352fE0758F16', [CHAIN.APECHAIN]: '0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55', } const RP6_ADDRESS: any = { [CHAIN.ETHEREUM]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.ARBITRUM]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.OPTIMISM]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.BASE]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.POLYGON]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.AVAX]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.BSC]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.LINEA]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.ARBITRUM_NOVA]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.XDAI]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.FANTOM]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.BITTORRENT]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.CELO]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.FILECOIN]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.HAQQ]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.KAVA]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.METIS]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.THUNDERCORE]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.SCROLL]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.ZETA]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.MOONBEAM]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.MOONRIVER]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.POLYGON_ZKEVM]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.FUSE]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.HARMONY]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.TELOS]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.BOBA]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.BOBA_BNB]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.CORE]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.CRONOS]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.BLAST]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.SKALE_EUROPA]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.ROOTSTOCK]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.ERA]: '0xE6fD46600A97CE06703b58333B9C2399F4bF6FEc', [CHAIN.MANTLE]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.MANTA]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.MODE]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.TAIKO]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.ZKLINK]: '0xE6fD46600A97CE06703b58333B9C2399F4bF6FEc', [CHAIN.APECHAIN]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.SONIC]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71', [CHAIN.HEMI]: '0x85CD07Ea01423b1E937929B44E4Ad8c40BbB5E71' } const RP7_ADDRESS: any = { [CHAIN.ETHEREUM]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.ARBITRUM]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.OPTIMISM]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.BASE]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.POLYGON]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.AVAX]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.BSC]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.LINEA]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.ARBITRUM_NOVA]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.XDAI]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.FANTOM]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.BITTORRENT]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.CELO]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.FILECOIN]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.HAQQ]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.KAVA]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.METIS]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.THUNDERCORE]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.SCROLL]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.ZETA]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.MOONBEAM]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.MOONRIVER]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.POLYGON_ZKEVM]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.FUSE]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.HARMONY]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.TELOS]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.BOBA]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.BOBA_BNB]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.CORE]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.CRONOS]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.BLAST]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.SKALE_EUROPA]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.ROOTSTOCK]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.ERA]: '0xd7C94C8C61628911C41141289af1D0dE17d7aC8d', [CHAIN.MANTLE]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.MANTA]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.MODE]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.TAIKO]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.ZKLINK]: '0xd7C94C8C61628911C41141289af1D0dE17d7aC8d', [CHAIN.APECHAIN]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.SONIC]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.HEMI]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', [CHAIN.KATANA]: '0x3Ced11c610556e5292fBC2e75D68c3899098C14C', } const RP8_ADDRESS: any = { [CHAIN.ETHEREUM]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', [CHAIN.ARBITRUM]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', [CHAIN.OPTIMISM]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', [CHAIN.BASE]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', [CHAIN.POLYGON]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', [CHAIN.MOONBEAM]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', [CHAIN.POLYGON_ZKEVM]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', [CHAIN.MANTLE]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', [CHAIN.KATANA]: '0x2905d7e4D048d29954F81b02171DD313F457a4a4', } const RP9_ADDRESS: any = { [CHAIN.ETHEREUM]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.ARBITRUM]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.OPTIMISM]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.BASE]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.POLYGON]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.AVAX]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.BSC]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.LINEA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.ARBITRUM_NOVA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.XDAI]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.FANTOM]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.BITTORRENT]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.CELO]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.FILECOIN]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.HAQQ]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.KAVA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.METIS]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.THUNDERCORE]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.SCROLL]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.ZETA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.MOONBEAM]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.MOONRIVER]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.POLYGON_ZKEVM]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.FUSE]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.HARMONY]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.TELOS]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.BOBA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.BOBA_BNB]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.CORE]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.CRONOS]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.BLAST]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.SKALE_EUROPA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.ROOTSTOCK]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.ERA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.MANTLE]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.MANTA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.MODE]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.TAIKO]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.ZKLINK]: '0xE2eFedE921B3114fdde3F9529bc682dBAf742058', [CHAIN.APECHAIN]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.SONIC]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.HEMI]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.KATANA]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.HYPERLIQUID]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', [CHAIN.BERACHAIN]: '0x81602EF321C46d73f5Ba7f476947AE1a862957dc', } const RP9_1_ADDRESS: any = { [CHAIN.ETHEREUM]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.ARBITRUM]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.OPTIMISM]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.BASE]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.POLYGON]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.AVAX]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.BSC]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.LINEA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.ARBITRUM_NOVA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.XDAI]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.FANTOM]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.BITTORRENT]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.CELO]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.FILECOIN]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.HAQQ]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.KAVA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.METIS]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.THUNDERCORE]: '0x861255aef9aad3e268fb67a3c97afd490bff3d6b', [CHAIN.SCROLL]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.ZETA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.POLYGON_ZKEVM]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.HARMONY]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.BOBA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.BOBA_BNB]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.CORE]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.CRONOS]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.BLAST]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.SKALE_EUROPA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.ROOTSTOCK]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.ERA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.MANTLE]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.MANTA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.MODE]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.TAIKO]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.ZKLINK]: '0xfb7eedd827c4bed92b9b6c5159bee11301f3da8c', [CHAIN.APECHAIN]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.SONIC]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.HEMI]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.KATANA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.HYPERLIQUID]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.BERACHAIN]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', [CHAIN.PLASMA]: '0x3b0aa7d38bf3c103bf02d1de2e37568cbed3d6e8', } const RP9_2_ADDRESS: any = { [CHAIN.ETHEREUM]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.ARBITRUM]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.OPTIMISM]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.BASE]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.POLYGON]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.AVAX]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.BSC]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.LINEA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.ARBITRUM_NOVA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.XDAI]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.FANTOM]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.BITTORRENT]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.CELO]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.FILECOIN]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.HAQQ]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.KAVA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.METIS]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.THUNDERCORE]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.SCROLL]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.ZETA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.POLYGON_ZKEVM]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.HARMONY]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.BOBA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.BOBA_BNB]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.CORE]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.CRONOS]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.BLAST]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.SKALE_EUROPA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.ROOTSTOCK]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.ERA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.MANTLE]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.MANTA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.MODE]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.TAIKO]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.ZKLINK]: '0xe0a091ceeb255ce3abc3b18305d48a07521e19e1', [CHAIN.APECHAIN]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.SONIC]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.HEMI]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.KATANA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.HYPERLIQUID]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.BERACHAIN]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.PLASMA]: '0xd2b37ade14708bf18904047b1e31f8166d39612b', [CHAIN.MONAD]: '0xd2b37aDE14708bf18904047b1E31F8166d39612b', } const RP10_ADDRESS: any = { [CHAIN.ETHEREUM]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.ARBITRUM]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.OPTIMISM]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.BASE]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.POLYGON]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.AVAX]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.BSC]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.LINEA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.ARBITRUM_NOVA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.XDAI]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.FANTOM]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.BITTORRENT]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.CELO]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.FILECOIN]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.HAQQ]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.KAVA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.METIS]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.THUNDERCORE]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.SCROLL]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.ZETA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.POLYGON_ZKEVM]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.HARMONY]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.BOBA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.BOBA_BNB]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.CORE]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.CRONOS]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.BLAST]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.SKALE_EUROPA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.ROOTSTOCK]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.ERA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.MANTLE]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.MANTA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.MODE]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.TAIKO]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.ZKLINK]: '0x67ad43499eda05ddd799f4e6c407646c5bf2ed47', [CHAIN.APECHAIN]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.SONIC]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.HEMI]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.KATANA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.HYPERLIQUID]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.BERACHAIN]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.PLASMA]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.MONAD]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.MEGAETH]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', [CHAIN.XLAYER]: '0xe89aab725a2b2c0656248dcccc894a04661be55a', } const RP11_ADDRESS: any = { [CHAIN.ETHEREUM]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.ARBITRUM]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.OPTIMISM]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.BASE]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.POLYGON]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.AVAX]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.BSC]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.LINEA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.ARBITRUM_NOVA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.XDAI]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.FANTOM]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.BITTORRENT]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.CELO]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.FILECOIN]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.KAVA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.METIS]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.THUNDERCORE]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.SCROLL]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.ZETA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.POLYGON_ZKEVM]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.HARMONY]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.BOBA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.BOBA_BNB]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.CORE]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.CRONOS]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.BLAST]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.SKALE_EUROPA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.ROOTSTOCK]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.ERA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.MANTLE]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.MANTA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.MODE]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.TAIKO]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.ZKLINK]: '0x169be3df32d31827067649a2d4c7574c738912a3', [CHAIN.APECHAIN]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.SONIC]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.HEMI]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.KATANA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.HYPERLIQUID]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.BERACHAIN]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.PLASMA]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.MONAD]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.MEGAETH]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', [CHAIN.XLAYER]: '0xc10ee9031f2a0b84766a86b55a8d90f357910fb4', } const WNATIVE_ADDRESS: any = { [CHAIN.ETHEREUM]: ADDRESSES.ethereum.WETH, [CHAIN.ARBITRUM]: ADDRESSES.arbitrum.WETH, [CHAIN.OPTIMISM]: ADDRESSES.optimism.WETH_1, [CHAIN.BASE]: ADDRESSES.optimism.WETH_1, [CHAIN.POLYGON]: ADDRESSES.polygon.WMATIC_2, [CHAIN.AVAX]: ADDRESSES.avax.WAVAX, [CHAIN.BSC]: ADDRESSES.bsc.WBNB, [CHAIN.LINEA]: ADDRESSES.linea.WETH, [CHAIN.ARBITRUM_NOVA]: ADDRESSES.arbitrum_nova.WETH, [CHAIN.XDAI]: ADDRESSES.xdai.WXDAI, [CHAIN.FANTOM]: ADDRESSES.fantom.WFTM, [CHAIN.BITTORRENT]: ADDRESSES.bittorrent.WBTT, [CHAIN.CELO]: ADDRESSES.celo.CELO, [CHAIN.FILECOIN]: '0x60e1773636cf5e4a227d9ac24f20feca034ee25a', [CHAIN.HAQQ]: ADDRESSES.islm.ISLM, [CHAIN.KAVA]: ADDRESSES.kava.WKAVA, [CHAIN.METIS]: '0x75cb093e4d61d2a2e65d8e0bbb01de8d89b53481', [CHAIN.THUNDERCORE]: ADDRESSES.thundercore.WTT, [CHAIN.SCROLL]: ADDRESSES.scroll.WETH, [CHAIN.ZETA]: ADDRESSES.zeta.WZETA, [CHAIN.MOONBEAM]: '0xacc15dc74880c9944775448304b263d191c6077f', [CHAIN.MOONRIVER]: '0xf50225a84382c74cbdea10b0c176f71fc3de0c4d', [CHAIN.POLYGON_ZKEVM]: ADDRESSES.polygon_zkevm.WETH, [CHAIN.FUSE]: ADDRESSES.fuse.WFUSE, [CHAIN.HARMONY]: ADDRESSES.harmony.WONE, [CHAIN.TELOS]: ADDRESSES.telos.WTLOS, [CHAIN.BOBA]: ADDRESSES.metis.Metis, [CHAIN.BOBA_BNB]: '0xc58aad327d6d58d979882601ba8dda0685b505ea', [CHAIN.CORE]: ADDRESSES.core.WCORE, [CHAIN.CRONOS]: ADDRESSES.cronos.WCRO_1, [CHAIN.BLAST]: ADDRESSES.blast.WETH, [CHAIN.SKALE_EUROPA]: ADDRESSES.null, [CHAIN.ROOTSTOCK]: ADDRESSES.rsk.WRBTC1, [CHAIN.MANTLE]: ADDRESSES.mantle.WMNT, [CHAIN.ERA]: ADDRESSES.era.WETH, [CHAIN.MANTA]: ADDRESSES.manta.WETH, [CHAIN.MODE]: ADDRESSES.optimism.WETH_1, [CHAIN.TAIKO]: ADDRESSES.taiko.WETH, [CHAIN.ZKLINK]: ADDRESSES.zklink.WETH, [CHAIN.APECHAIN]: ADDRESSES.apechain.WAPE, [CHAIN.SONIC]: ADDRESSES.sonic.wS, [CHAIN.HEMI]: ADDRESSES.optimism.WETH_1, [CHAIN.KATANA]: ADDRESSES.optimism.WETH_1, [CHAIN.HYPERLIQUID]: ADDRESSES.hyperliquid.WHYPE, [CHAIN.BERACHAIN]: ADDRESSES.berachain.WBERA, [CHAIN.PLASMA]: ADDRESSES.plasma.WXPL, [CHAIN.MONAD]: ADDRESSES.monad.WMON, [CHAIN.MEGAETH]: '0x4200000000000000000000000000000000000006', [CHAIN.XLAYER]: ADDRESSES.xlayer.WOKB, } const useSushiAPIPrice = (chain: any) => [ CHAIN.BOBA_BNB, CHAIN.MOONRIVER ].includes(chain) interface Log { tokenIn: string; amountIn: string; tokenOut: string; amountOut: string; } const fetch: FetchV2 = async ({ getLogs, createBalances, chain }): Promise => { const dailyVolume = createBalances() const blacklistedTokens = getDefaultDexTokensBlacklisted(chain) const whitelistedTokens = await getDefaultDexTokensWhitelisted({ chain: chain }) let logs: Array = []; if (RP4_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP4_ADDRESS[chain], eventAbi: ROUTE_RP45_EVENT })) if (RP5_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP5_ADDRESS[chain], eventAbi: ROUTE_RP45_EVENT })) if (RP6_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP6_ADDRESS[chain], eventAbi: ROUTE_RP6_EVENT })) if (RP7_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP7_ADDRESS[chain], eventAbi: ROUTE_RP7_EVENT })) if (RP8_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP8_ADDRESS[chain], eventAbi: ROUTE_RP7_EVENT })) if (RP9_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP9_ADDRESS[chain], eventAbi: ROUTE_RP9_EVENT })) if (RP9_1_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP9_1_ADDRESS[chain], eventAbi: ROUTE_RP9_EVENT })) if (RP9_2_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP9_2_ADDRESS[chain], eventAbi: ROUTE_RP9_EVENT })) if (RP10_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP10_ADDRESS[chain], eventAbi: ROUTE_RP9_EVENT })) if (RP11_ADDRESS[chain]) logs = logs.concat(await getLogs({ target: RP11_ADDRESS[chain], eventAbi: ROUTE_RP9_EVENT })) if (whitelistedTokens.length > 0) { logs = logs.filter((log: Log) => (whitelistedTokens.includes(formatAddress(log.tokenIn)) || whitelistedTokens.includes(formatAddress(log.tokenOut))) && !blacklistedTokens.includes(formatAddress(log.tokenIn)) && !blacklistedTokens.includes(formatAddress(log.tokenOut)) ) } // filter many scam/spam tokens on arbitrum if (chain === CHAIN.ARBITRUM) { // require both input and output tokens in whitelisted logs = logs.filter((log: Log) => (whitelistedTokens.includes(formatAddress(log.tokenIn)) && whitelistedTokens.includes(formatAddress(log.tokenOut)))) } if (useSushiAPIPrice(chain)) { const tokenPrice = Object.entries(await httpGet(`https://api.sushi.com/price/v1/${CHAIN_ID[chain]}`)).reduce((acc, [key, value]: any) => { acc[key.toLowerCase()] = value return acc }); const tokensIn = [...new Set(logs.map(log => log.tokenIn.toLowerCase()))] const tokensInfo = (await Promise.all(tokensIn.map(token => httpGet(`https://api.sushi.com/token/v1/${CHAIN_ID[chain]}/${token}`)))).flat(); const tokens = tokensInfo.reduce((tokens, token) => { const address = token.address.toLowerCase() tokens[address] = { ...token, price: tokenPrice[address] ?? 0 } return tokens }, {}); for (const log of logs) { const token = tokens[log.tokenIn.toLowerCase()] if (token && log.tokenIn.toLowerCase() !== ADDRESSES.GAS_TOKEN_2.toLowerCase()) { const _dailyVolume = Number(log.amountIn) * token.price / 10 ** token.decimals if (_dailyVolume < 0) throw new Error(`Daily volume cannot be negative. Current value: ${_dailyVolume}`) dailyVolume.addUSDValue(_dailyVolume) } else { if (Number(log.amountIn) < 0) throw new Error(`Amount cannot be negative. Current value: ${log.amountIn}`) dailyVolume.add(WNATIVE_ADDRESS[chain], log.amountIn) } } } else { for (const log of logs) { if (Number(log.amountIn) < 0) throw new Error(`Amount cannot be negative. Current value: ${log.amountIn}`) if (log.tokenIn.toLowerCase() === ADDRESSES.GAS_TOKEN_2.toLowerCase()) dailyVolume.addGasToken(log.amountIn) else { dailyVolume.add(log.tokenIn, log.amountIn) } } } return { dailyVolume } } const adapters = { [CHAIN.ARBITRUM]: { fetch, start: '2024-02-25', }, [CHAIN.ARBITRUM_NOVA]: { fetch, start: '2024-02-25' }, [CHAIN.AVAX]: { fetch, start: '2024-02-25' }, [CHAIN.BASE]: { fetch, start: '2024-02-25' }, [CHAIN.BLAST]: { fetch, start: '2024-03-01' }, [CHAIN.BOBA]: { fetch, start: '2024-03-22' }, // [CHAIN.BOBA_BNB]: { // fetch, // start: '2024-02-25' // }, [CHAIN.BSC]: { fetch, start: '2024-02-25' }, [CHAIN.BITTORRENT]: { fetch, start: '2024-02-25' }, [CHAIN.CELO]: { fetch, start: '2024-02-25' }, [CHAIN.CORE]: { fetch, start: '2024-02-25' }, [CHAIN.ETHEREUM]: { fetch, start: '2024-02-25' }, [CHAIN.FANTOM]: { fetch, start: '2024-02-25' }, // [CHAIN.FILECOIN]: { // fetch, // start: '2024-02-25' // }, [CHAIN.FUSE]: { fetch, start: '2024-02-25' }, [CHAIN.XDAI]: { fetch, start: '2024-02-25' }, // [CHAIN.HAQQ]: { // fetch, // start: '2024-02-25' // }, // [CHAIN.HARMONY]: { // fetch, // start: '2024-02-25' // }, [CHAIN.KAVA]: { fetch, start: '2024-02-25' }, [CHAIN.LINEA]: { fetch, start: '2024-02-25' }, [CHAIN.METIS]: { fetch, start: '2024-02-25' }, [CHAIN.MOONBEAM]: { fetch, start: '2024-02-25' }, // [CHAIN.MOONRIVER]: { // fetch, // start: '2024-02-25' // }, [CHAIN.OPTIMISM]: { fetch, start: '2024-02-25' }, [CHAIN.POLYGON]: { fetch, start: '2024-02-25' }, [CHAIN.POLYGON_ZKEVM]: { fetch, start: '2024-02-25' }, // [CHAIN.ROOTSTOCK]: { // fetch, // start: '2024-05-21' // }, [CHAIN.SCROLL]: { fetch, start: '2024-02-25' }, // [CHAIN.SKALE_EUROPA]: { // fetch, // start: '2024-04-22' // }, [CHAIN.THUNDERCORE]: { fetch, start: '2024-02-25' }, [CHAIN.ZETA]: { fetch, start: '2024-02-25' }, [CHAIN.MANTLE]: { fetch, start: '2024-02-25' }, [CHAIN.ERA]: { fetch, start: '2024-02-25' }, [CHAIN.MANTA]: { fetch, start: '2024-02-25' }, [CHAIN.MODE]: { fetch, start: '2024-02-25' }, [CHAIN.TAIKO]: { fetch, start: '2024-02-25' }, [CHAIN.ZKLINK]: { fetch, start: '2024-02-25' }, [CHAIN.APECHAIN]: { fetch, start: '2024-02-25' }, [CHAIN.SONIC]: { fetch, start: '2025-02-19' }, [CHAIN.HEMI]: { fetch, start: '2025-02-19' }, [CHAIN.KATANA]: { fetch, start: '2025-07-01' }, [CHAIN.HYPERLIQUID]: { fetch, start: '2025-09-01' }, [CHAIN.BERACHAIN]: { fetch, start: '2025-09-01' }, [CHAIN.PLASMA]: { fetch, start: '2025-09-25' }, [CHAIN.MONAD]: { fetch, start: '2025-11-23' }, [CHAIN.MEGAETH]: { fetch, start: '2026-02-08' }, // [CHAIN.XLAYER]: { // fetch, // start: '2026-02-08' // }, } export default { version: 2, adapter: adapters, } ================================================ FILE: aggregators/swap-coffee/index.ts ================================================ import { Adapter, FetchV2 } from "../../adapters/types"; import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; const statisticsEndpoint = "https://backend.swap.coffee/v1/statistics/generic" const fetch: FetchV2 = async ({startTimestamp, endTimestamp}) => { const statistics = await httpGet( statisticsEndpoint, { params: { from: startTimestamp, to: endTimestamp - 1 } }) return { dailyVolume: statistics?.volume, dailyFees: statistics?.fees, }; } const adapter: Adapter = { version: 2, adapter: { [CHAIN.TON]: { fetch, start: '2024-06-09', }, } } export default adapter; ================================================ FILE: aggregators/swapgpt/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; interface IVolumeall { dailyVolumeUSD: Array<{ startDateTime: string; dailyVolumeUSD: string; }> } const url = "https://stats-api.panora.exchange/getDefiLlamaStats"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const timestamp = options.startOfDay const dateStr = new Date(timestamp * 1000).toISOString().split('T')[0]; const response: IVolumeall = await fetchURL(url); const dailyVolume = response.dailyVolumeUSD.find((d) => d.startDateTime.split('T')[0] === dateStr); return { dailyVolume: dailyVolume?.dailyVolumeUSD || '0' } }; const adapter: SimpleAdapter = { version: 1, adapter: { [CHAIN.APTOS]: { fetch, start: '2023-11-28', }, }, }; export default adapter; ================================================ FILE: aggregators/swing/index.ts ================================================ import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; const baseURL = 'https://swap.prod.swing.xyz' const chains: Record = { [CHAIN.SOLANA]: 'solana', [CHAIN.ETHEREUM]: 'ethereum', [CHAIN.BSC]: 'bsc', [CHAIN.AVAX]: 'avalanche', [CHAIN.POLYGON]: 'polygon', [CHAIN.ARBITRUM]: 'arbitrum', [CHAIN.ARCHWAY]: 'archway-1', [CHAIN.BSQUARED]: 'b2-network', [CHAIN.BASE]: 'base', [CHAIN.BITCOIN]: 'bitcoin', [CHAIN.BITLAYER]: 'bitlayer', [CHAIN.BLAST]: 'blast', [CHAIN.BOB]: 'bob', [CHAIN.CORE]: 'core-blockchain', [CHAIN.COSMOS]: 'cosmoshub-4', [CHAIN.FANTOM]: 'fantom', [CHAIN.XDAI]: 'gnosis', [CHAIN.GRAVITY]: 'gravity', [CHAIN.INJECTIVE]: 'injective-1', [CHAIN.LINEA]: 'linea', [CHAIN.MANTA]: 'manta-pacific', [CHAIN.MANTLE]: 'mantle', [CHAIN.METIS]: 'metis', [CHAIN.MODE]: 'mode', [CHAIN.MOONBEAM]: 'moonbeam', [CHAIN.MORPH]: 'morph', [CHAIN.CELESTIA]: 'cataclysm-1', [CHAIN.OPTIMISM]: 'optimism', [CHAIN.OSMOSIS]: 'osmosis-1', [CHAIN.SCROLL]: 'scroll', [CHAIN.TAIKO]: 'taiko', [CHAIN.WC]: 'world-chain', [CHAIN.ZKSYNC]: 'zksync-era', }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const startOfDay = options.startOfDay; const endOfDay = startOfDay + 24 * 60 * 60; const dailyRes = await httpGet(`${baseURL}/v0/metrics/stats`, { headers: { 'Content-Type': 'application/json', }, params: { startDate: startOfDay, endDate: endOfDay }, }); const sameChainVolumes = dailyRes?.historicalVolumeSamechain?.map((history: any) => { const chainVol = history?.volume?.find((vol: any) => { return vol?.chainSlug?.toLowerCase() === chains[options.chain].toLowerCase(); }) return chainVol; }); // calculate the total volume const chainVol = sameChainVolumes?.reduce((acc: number, curr: any) => { return acc + Number(curr?.value || 0); }, 0); return { dailyVolume: chainVol || 0, }; }; const startDate = '2022-11-01' const chainAdapters = { ...Object.entries(chains).reduce((acc, chain) => { const [key, value] = chain; return { ...acc, [key]: { fetch: fetch, start: startDate }, }; }, {}) } const adapter = { version: 1, adapter: chainAdapters }; export default adapter; ================================================ FILE: aggregators/symphony/index.ts ================================================ import { Adapter, FetchOptions, FetchResultVolume } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const API_ENDPOINT = "http://stats.symphony.ag/api/v1/stats"; interface IVolumeResponse { last24Hours: { volumeUSD: number; }; } const fetch = async (_a: any, _b: any, options: FetchOptions): Promise => { const data: IVolumeResponse = await fetchURL(`${API_ENDPOINT}?timestamp=${options.startOfDay}`); return { dailyVolume: data.last24Hours.volumeUSD.toString(), }; }; const adapter: Adapter = { version: 1, methodology: 'Tracks the total value of all trades executed through Symphony Aggregator on SEI chain. Volume is calculated by summing the USD value of all trades.', fetch, adapter: { [CHAIN.SEI]: { start: '2024-08-25', // Aug 26, 2024 00:00:00 UTC }, }, }; export default adapter; ================================================ FILE: aggregators/tephra/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const TransformedERC20Event = "event TransformedERC20(address indexed taker, address inputToken, address outputToken, uint256 inputTokenAmount, uint256 outputTokenAmount)"; const FLAT_FEE_RATE = 0.0005; // 0.05% const TEPHRA_AGGREGATOR_CONTRACTS = [ '0xde3102F480dE10385680DCBaFA1834945a63273E', ]; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const logs: any[] = await options.getLogs({ targets: TEPHRA_AGGREGATOR_CONTRACTS, eventAbi: TransformedERC20Event, flatten: true, }); for (const log of logs) { dailyVolume.add(log.inputToken, log.inputTokenAmount); } const dailyFees = dailyVolume.clone(FLAT_FEE_RATE); return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, start: "2025-12-09", methodology: { Volume: "Total trading volume aggregated via Tephra routers.", Fees: "Flat 0.05% amount of trading fees on all trades.", Revenue: "Flat 0.05% amount of trading fees on all trades are revenue.", ProtocolRevenue: "Flat 0.05% amount of trading fees on all trades are revenue.", }, chains: [CHAIN.INK], }; export default adapter; ================================================ FILE: aggregators/tideswap/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addTokensReceived } from "../../helpers/token"; const TREASURY = "0x647128722e6aC0FDF10C1c5bEB9d37C66cE6f907"; const FEE_BPS = 5; const INK_TOKENS = [ "0x4200000000000000000000000000000000000006", "0x2d270e6886d130d724215a266106e6832161eaed", "0x0200c29006150606b650577bbe7b6248f58470c1", ]; const fetch = async (options: FetchOptions) => { const dailyFees = await addTokensReceived({ options, tokens: INK_TOKENS, targets: [TREASURY], }); const dailyVolume = options.createBalances(); const feeEntries = dailyFees.getBalances(); for (const [token, amount] of Object.entries(feeEntries)) { dailyVolume.add(token, BigInt(amount) * BigInt(10000) / BigInt(FEE_BPS)); } return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const methodology = { Volume: "Aggregated swap volume on Ink L2, back-calculated from the 0.05% integrator fee collected by the TideSwap treasury on 0x-routed swaps.", Fees: "TideSwap charges a 0.05% integrator fee on swaps routed through 0x. LI.FI-routed swaps have no TideSwap fee.", Revenue: "100% of fees go to the TideSwap treasury (Gnosis Safe).", ProtocolRevenue: "All revenue is protocol revenue.", }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, chains: [CHAIN.INK], fetch, start: "2025-02-22", methodology, doublecounted: true }; export default adapter; ================================================ FILE: aggregators/titan/index.ts ================================================ import { Adapter, FetchV2 } from "../../adapters/types"; import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; const statisticsEndpoint = "https://api.titan.tg/v1/statistics" const fetch: FetchV2 = async ({ fromTimestamp, toTimestamp }) => { const statistics = await httpGet(statisticsEndpoint, { params: { start: fromTimestamp, end: toTimestamp, } }) return { dailyVolume: statistics?.volumeUsd, }; } const adapter: Adapter = { version: 2, adapter: { [CHAIN.TON]: { fetch, start: '2024-10-30', }, }, deadFrom: "2026-02-28", } export default adapter; ================================================ FILE: aggregators/titan-exchange/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; const API_URL = "https://titan.exchange/public/hourly-volume"; //https://dune.com/queries/5450215/8891846 const badDataDays = [ { date: "2026-04-26", realVolume: 56900000 } ] const fetch = async (_a: any, _b: any, options: FetchOptions) => { const realVolume = badDataDays.find(day => day.date === options.dateString)?.realVolume; if (realVolume) { return { dailyVolume: realVolume }; } const url = `${API_URL}?start_timestamp=${options.startTimestamp}&end_timestamp=${options.endTimestamp}`; const result = await fetchURL(url); // Sum hourly volumes for the exact timestamp range const totalVolume = result.data.reduce((sum: number, hour: any) => { return sum + Number(hour.volume_usd); }, 0); return { dailyVolume: totalVolume }; }; const adapter: any = { version: 1, fetch, start: '2025-09-18', chains: [CHAIN.SOLANA], }; export default adapter; ================================================ FILE: aggregators/tondiamonds/index.ts ================================================ import { Adapter } from "../../adapters/types"; import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; const statisticsEndpoint = "https://ton.diamonds/api/v2/dex/stats" const fetch = async () => { const statistics = await httpGet(statisticsEndpoint) return { timestamp: Math.floor(new Date(statistics?.data?.yesterday).getTime() / 1000), dailyVolume: statistics?.data?.yesterdayVolume, }; } const adapter: Adapter = { version: 1, adapter: { [CHAIN.TON]: { fetch, runAtCurrTime: true, start: '2024-09-01', }, } } export default adapter; ================================================ FILE: aggregators/udex-agg/index.ts ================================================ import ADDRESSES from '../../helpers/coreAssets.json' import { Chain } from "../../adapters/types"; import { FetchResult, FetchResultV2, FetchV2, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; let abi = ["event Swap(address indexed payer,address indexed payee,address fromToken,address toToken,uint fromAmount,uint receivedAmount)"]; let knownTokens=new Set([ADDRESSES.bsc.WBNB,ADDRESSES.bsc.USDT,ADDRESSES.bsc.USDC]) type IContract = { [c: string | Chain]: string; } const contract: IContract = { [CHAIN.BSC]: '0xfCD555b55AA785d46E8c6e9bBB109b10602c431c', [CHAIN.POLYGON]:'0x464599BDaC77E8e5843D5BbC531EC8aD75d3F7b1', [CHAIN.ETHEREUM]:'0x9556E8ce70ceA3c43e4A6c17ad2FAb258067b058', [CHAIN.BASE]:'0x334F493613c1dD33a364684802fB9C728dfcE1A5', [CHAIN.OP_BNB]:'0x8A3e34e45b76885001aa024d6F35FBAcfDBd9DB0' } const fetch: FetchV2 = async ({ getLogs, createBalances, chain, }): Promise => { const dailyVolume = createBalances(); const logs = (await getLogs({ target: contract[chain], eventAbi: abi[0] })) logs.map((log: any) => { if ( knownTokens.has(log.toToken)){ dailyVolume.add(log.toToken, log.receivedAmount) }else{ dailyVolume.add(log.fromToken, log.fromAmount) } }); return { dailyVolume }; }; const adapter: SimpleAdapter = { adapter: Object.keys(contract).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2024-09-17', }, } }, {}), version: 2, pullHourly: true, }; export default adapter; ================================================ FILE: aggregators/unizen/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; type TChain = { [key: string]: number; }; const CHAINS: TChain = { [CHAIN.ETHEREUM]: 1, [CHAIN.BSC]: 56, [CHAIN.POLYGON]: 137, [CHAIN.AVAX]: 43114, [CHAIN.FANTOM]: 250, [CHAIN.ARBITRUM]: 42161, [CHAIN.OPTIMISM]: 10, [CHAIN.BASE]: 8453, [CHAIN.BERACHAIN]: 80094, [CHAIN.SONIC]: 146, [CHAIN.UNICHAIN]: 130, [CHAIN.BITCOIN]: 0, [CHAIN.BITCOIN_CASH]: 0, [CHAIN.LITECOIN]: 0, [CHAIN.DOGECHAIN]: 0, [CHAIN.COSMOS]: 0, }; interface VolumeReport { volume: number; count: number; reportByChain: { [key: string]: { volume: number; count: number; }; } } function isVolumeReport(data: any): data is VolumeReport { return data && typeof data.reportByChain === 'object'; } const fetch = async (_a: any, _b: any, options: FetchOptions) => { const chainCode = CHAINS[options.chain]; if (!chainCode) { return { dailyVolume: 0, }; } const url = `https://api.zcx.com/private/integrators/report/volumeAndCount/24h`; const data = (await httpGet(url, { headers: { 'User-Agent': 'Mozilla/5.0+(compatible; unizen; exchange)', 'Content-Type': 'application/json', } })); if (!isVolumeReport(data)) throw new Error(`Invalid data structure for chain ${chainCode}: ${JSON.stringify(data)}`); const chainData = data.reportByChain[chainCode]; return { dailyVolume: chainData?.volume || 0, }; }; const adapter: SimpleAdapter = { version: 1, adapter: { ...Object.keys(CHAINS).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, runAtCurrTime: true, start: '2024-10-19', }, }; }, {}), }, }; export default adapter; ================================================ FILE: aggregators/venum/index.ts ================================================ import { Adapter, FetchV2 } from "../../adapters/types"; import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; const volumeEndpoint = "https://api.venum.dev/v1/stats/volume"; const fetch: FetchV2 = async ({ startTimestamp, endTimestamp }) => { const stats = await httpGet(volumeEndpoint, { params: { from: startTimestamp, to: endTimestamp - 1, }, }); if (!stats) { throw new Error('No stats found'); } return { dailyVolume: stats.volumeUsd, }; }; const methodology = { Volume: "Volume routed via the Venum aggregator frontend/API to underlying Solana DEX programs (Orca, Meteora, Raydium, etc). Each swap is recorded server-side only after the transaction is confirmed on-chain (signature verified via /v1/tx/:signature), priced from live pool quotes, deduped by signature, and served from /v1/stats/volume.", }; const adapter: Adapter = { version: 2, fetch, chains: [CHAIN.SOLANA], start: '2026-04-01', methodology, }; export default adapter; ================================================ FILE: aggregators/vetrade/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = 'https://vetrade.vet/api/index/analytics/volumes/'; interface IAPIResponse { date: number; volume_vet: number; volume_usd: number; trade_count: number; last_updated: string; } const fetch = async (_a: any, _b: any, options: FetchOptions): Promise => { const dateString = new Date(options.startOfDay * 1000).toISOString().split('T')[0]; const { volume_usd: dailyVolume }: IAPIResponse = (await fetchURL(`${URL}${dateString}`)); return { dailyVolume, }; } const adapter: SimpleAdapter = { adapter: { [CHAIN.VECHAIN]: { fetch, start: '2025-04-01', }, }, }; export default adapter; ================================================ FILE: aggregators/virtus/index.ts ================================================ import { Adapter, FetchOptions } from '../../adapters/types'; import { httpGet } from '../../utils/fetchURL'; import { CHAIN } from '../../helpers/chains'; import { LifiDiamonds } from '../../helpers/aggregators/lifi'; import { getEnv } from '../../helpers/env'; const BACKEND_BASE = getEnv('VIRTUS_BACKEND_BASE'); const start = '2025-09-03'; const CHAINS: Record = { [CHAIN.ETHEREUM]: { id: 'ethereum' }, [CHAIN.SOLANA]: { id: 'solana' }, [CHAIN.BSC]: { id: 'bsc' }, [CHAIN.SCROLL]: { id: 'scroll' }, [CHAIN.BASE]: { id: 'base' }, [CHAIN.BITCOIN]: { id: 'bitcoin' }, [CHAIN.ARBITRUM]: { id: 'arbitrum' }, [CHAIN.POLYGON]: { id: 'polygon' }, [CHAIN.OPTIMISM]: { id: 'optimism' }, [CHAIN.LINEA]: { id: 'linea' }, [CHAIN.CELO]: { id: 'celo' }, [CHAIN.AVAX]: { id: 'avax' }, [CHAIN.ERA]: { id: 'era' }, [CHAIN.MODE]: { id: 'mode' }, [CHAIN.TRON]: { id: 'tron' }, [CHAIN.ZORA]: { id: 'zora' }, [CHAIN.BLAST]: { id: 'blast' }, [CHAIN.OSMOSIS]: { id: 'osmosis' }, [CHAIN.COSMOS]: { id: 'cosmos' }, [CHAIN.FANTOM]: { id: 'fantom' }, [CHAIN.MOONRIVER]: { id: 'moonriver' }, [CHAIN.TAIKO]: { id: 'taiko' }, [CHAIN.STARKNET]: { id: 'starknet' }, [CHAIN.POLYGON_ZKEVM]: { id: 'polygon_zkevm' }, [CHAIN.SUI]: { id: 'sui' }, [CHAIN.CRONOS]: { id: 'cronos' }, [CHAIN.NOBLE]: { id: 'noble' }, [CHAIN.BOBA]: { id: 'boba' }, [CHAIN.THORCHAIN]: { id: 'thorchain' }, [CHAIN.FUSE]: { id: 'fuse' }, [CHAIN.XDAI]: { id: 'xdai' }, [CHAIN.HARMONY]: { id: 'harmony' }, [CHAIN.MOONBEAM]: { id: 'moonbeam' }, [CHAIN.TERRA]: { id: 'terra' }, [CHAIN.SONIC]: { id: 'sonic' }, [CHAIN.TON]: { id: 'ton' }, [CHAIN.BERACHAIN]: { id: 'berachain' }, [CHAIN.AURORA]: { id: 'aurora' }, [CHAIN.ROOTSTOCK]: { id: 'rsk' }, [CHAIN.KLAYTN]: { id: 'klaytn' }, [CHAIN.KAVA]: { id: 'kava' }, [CHAIN.EVMOS]: { id: 'evmos' }, [CHAIN.OKEXCHAIN]: { id: 'okexchain' }, [CHAIN.FILECOIN]: { id: 'filecoin' }, [CHAIN.CORE]: { id: 'core' }, [CHAIN.KROMA]: { id: 'kroma' }, [CHAIN.XLAYER]: { id: 'xlayer' }, [CHAIN.BITLAYER]: { id: 'btr' }, [CHAIN.MERLIN]: { id: 'merlin' }, [CHAIN.BOB]: { id: 'bob' }, [CHAIN.ZKLINK]: { id: 'zklink' }, [CHAIN.ZETA]: { id: 'zeta' }, [CHAIN.PULSECHAIN]: { id: 'pulse' }, }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const { chain, endTimestamp } = options; const info = CHAINS[chain]; if (!info) return { dailyVolume: 0, timestamp: endTimestamp }; const url = `${BACKEND_BASE}/defillama/volume?chain=${info.id}×tamp=${endTimestamp}`; const res = await httpGet(url) as { dailyVolume: number }; return { dailyVolume: res?.dailyVolume || 0, timestamp: endTimestamp }; }; const CHAINS_UNION: Record = Object.entries(LifiDiamonds).reduce((acc, [chain]: any) => { if (!acc[chain]) acc[chain] = { id: chain.toLowerCase() } as any; return acc; }, { ...CHAINS } as Record); const adapter: Adapter = { version: 1, start, fetch, chains: Object.keys(CHAINS_UNION), }; export default adapter; ================================================ FILE: aggregators/wolfswap/index.ts ================================================ import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const abis = { "Swapped": "event Swapped(uint indexed id, address wallet, address sourceToken, address destinationToken, uint amountOut)", } const contracts: Record = { [CHAIN.POLYGON]: '0x9fB5f7Bc34cEd4dE039405D7bE26CbF1D0a420d9', [CHAIN.CRONOS]: '0xeC68090566397DCC37e54B30Cc264B2d68CF0489', [CHAIN.CRONOS_ZKEVM]: '0x7c39eAcCd16cDAD8BFE05e1874da1BD315DB766F', [CHAIN.BASE]: '0xE6174feAD698da575312ae85020A3224E556f8F9', [CHAIN.AVAX]: '0x643dEB007DfA43c0D7BeA2155E97E61279d9a56F', [CHAIN.SEI]: '0x1AD805e80b59C802f9D8059f904DCA6AC153de30', [CHAIN.BLAST]: '0xb86a6e5702C327c5C051Bf5323Cb2bAb5E628d0c', [CHAIN.SONIC]: '0x222680A4fCcFE131acAf7a26301FC929364a881E', [CHAIN.ABSTRACT]: '0x74bAf6450B8E862Ed8daAE385E12704E4882927A', } const fetch = async ({ createBalances, getLogs, chain }: FetchOptions) => { const dailyVolume = createBalances() const logs = await getLogs({ target: contracts[chain], eventAbi: abis.Swapped, }) logs.forEach((log: any) => { dailyVolume.add(log.destinationToken, log.amountOut) }) return { dailyVolume } }; const adapter: any = { version: 2, adapter: { [CHAIN.POLYGON]: { fetch, start: '2024-03-20', }, [CHAIN.CRONOS]: { fetch, start: '2024-03-24', }, [CHAIN.CRONOS_ZKEVM]: { fetch, start: '2024-06-19', }, [CHAIN.BASE]: { fetch, start: '2024-04-14', }, [CHAIN.AVAX]: { fetch, start: '2024-05-31', }, //[CHAIN.SEI]: { fetch, start: '2024-05-31', }, [CHAIN.BLAST]: { fetch, start: '2024-03-07', }, [CHAIN.SONIC]: { fetch, start: '2024-12-16', }, [CHAIN.ABSTRACT]: { fetch, start: '2025-01-27', }, }, }; export default adapter; ================================================ FILE: aggregators/wowmax/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; const chains = [ CHAIN.ETHEREUM, CHAIN.BSC, CHAIN.BASE, CHAIN.LINEA, CHAIN.SCROLL, CHAIN.CRONOS, CHAIN.MANTA, CHAIN.BLAST, CHAIN.XLAYER, CHAIN.METIS, CHAIN.ARBITRUM, CHAIN.ZETA, CHAIN.SONEIUM, CHAIN.UNIT0, ]; const chainToId: Record = { [CHAIN.ETHEREUM]: 1, [CHAIN.BSC]: 56, [CHAIN.BASE]: 8453, [CHAIN.LINEA]: 59144, [CHAIN.SCROLL]: 534352, [CHAIN.CRONOS]: 25, [CHAIN.MANTA]: 169, [CHAIN.BLAST]: 81457, [CHAIN.METIS]: 1088, [CHAIN.XLAYER]: 196, [CHAIN.ARBITRUM]: 42161, [CHAIN.ZETA]: 7000, [CHAIN.SONEIUM]: 1868, [CHAIN.UNIT0]: 88811, }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const dailyVolume = (await fetchURL(`https://api-gateway.wowmax.exchange/statistics/chains/${chainToId[options.chain]}/volume?timestamp=${options.startOfDay}`))?.volume; return { dailyVolume, }; }; const adapter: any = { adapter: { ...chains.reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2024-01-13', }, }; }, {}), }, }; export default adapter; ================================================ FILE: aggregators/yield-yak/index.ts ================================================ import { FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const routers: any = { [CHAIN.ARBITRUM]: "0xb32C79a25291265eF240Eb32E9faBbc6DcEE3cE3", [CHAIN.AVAX]: "0xC4729E56b831d74bBc18797e0e17A295fA77488c", } const fetch = async ({ createBalances, getLogs, chain, }: FetchOptions) => { const dailyVolume = createBalances() const logs = await getLogs({ target: routers[chain], eventAbi: 'event YakSwap (address indexed _tokenIn, address indexed _tokenOut, uint256 _amountIn, uint256 _amountOut)' }); logs.forEach((log: any) => dailyVolume.add(log._tokenOut, log._amountOut)); return { dailyVolume } }; const adapter: any = { version: 2, adapter: { [CHAIN.AVAX]: { fetch, start: '2023-05-31', }, [CHAIN.ARBITRUM]: { fetch, start: '2023-05-31', }, }, }; export default adapter; ================================================ FILE: aggregators/zrx/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; import { getEnv } from "../../helpers/env"; import { httpGet } from "../../utils/fetchURL"; type TChain = { [key: string]: number; }; const CHAINS: TChain = { [CHAIN.ARBITRUM]: 42161, [CHAIN.AVAX]: 43114, [CHAIN.BASE]: 8453, [CHAIN.BSC]: 56, [CHAIN.ETHEREUM]: 1, [CHAIN.OPTIMISM]: 10, [CHAIN.POLYGON]: 137, // [CHAIN.BLAST]: 81457, [CHAIN.LINEA]: 59144, [CHAIN.SCROLL]: 534352, [CHAIN.MANTLE]: 5000, [CHAIN.MODE]: 34443, [CHAIN.BERACHAIN]: 80094, [CHAIN.INK]: 57073, [CHAIN.UNICHAIN]: 130, [CHAIN.WC]: 480, [CHAIN.PLASMA]: 9745, [CHAIN.SONIC]: 146, [CHAIN.MONAD]: 143, [CHAIN.HYPERLIQUID]: 999, [CHAIN.ABSTRACT]: 2741, [CHAIN.TEMPO]: 4217, }; const inflatedVolume: Record> = { [CHAIN.ETHEREUM]: ["2026-03-02", "2026-03-22"], [CHAIN.BASE]: ["2026-05-02"], } const fetch = async (_a: any, _b: any, options: FetchOptions) => { const response= await httpGet(`https://api.0x.org/stats/volume/daily?timestamp=${options.startOfDay}&chainId=${CHAINS[options.chain]}`, { headers: { "0x-api-key": getEnv("AGGREGATOR_0X_API_KEY") } }) let dailyVolume = 0; if (!inflatedVolume[options.chain] || !inflatedVolume[options.chain].includes(options.dateString)) dailyVolume = response.data.volume; return { dailyVolume, } }; const adapter: any = { version: 1, adapter: Object.keys(CHAINS).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: fetch, start: '2022-05-17', }, }; }, {}), }; export default adapter; ================================================ FILE: bridge-aggregators/GUIDELINES.md ================================================ # Bridge Aggregator Guidelines These guidelines apply to all adapters in the `bridge-aggregators/` directory. ## Required Dimensions | Dimension | Required | Description | |-----------|----------|-------------| | `dailyBridgeVolume` | YES | Bridge volume for the period | ## What is a Bridge Aggregator? Bridge aggregators route cross-chain transfers through multiple bridges to find optimal routes, fees, and speed. ## Volume Calculation - Track volume ROUTED through the bridge aggregator - Include all cross-chain transfers facilitated - Volume should reflect the value being bridged, not fees ## Data Sources 1. **On-chain logs** - Track bridge initiation/completion events 2. **Multi-chain indexing** - Required for tracking both source and destination 3. **Aggregator APIs** - When on-chain tracking across chains is complex ## Example Implementation ```typescript const fetch = async (options: FetchOptions) => { const dailyBridgeVolume = options.createBalances(); const logs = await options.getLogs({ target: BRIDGE_AGGREGATOR, eventAbi: 'event BridgeInitiated(address token, uint256 amount, uint256 destChainId)' }); logs.forEach(log => { dailyBridgeVolume.add(log.token, log.amount); }); return { dailyBridgeVolume }; }; ``` ## Fees/Revenue Tracking If the bridge aggregator charges fees and this adapter returns fee/revenue dimensions, follow the guidelines in `fees/GUIDELINES.md`. Include: - `dailyFees` - All fees collected (bridge fees, relayer fees) - `dailyRevenue` - Aggregator's portion - `dailySupplySideRevenue` - Relayer/partner fees ## Common Mistakes to Avoid 1. Double-counting with underlying bridge adapters 2. Not tracking volume on all source chains 3. Counting failed/reverted bridge attempts 4. Missing multi-hop bridge routes 5. Confusing bridge volume with swap volume (if aggregator also does swaps) ================================================ FILE: bridge-aggregators/babydoge-bridge/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { httpGet } from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; const API_BASE = "https://axelar-bridge-connector-backend-main.babybulldog.xyz/lama-api"; const API_TON = "https://defillama-bsc-ton-bridge-backend-main.babybulldog.xyz"; const API_SOL = "https://wormhole-bridge-defilama-connector-backend-main.babybulldog.xyz"; const chainIds: Record = { [CHAIN.BSC]: "56", [CHAIN.SOLANA]: "sol_mainnet_beta", [CHAIN.BASE]: "8453", [CHAIN.TON]: "ton_0", }; const apis: Record = { [CHAIN.BSC]: [API_BASE, API_TON, API_SOL], [CHAIN.SOLANA]: [API_SOL], [CHAIN.BASE]: [API_BASE], [CHAIN.TON]: [API_TON], }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const chainId = chainIds[options.chain]; const apiList = apis[options.chain]; let dailyBridgeVolume = 0; for (const api of apiList) { const data = await httpGet(`${api}/volume?chain_id=${chainId}`); dailyBridgeVolume += data.dailyVolume || 0; } return { dailyBridgeVolume, }; }; const adapter: SimpleAdapter = { version: 1, fetch, runAtCurrTime: true, adapter: { [CHAIN.BSC]: { start: "2024-01-01" }, [CHAIN.SOLANA]: { start: "2024-01-01" }, [CHAIN.TON]: { start: "2024-01-01" }, [CHAIN.BASE]: { start: "2024-01-01" }, }, }; export default adapter; ================================================ FILE: bridge-aggregators/bim/index.ts ================================================ import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { fetchBungeeData } from "../../helpers/aggregators/bungee"; import { fetchBimChains } from "../../aggregators/bim/config"; const fetch: any = async (options: FetchOptions): Promise => { const { dailyBridgeVolume } = await fetchBungeeData(options, { bridgeVolume: true }, '2758') return { dailyBridgeVolume, }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, doublecounted: true, //Bungee adapter: fetchBimChains().reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2026-01-13', } } }, {}) }; export default adapter; ================================================ FILE: bridge-aggregators/bitgetwallet/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import fetchURL from "../../utils/fetchURL"; const CHAINS: Array = [ CHAIN.APTOS, CHAIN.HYPERLIQUID, CHAIN.SOLANA, CHAIN.BLAST, CHAIN.BITCOIN, CHAIN.ARBITRUM, CHAIN.KLAYTN, CHAIN.SONIC, CHAIN.MANTLE, CHAIN.RIPPLE, CHAIN.AVAX, CHAIN.LINEA, CHAIN.SUI, CHAIN.SCROLL, CHAIN.BASE, CHAIN.POLYGON, CHAIN.TON, CHAIN.CRONOS, CHAIN.DOGECHAIN, CHAIN.BERACHAIN, CHAIN.MONAD, CHAIN.TRON, CHAIN.CELO, CHAIN.BSC, CHAIN.MORPH, CHAIN.XLAYER, CHAIN.CORE, CHAIN.OP_BNB, CHAIN.ZKSYNC, CHAIN.ETHEREUM, CHAIN.OPTIMISM, CHAIN.FANTOM, CHAIN.PLASMA, CHAIN.SEI ]; interface IVolumeBridge { volume: string; date: string; } async function queryDataByApi(path: string) { const historicalVolumeEndpoint = "https://api-3rd.bitkeep.com/swap-go/open"; let info = await fetchURL(`${historicalVolumeEndpoint}${path}`); const data: IVolumeBridge[] = (info)?.data?.list || []; return data } const fetch = async (_a: any, _b: any, options: FetchOptions) => { const path = `/getOrderDayVolume?bridge=1&chain=${options.chain}×tamp=${options.startOfDay}` const data = await queryDataByApi(path) const dateString = new Date(options.startOfDay * 1000).toISOString().split("T")[0]; const dailyVolume = data.find(dayItem => dayItem.date === dateString)?.volume return { dailyBridgeVolume: dailyVolume || 0, }; }; const adapter: SimpleAdapter = { version: 1, fetch, chains: CHAINS, start: '2025-08-01', }; export default adapter; ================================================ FILE: bridge-aggregators/brotocol/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; interface ApiResponse { day: string; volume: number; } const chains: Record = { [CHAIN.AILAYER]: 'AILayer', [CHAIN.ARBITRUM]: 'Arbitrum', [CHAIN.AURORA]: 'Aurora', [CHAIN.AVAX]: 'AVAX', [CHAIN.BASE]: 'Base', [CHAIN.BITCOIN]: 'Bitcoin', [CHAIN.BITLAYER]: 'Bitlayer', [CHAIN.BSC]: 'BNB', [CHAIN.BOB]: 'BOB', [CHAIN.BSQUARED]: 'Bsquared', [CHAIN.CORE]: 'CORE', [CHAIN.ETHEREUM]: 'Ethereum', [CHAIN.LINEA]: 'Linea', [CHAIN.MANTA]: 'Manta', [CHAIN.MERLIN]: 'Merlin', [CHAIN.MEZO]: 'Mezo', [CHAIN.MODE]: 'MODE', [CHAIN.SOLANA]: 'Solana', [CHAIN.STACKS]: 'Stacks', [CHAIN.XLAYER]: 'Xlayer', // dead chains // [CHAIN.LORENZO]: 'Lorenzo', // [CHAIN.RUNES]: 'Runes', // [CHAIN.BRC20]: 'BRC20', }; const api = "https://api.brotocol.xyz/v1/xlink/bridge-chain-volume-by-day" const fetch = async (_a: any, _b: any, options: FetchOptions) => { const dateStr = new Date(options.startOfDay * 1000).toISOString().split('T')[0] const data: ApiResponse = await fetchURL(`${api}?day=${dateStr}&chain=${chains[options.chain]}`) return { dailyBridgeVolume: data.volume } } const adapter: SimpleAdapter = { adapter: { ...Object.entries(chains).reduce((acc, chain) => { const [key, _] = chain; return { ...acc, [key]: { fetch, runAtCurrTime: true, // start: "2023-04-17", }, }; }, {}), }, }; export default adapter; ================================================ FILE: bridge-aggregators/bungee-bridge/index.ts ================================================ import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { fetchBungeeChains, fetchBungeeData } from "../../helpers/aggregators/bungee"; const fetch: any = async (options: FetchOptions): Promise => { const { dailyBridgeVolume } = await fetchBungeeData(options, { bridgeVolume: true }) return { dailyBridgeVolume, }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: fetchBungeeChains().reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2023-08-10', } } }, {}) }; export default adapter; ================================================ FILE: bridge-aggregators/dzap/index.ts ================================================ import { FetchOptions, FetchResultV2, SimpleAdapter } from "../../adapters/types"; import { DZAP_SUPPORTED_CHAINS, fetchChainWiseVolumeFromDZapAPI } from "../../helpers/aggregators/dzap"; const prefetch = async (options: FetchOptions): Promise => fetchChainWiseVolumeFromDZapAPI({ ...options, txType: "bridge" }); const fetch = async (_a: any, _b: any, options: FetchOptions) => { const volume = options.preFetchedResults[options.chain] ?? 0; return { dailyBridgeVolume: volume, }; }; const adapter: SimpleAdapter = { version: 1, fetch, chains: Object.values(DZAP_SUPPORTED_CHAINS), start: "2023-01-01", prefetch, }; export default adapter; ================================================ FILE: bridge-aggregators/garden/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const chainMapper: Record = { [CHAIN.ETHEREUM]: { name: "ethereum", start: "2023-08-23", primaryCGToken: 'ethereum', decimals: 18 }, [CHAIN.BITCOIN]: { name: "bitcoin", start: "2023-08-23", primaryCGToken: 'bitcoin', decimals: 8 }, [CHAIN.ARBITRUM]: { name: "arbitrum", start: "2023-08-23", primaryCGToken: 'ethereum', decimals: 18 }, [CHAIN.BASE]: { name: "base", start: "2024-12-11", primaryCGToken: 'ethereum', decimals: 18 }, [CHAIN.UNICHAIN]: { name: "unichain", start: "2025-04-17", primaryCGToken: 'ethereum', decimals: 18 }, [CHAIN.BERACHAIN]: { name: "bera", start: "2025-02-10", primaryCGToken: 'ethereum', decimals: 18 }, [CHAIN.STARKNET]: { name: "starknet", start: "2023-08-23", primaryCGToken: 'starknet', decimals: 18 }, [CHAIN.HYPERLIQUID]: { name: "hyperliquid", start: "2025-04-17", primaryCGToken: 'hyperliquid', decimals: 18 }, [CHAIN.BSC]: { name: "bnbchain", start: "2025-07-28", primaryCGToken: 'binancecoin', decimals: 18 }, [CHAIN.CORN]: { name: "corn", start: "2025-03-30", primaryCGToken: 'corn-3', decimals: 18 }, [CHAIN.SUI]: { name: "sui", start: "2025-08-14", primaryCGToken: 'sui', decimals: 9 }, [CHAIN.SOLANA]: { name: "solana", start: "2025-08-07", primaryCGToken: 'solana', decimals: 9 }, [CHAIN.MONAD]: { name: "monad", start: "2025-11-24", primaryCGToken: 'monad', decimals: 18 }, }; const baseUrl = "https://api.garden.finance/orders"; type SwapDetails = { chain: string; filled_amount: string; token_address: string; initiate_timestamp: string; }; type GardenTransaction = { created_at: string; source_swap: SwapDetails; destination_swap: SwapDetails; }; type GardenApiResponse = { status: string; result: { data: GardenTransaction[]; page: number; total_pages: number; total_items: number; per_page: number; }; }; type ChainVolumes = { [chain: string]: { [tokenAddress: string]: string; }; }; type VolumeCounters = { sameChain: ChainVolumes; crossChain: ChainVolumes; }; function addToVolume(volumes: ChainVolumes, chain: string, tokenAddress: string, amount: string) { if (!volumes[chain]) { volumes[chain] = {}; } if (!volumes[chain][tokenAddress]) { volumes[chain][tokenAddress] = "0"; } volumes[chain][tokenAddress] = ( Number(volumes[chain][tokenAddress]) + Number(amount) ).toString(); } const prefetch = async (options: FetchOptions) => { return await fetchTransactionsInDateRange( options.startTimestamp, options.endTimestamp ); } async function fetchTransactionsInDateRange(startTimestamp: number, endTimestamp: number) { const volumes = { sameChain: {}, crossChain: {} }; let currentPage = 1; let insideDateRange = false; let shouldContinue = true; while (shouldContinue) { const response: GardenApiResponse = await fetchURL( `${baseUrl}/matched?page=${currentPage}&per_page=200&status=completed` ); if (response.status !== "Ok" || !response.result.data.length) { break; } for (const tx of response.result.data) { const txTimestamp = new Date(tx.created_at).getTime() / 1000; if (!insideDateRange && txTimestamp > endTimestamp) { continue; } if (txTimestamp <= endTimestamp && txTimestamp >= startTimestamp) { if (!insideDateRange) { insideDateRange = true; } const { source_swap, destination_swap } = tx; addToVolume( source_swap.chain === destination_swap.chain ? volumes.sameChain : volumes.crossChain, source_swap.chain, source_swap.token_address, source_swap.filled_amount ); } if (insideDateRange && txTimestamp < startTimestamp) { shouldContinue = false; break; } } if (shouldContinue && currentPage < response.result.total_pages) { currentPage++; } else { break; } } return volumes; } const fetch = async (options: FetchOptions) => { const volumes = options.preFetchedResults as VolumeCounters || { sameChain: {}, crossChain: {} }; const dailyBridgeVolume = options.createBalances(); const chainName = chainMapper[options.chain].name; const crossChainVolumes = volumes.crossChain[chainName] || {}; for (const [tokenAddress, volume] of Object.entries(crossChainVolumes)) { if (tokenAddress === 'primary') { dailyBridgeVolume.addCGToken(chainMapper[options.chain].primaryCGToken, Number(volume) / 10 ** chainMapper[options.chain].decimals) } else { dailyBridgeVolume.add(tokenAddress, volume); } } return { dailyBridgeVolume, }; }; const adapter: SimpleAdapter = { version: 2, fetch, adapter: chainMapper, prefetch: prefetch as any }; export default adapter; ================================================ FILE: bridge-aggregators/jumper.exchange/index.ts ================================================ import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { LifiDiamonds, fetchVolumeFromLIFIAPI } from "../../helpers/aggregators/lifi"; import { CHAIN } from "../../helpers/chains"; const LifiBridgeEvent = "event LiFiTransferStarted((bytes32 transactionId, string bridge, string integrator, address referrer, address sendingAssetId, address receiver, uint256 minAmount, uint256 destinationChainId, bool hasSourceSwaps, bool hasDestinationCall) bridgeData)" const integrators = ['jumper.exchange', 'transferto.xyz', 'jumper.exchange.gas','lifi-gasless-jumper'] const fetch: any = async (options: FetchOptions): Promise => { if (options.chain === CHAIN.BITCOIN || options.chain === CHAIN.SOLANA) { const dailyVolume = await fetchVolumeFromLIFIAPI(options.chain, options.startTimestamp, options.endTimestamp, integrators, [], 'cross-chain'); return { dailyBridgeVolume: dailyVolume }; } const dailyVolume = options.createBalances(); const logs: any[] = await options.getLogs({ target: LifiDiamonds[options.chain].id, topic: '0xcba69f43792f9f399347222505213b55af8e0b0b54b893085c2e27ecbe1644f1', eventAbi: LifiBridgeEvent, }); logs.forEach((e: any) => { const { bridgeData: { integrator, sendingAssetId, minAmount } } = e; if (integrators.includes(integrator)) { dailyVolume.add(sendingAssetId, minAmount); } }); return { dailyBridgeVolume: dailyVolume } as any; }; const adapter: SimpleAdapter = { version: 2, adapter: Object.keys(LifiDiamonds).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: LifiDiamonds[chain].startTime, } } }, {}) }; export default adapter; ================================================ FILE: bridge-aggregators/lifi/index.ts ================================================ import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { fetchVolumeFromLIFIAPI, LifiDiamonds } from "../../helpers/aggregators/lifi"; const LifiBridgeEvent = "event LiFiTransferStarted((bytes32 transactionId, string bridge, string integrator, address referrer, address sendingAssetId, address receiver, uint256 minAmount, uint256 destinationChainId, bool hasSourceSwaps, bool hasDestinationCall) bridgeData)" const exclude_integrators = ['jumper.exchange', 'transferto.xyz', 'jumper.exchange.gas', 'lifi-gasless-jumper'] const fetch: any = async (options: FetchOptions): Promise => { if (options.chain === CHAIN.BITCOIN || options.chain === CHAIN.SOLANA) { const dailyVolume = await fetchVolumeFromLIFIAPI(options.chain, options.startTimestamp, options.endTimestamp, [], exclude_integrators, 'cross-chain'); return { dailyBridgeVolume: dailyVolume }; } const dailyVolume = options.createBalances(); const logs: any[] = await options.getLogs({ target: LifiDiamonds[options.chain].id, topic: '0xcba69f43792f9f399347222505213b55af8e0b0b54b893085c2e27ecbe1644f1', eventAbi: LifiBridgeEvent, }); logs.forEach((e: any) => { const { bridgeData: { integrator, sendingAssetId, minAmount } } = e; if (!exclude_integrators.includes(integrator)) { dailyVolume.add(sendingAssetId, minAmount); } }); return { dailyBridgeVolume: dailyVolume } as any; }; const adapter: SimpleAdapter = { version: 2, adapter: Object.keys(LifiDiamonds).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: LifiDiamonds[chain].startTime, } } }, {}) }; export default adapter; ================================================ FILE: bridge-aggregators/lunar-finance-bridge/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const LUNA_API_BASE = "https://api.lunarfinance.io"; const BRIDGE_ANALYTICS_ENDPOINT = `${LUNA_API_BASE}/api/analytics/bridge`; interface LunaAnalyticsResponse { success: boolean; data: { dailyBridgeVolume?: { usd: string; }; dailyFees?: { usd: string; }; dailyRevenue?: { usd: string; }; }; } const fetch = async (options: FetchOptions) => { const url = `${BRIDGE_ANALYTICS_ENDPOINT}?startTime=${options.startTimestamp + 1}&endTime=${options.endTimestamp}`; const data: LunaAnalyticsResponse = await fetchURL(url); const { dailyBridgeVolume, dailyFees, dailyRevenue } = data.data; return { dailyBridgeVolume: Number(dailyBridgeVolume?.usd) / 1e18 || 0, dailyFees: Number(dailyFees?.usd) / 1e18 || 0, dailyRevenue: Number(dailyRevenue?.usd) / 1e18 || 0, dailyProtocolRevenue: Number(dailyRevenue?.usd) / 1e18 || 0, }; }; const adapter: SimpleAdapter = { version: 2, chains: [CHAIN.SOLANA], fetch, start: '2025-05-01', methodology: { Fees: "Bridge fees include protocol fees charged by Luna Finance plus underlying bridge protocol fees paid by users.", Revenue: "Revenue represents fees collected by Luna Finance protocol from bridge transactions, typically 0.1-0.5% of transaction value.", ProtocolRevenue: "Protocol revenue is the portion of fees that goes to Luna Finance treasury.", } }; export default adapter; ================================================ FILE: bridge-aggregators/mynth/index.ts ================================================ import BigNumber from "bignumber.js"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; type Transfer = { amount: string; from: { blockchain: string; decimals: number; token: string; }; to: { blockchain: string; }; }; type NovaApiResponse = { contents: { transfers: Transfer[]; }; }; const prefetch = async (options: FetchOptions) => { const baseUrl = "https://api.novaswap.io/liquidity/transfers"; const end = options.toTimestamp * 1000; const start = options.fromTimestamp * 1000; const fetched: string[] = []; const transfers: Transfer[] = []; const limit = 1000; for (let page = 1; ; page++) { const url = `${baseUrl}?start=${start}&end=${end}&limit=${limit}&page=${page}`; const response: NovaApiResponse = await fetchURL(url); transfers.push(...response.contents.transfers); if (response.contents.transfers.length < limit) break; } for (const transfer of transfers) { if (transfer.from.blockchain === transfer.to.blockchain) continue; const chain = transfer.from.blockchain; const decimals = transfer.from.decimals; const token = transfer.from.token; const amount = new BigNumber(transfer.amount) .shiftedBy(decimals) .toFixed(0, BigNumber.ROUND_FLOOR); fetched.push(`${chain};${token};${amount}`); } return Object.fromEntries(fetched.map((v, i) => [i, v])); }; type PrefetchResults = Awaited>; const fetch = async (options: FetchOptions) => { const fetched = options.preFetchedResults as PrefetchResults; const dailyBridgeVolume = options.createBalances(); for (const value of Object.values(fetched)) { const [blockchain, token, amount] = value.split(";"); if (blockchain !== options.chain) continue; dailyBridgeVolume.add(token, amount); } return { dailyBridgeVolume }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, chains: [ CHAIN.ARBITRUM, CHAIN.BASE, CHAIN.CARDANO, CHAIN.ETHEREUM, CHAIN.HEMI, CHAIN.HYPERLIQUID, CHAIN.PLASMA, CHAIN.POLYGON, CHAIN.SOLANA, CHAIN.STABLE, CHAIN.SUI, CHAIN.TRON, ], fetch, methodology: { BridgeVolume: "Sum of token amounts bridged for the period, per origin chain. We count all cross-chain transfers where origin and receiving chains are different.", }, prefetch, start: "2025-06-20", }; export default adapter; ================================================ FILE: bridge-aggregators/okx/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; import { getEnv } from "../../helpers/env"; import axios from "axios"; import { createHmac } from "crypto"; import asyncRetry from "async-retry"; const plimit = require('p-limit'); const limits = plimit(1); type TChain = { [key: string]: number; }; const CHAINS: TChain = { [CHAIN.ETHEREUM]: 1, [CHAIN.BSC]: 56, [CHAIN.OKEXCHAIN]: 66, [CHAIN.POLYGON]: 137, [CHAIN.TRON]: 195, [CHAIN.AVAX]: 43114, [CHAIN.FANTOM]: 250, [CHAIN.ARBITRUM]: 42161, [CHAIN.OPTIMISM]: 10, [CHAIN.CRONOS]: 25, [CHAIN.SOLANA]: 501, // [CHAIN.OSMOSIS]: 706, // 10001, "EthereumPoW" // [CHAIN.APTOS]: 637, //[CHAIN.FLARE]: 14, // broken [CHAIN.ERA]: 324, // [CHAIN.CONFLUX]: 1030, // Conflux eSpace [CHAIN.SUI]: 784, //[CHAIN.BITCOIN]: 0, // broken [CHAIN.POLYGON_ZKEVM]: 1101, // [CHAIN.SEI]: 70000029, [CHAIN.LINEA]: 59144, [CHAIN.MANTLE]: 5000, [CHAIN.BASE]: 8453, // [CHAIN.STACKS]: 5757, [CHAIN.STARKNET]: 9004, [CHAIN.SCROLL]: 534352, [CHAIN.XLAYER]: 196, [CHAIN.MANTA]: 169, [CHAIN.METIS]: 1088, [CHAIN.ZETA]: 7000, [CHAIN.MERLIN]: 4200, [CHAIN.BLAST]: 81457, [CHAIN.MODE]: 34443, [CHAIN.TON]: 607, }; const sleep = (ms: number) => new Promise(r => setTimeout(r, ms)); async function queryOkxApi(timestamp:string, path:string){ const [secretKey, passphrase] = getEnv("OKX_API_KEY").split(":") const data = await asyncRetry( async () => { const response = await axios.get(`https://www.okx.com${path}`, { headers: { 'OK-ACCESS-PROJECT': 'be0ee327bbc230c3977c6868a77cd894', 'OK-ACCESS-KEY': 'feb1a319-69e0-4c00-96df-d1188d8a616a', 'OK-ACCESS-SIGN': createHmac('sha256', secretKey) .update(timestamp + 'GET' + path) .digest('base64'), 'OK-ACCESS-PASSPHRASE': passphrase, 'OK-ACCESS-TIMESTAMP': timestamp } }); if (response.data?.data?.volumeUsdLast24hour) { return response.data.data.volumeUsdLast24hour; } else { throw new Error(`Invalid response: no volumeUsdLast24hour found. Response: ${JSON.stringify(response.data)}`); } }, { retries: 3, minTimeout: 1000, maxTimeout: 5000, factor: 2, } ); await sleep(200) return data } const fetch = async (_timestampParam: number, block: any, options: FetchOptions) => { const timestamp = new Date().toISOString() const path = `/api/v5/dex/cross-chain/volume?timestamp=${options.endTimestamp * 1e3}&chainId=${CHAINS[options.chain]}` const dailyBridgeVolume = await limits(() => queryOkxApi(timestamp, path)) return { dailyBridgeVolume, timestamp: options.endTimestamp, }; }; const adapter: any = { version: 1, // api supports other timestamps but if you try using current timestamps, it breaks, so sticking to v1 even though it should be able to support v2 adapter: Object.keys(CHAINS).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2022-05-17', }, }; }, {}), }; export default adapter; ================================================ FILE: bridge-aggregators/opensea/index.ts ================================================ import { Dependencies, FetchOptions } from "../../adapters/types"; import { queryDuneSql } from "../../helpers/dune"; import { CHAIN } from "../../helpers/chains"; import { SimpleAdapter } from "../../adapters/types"; const chainConfig: Record = { [CHAIN.ETHEREUM]: {dune_chain: 'ethereum'}, // [CHAIN.ABSTRACT]: {dune_chain: 'abstract'}, [CHAIN.APECHAIN]: {dune_chain: 'apechain'}, [CHAIN.ARBITRUM]: {dune_chain: 'arbitrum'}, [CHAIN.AVAX]: {dune_chain: 'avalanche_c'}, [CHAIN.BLAST]: {dune_chain: 'blast'}, [CHAIN.BASE]: {dune_chain: 'base'}, [CHAIN.BERACHAIN]: {dune_chain: 'berachain'}, // [CHAIN.FLOW]: {dune_chain: 'flow'}, [CHAIN.OPTIMISM]: {dune_chain: 'optimism'}, [CHAIN.POLYGON]: {dune_chain: 'polygon'}, // [CHAIN.SEI]: {dune_chain: 'sei'}, [CHAIN.UNICHAIN]: {dune_chain: 'unichain'}, // [CHAIN.ZORA]: {dune_chain: 'zora'}, [CHAIN.MONAD]: {dune_chain: 'monad'}, } const prefetch = async (options: FetchOptions) => { return await queryDuneSql(options, ` WITH opensea_txs AS ( SELECT DISTINCT tx.hash, tx.blockchain FROM evms.transactions tx WHERE varbinary_substring(tx.data, varbinary_length(tx.data) - 3, 4) = from_hex('865d8597') AND tx.block_time >= FROM_UNIXTIME(${options.startTimestamp}) AND tx.block_time <= FROM_UNIXTIME(${options.endTimestamp}) ), dex_txs AS ( SELECT DISTINCT tx_hash FROM dex_aggregator.trades WHERE block_time >= FROM_UNIXTIME(${options.startTimestamp}) AND block_time <= FROM_UNIXTIME(${options.endTimestamp}) ), filtered_bridge_txs AS ( SELECT os.hash, os.blockchain FROM opensea_txs os WHERE NOT EXISTS ( SELECT 1 FROM dex_txs dt WHERE dt.tx_hash = os.hash ) ) SELECT t.blockchain, SUM(t.amount_usd) as dailyBridgeVolume FROM tokens.transfers t INNER JOIN filtered_bridge_txs fb ON t.tx_hash = fb.hash WHERE t.block_time >= FROM_UNIXTIME(${options.startTimestamp}) AND t.block_time <= FROM_UNIXTIME(${options.endTimestamp}) GROUP BY 1 `); }; const fetch = async (_a:any, _b:any, options: FetchOptions) => { const results: Array = options.preFetchedResults || []; const chainData = results.find( (item) => chainConfig[options.chain].dune_chain === item.blockchain ); return { dailyBridgeVolume: chainData?.dailyBridgeVolume || 0, } } const adapter: SimpleAdapter = { version: 1, fetch, dependencies: [Dependencies.DUNE], chains: Object.keys(chainConfig), prefetch, doublecounted: true } export default adapter; ================================================ FILE: bridge-aggregators/orbiter-finance/index.ts ================================================ import type { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const DEFAULT_AGGREGATOR = '0xe530d28960d48708ccf3e62aa7b42a80bc427aef' const SWAP_ROUTER: Record = { [CHAIN.UNICHAIN]: '0x70f6060fc8b01b56869feba8361df468f98c2900', } const bridgeEvent = "event BridgeExecuted(address indexed sender, address indexed recipient, address inputToken, address outputToken, uint256 inputAmount, bytes extData)"; const fetch = async (options: FetchOptions) => { const dailyBridgeVolume = options.createBalances(); const target = SWAP_ROUTER[options.chain] || DEFAULT_AGGREGATOR; const logs = await options.getLogs({ target, eventAbi: bridgeEvent, }); for (const l of logs) { dailyBridgeVolume.add(l.inputToken, l.inputAmount); } return { dailyBridgeVolume }; } const adapter: SimpleAdapter = { version: 2, fetch, chains: [CHAIN.ETHEREUM, CHAIN.ARBITRUM, CHAIN.HEMI, CHAIN.POLYGON, CHAIN.OPTIMISM, CHAIN.BSC, CHAIN.BASE, CHAIN.SCROLL, CHAIN.LINEA, CHAIN.UNICHAIN, CHAIN.BERACHAIN, CHAIN.SONIC, CHAIN.INK, CHAIN.BLAST, CHAIN.POLYGON_ZKEVM, CHAIN.SCROLL, CHAIN.MANTLE, CHAIN.MODE, CHAIN.FRAXTAL, CHAIN.FUSE, CHAIN.GRAVITY, CHAIN.WC, CHAIN.SONEIUM, CHAIN.CELO] }; export default adapter; ================================================ FILE: bridge-aggregators/rango/index.ts ================================================ import { Adapter, FetchOptions } from '../../adapters/types'; import { httpGet } from '../../utils/fetchURL'; import { CHAIN } from '../../helpers/chains'; const RangoChains: Record = { [CHAIN.ETHEREUM]: 'ETH', [CHAIN.SOLANA]: 'SOLANA', [CHAIN.BSC]: 'BSC', [CHAIN.SCROLL]: 'SCROLL', [CHAIN.BASE]: 'BASE', [CHAIN.BITCOIN]: 'BTC', [CHAIN.ARBITRUM]: 'ARBITRUM', [CHAIN.POLYGON]: 'POLYGON', [CHAIN.OPTIMISM]: 'OPTIMISM', [CHAIN.LINEA]: 'LINEA', [CHAIN.CELO]: 'CELO', [CHAIN.AVAX]: 'AVAX_CCHAIN', [CHAIN.ERA]: 'ZKSYNC', [CHAIN.MODE]: 'MODE', [CHAIN.TRON]: 'TRON', [CHAIN.ZORA]: 'ZORA', [CHAIN.BLAST]: 'BLAST', [CHAIN.OSMOSIS]: 'OSMOSIS', [CHAIN.COSMOS]: 'COSMOS', [CHAIN.FANTOM]: 'FANTOM', [CHAIN.MOONRIVER]: 'MOONRIVER', [CHAIN.TAIKO]: 'TAIKO', [CHAIN.STARKNET]: 'STARKNET', [CHAIN.POLYGON_ZKEVM]: 'POLYGONZK', [CHAIN.SUI]: 'SUI', [CHAIN.CRONOS]: 'CRONOS', [CHAIN.NOBLE]: 'NOBLE', [CHAIN.BOBA]: 'BOBA', [CHAIN.THORCHAIN]: 'THOR', [CHAIN.FUSE]: 'FUSE', [CHAIN.XDAI]: 'GNOSIS', [CHAIN.HARMONY]: 'HARMONY', [CHAIN.MOONBEAM]: 'MOONBEAM', [CHAIN.TERRA]: 'TERRA', [CHAIN.SONIC]: 'SONIC', [CHAIN.TON]: 'TON', [CHAIN.BERACHAIN]: 'BERACHAIN', [CHAIN.AURORA]: 'AURORA', [CHAIN.RIPPLE]: 'XRPL', [CHAIN.HYPERLIQUID]: 'HYPERLIQUID', [CHAIN.MONAD]: 'MONAD', [CHAIN.UNICHAIN]: 'UNICHAIN', [CHAIN.SONEIUM]: 'SONEIUM', [CHAIN.KATANA]: 'KATANA', [CHAIN.PLASMA]: 'PLASMA' }; const fetch: any = async (timestamp: number, _: any, options: FetchOptions) => { const prefetchData = options.preFetchedResults let dailyVolume = 0 const date = new Date(timestamp * 1000).toISOString().split('T')[0]; for (const item of prefetchData) { const itemDate = item.date.split('T')[0]; if (date === itemDate && item.bucket === RangoChains[options.chain]) { dailyVolume = Number(item.volume); } } return { dailyBridgeVolume: dailyVolume, } } const prefetch = async (_: FetchOptions) => { const data = await httpGet('https://api.rango.exchange/scanner/summary/daily?days=10000&breakDownBy=SOURCE&apiKey=4a624ab5-16ff-4f96-90b7-ab00ddfc342c&txType=BRIDGE'); return data.stats; } const chainAdapter = { fetch, start: '2021-08-04' } const adapter: Adapter = { adapter: Object.fromEntries(Object.entries(RangoChains).map( ([chain]) => [chain, chainAdapter] )), prefetch: prefetch, } export default adapter; ================================================ FILE: bridge-aggregators/rubic/index.ts ================================================ import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const chains: Record = { [CHAIN.SOLANA]: 'solana', [CHAIN.ETHEREUM]: 'ethereum', [CHAIN.BSC]: 'binance-smart-chain', [CHAIN.AVAX]: 'avalanche', [CHAIN.POLYGON]: 'polygon', [CHAIN.ARBITRUM]: 'arbitrum', [CHAIN.ZKSYNC]: 'zksync', [CHAIN.BLAST]: 'blast', [CHAIN.LINEA]: 'linea', [CHAIN.SCROLL]: 'scroll', [CHAIN.ZETA]: 'zetachain', [CHAIN.MANTLE]: 'mantle', [CHAIN.MANTA]: 'manta-pacific', [CHAIN.POLYGON_ZKEVM]: 'polygon-zkevm', [CHAIN.PULSECHAIN]: 'pulsechain', [CHAIN.BASE]: 'base', [CHAIN.FANTOM]: 'fantom', [CHAIN.BOBA]: 'boba', [CHAIN.TELOS]: 'telos-evm', [CHAIN.KAVA]: 'kava', [CHAIN.OPTIMISM]: 'optimistic-ethereum', [CHAIN.AURORA]: 'aurora', [CHAIN.METIS]: 'metis', [CHAIN.MOONRIVER]: 'moonriver', [CHAIN.TRON]: 'tron', [CHAIN.MOONBEAM]: 'moonbeam', [CHAIN.FUSE]: 'fuse', [CHAIN.CELO]: 'celo', // [CHAIN.OKEXCHAIN]: 'oke-x-chain', [CHAIN.CRONOS]: 'cronos', [CHAIN.MODE]: 'mode', [CHAIN.MERLIN]: 'merlin', [CHAIN.CORE]: 'core', [CHAIN.TAIKO]: 'taiko', [CHAIN.ZKLINK]: 'zklink', [CHAIN.BITLAYER]: 'bitlayer', [CHAIN.BITCOIN]: 'bitcoin', [CHAIN.BERACHAIN]: 'berachain', [CHAIN.APTOS]: 'aptos', [CHAIN.ALGORAND]: 'algorand', [CHAIN.ASTAR]: 'astar', [CHAIN.CARDANO]: 'cardano', // [CHAIN.ASTAR_ZKEVM]: 'astar-evm', [CHAIN.BOBA_BNB]:'boba-bsc', [CHAIN.EOS]: 'eos', [CHAIN.DOGECHAIN]: 'dogecoin', [CHAIN.FILECOIN]: 'filecoin', [CHAIN.FLOW]: 'flow', [CHAIN.HEDERA]: 'hedera', [CHAIN.ICP]: 'icp', [CHAIN.SUI]: 'sui', [CHAIN.UNICHAIN]: 'unichain', [CHAIN.MORPH]: 'morph', [CHAIN.FRAXTAL]: 'fraxtal', [CHAIN.SONIC]: 'sonic', [CHAIN.SONEIUM]: 'soneium', [CHAIN.GRAVITY]: 'gravity', [CHAIN.ROOTSTOCK]: 'rootstock', [CHAIN.KROMA]: 'kroma', [CHAIN.XLAYER]: 'xlayer', [CHAIN.SEI]: 'sei', // [CHAIN.EON]: 'horizen-eon', // chain is dead [CHAIN.BAHAMUT]: 'bahamut', [CHAIN.KLAYTN]: 'klaytn', [CHAIN.VELAS]: 'velas', [CHAIN.SYSCOIN]: 'syscoin', [CHAIN.FLARE]: 'flare', [CHAIN.TON]: 'ton', [CHAIN.COSMOS]: 'cosmos', [CHAIN.LITECOIN]: 'litecoin', [CHAIN.OSMOSIS]: 'osmosis', [CHAIN.RIPPLE]: 'ripple', [CHAIN.POLKADEX]: 'polkadot', [CHAIN.STELLAR]: 'stellar', [CHAIN.NEAR]: 'near', [CHAIN.TEZOS]: 'tezos', [CHAIN.WAVES]: 'waves', [CHAIN.WAX]: 'wax', [CHAIN.XDC]: 'xdc', [CHAIN.NEO]: 'neo', [CHAIN.HEMI]: 'hemi', [CHAIN.ZILLIQA]: 'zilliqa', [CHAIN.MONAD]: 'monad', [CHAIN.MEGAETH]: 'megaeth', [CHAIN.PLASMA]: 'plasma', [CHAIN.HYPERLIQUID]: 'hyper-evm', }; interface ApiResponse { daily_volume_in_usd: string; daily_transaction_count: string; total_volume_in_usd: string; total_transaction_count: string; } const BadDataDays = [1758931200, 1759190400] const fetch: any = async (_a: any, _b: any, options: FetchOptions): Promise => { const response: ApiResponse = ( await fetchURL(`https://api.rubic.exchange/api/stats/defilama_crosschain?date=${options.startTimestamp}&network=${chains[options.chain]}`, 3) ); let dailyBridgeVolume = response?.daily_volume_in_usd || '0' if (BadDataDays.includes(options.startOfDay) && options.chain === CHAIN.ARBITRUM) { // bad data dailyBridgeVolume = '0'; } return { dailyBridgeVolume, }; }; const adapter: SimpleAdapter = { adapter: Object.fromEntries( Object.keys(chains).map(chain => [ chain, { fetch, start: '2023-01-01' } ]) ), version: 1 }; export default adapter; ================================================ FILE: bridge-aggregators/sharpe-bridge/index.ts ================================================ import { Chain } from "../../adapters/types"; import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; type IContract = { [c: string | Chain]: string; } const contract: IContract = { [CHAIN.AURORA]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.ARBITRUM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.OPTIMISM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.BASE]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.ETHEREUM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.AVAX]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.BSC]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.LINEA]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.MANTA]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.POLYGON]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.POLYGON_ZKEVM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.FANTOM]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.MODE]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.SCROLL]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.ZKSYNC]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.METIS]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', [CHAIN.XDAI]: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', } const fetch = async ({ chain, getLogs, createBalances, }: FetchOptions) => { const dailyVolume = createBalances(); const data: any[] = await getLogs({ target: contract[chain], eventAbi: 'event LiFiTransferStarted(bytes32 indexed transactionId, string bridge, string integrator, address referrer, address sendingAssetId, address receiver, uint256 minAmount, uint256 destinationChainId,bool hasSourceSwaps,bool hasDestinationCall )' }); data.forEach((e: any) => { if (e.integrator === 'sharpe.ai') { dailyVolume.add(e.sendingAssetId, e.minAmount); } }); return { dailyBridgeVolume: dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, adapter: Object.keys(contract).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2024-04-01', } } }, {}) }; export default adapter; ================================================ FILE: bridge-aggregators/socket/contracts.ts ================================================ import ADDRESSES from '../../helpers/coreAssets.json' import { CHAIN } from "../../helpers/chains"; // chain => vault => token export const SocketVaults: {[key: string]: {[key: string]: string}} = { [CHAIN.ETHEREUM]: { // derive '0x6D303CEE7959f814042D31E0624fB88Ec6fbcC1d': ADDRESSES.ethereum.USDC, '0xD4efe33C66B8CdE33B8896a2126E41e5dB571b7e': ADDRESSES.ethereum.WETH, '0x3Eec7c855aF33280F1eD38b93059F5aa5862E3ab': ADDRESSES.ethereum.WBTC, '0x5e98A25d8d6FF69A8992d6Aa57948dFB77D4ECBa': ADDRESSES.ethereum.USDT, '0x7D7aC8d55A9bD4152b703011f3E61AB3bB0A5592': ADDRESSES.ethereum.SNX, '0xeBB5D642aA8ccDeE98373D6aC3ee0602b63824b3': ADDRESSES.ethereum.WSTETH, '0x8180EcCC825b692ef65FF099a0A387743788bf78': ADDRESSES.ethereum.WEETH, '0x4BB4C3CDc7562f08e9910A0C7D8bB7e108861eB4': '0xFAe103DC9cf190eD75350761e95403b7b8aFa6c0', '0x35d4D9bc79B0a543934b1769304B90d752691caD': '0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7', '0xE3E96892D30E0ee1a8131BAf87c891201F7137bf': ADDRESSES.ethereum.sUSDe, '0x7E1d17b580dD4F89037DB331430eAEe8B8e50c91': ADDRESSES.ethereum.DAI, '0x613e87BE1cd75dEBC5e6e56a2AF2fED84162C142': ADDRESSES.ethereum.SDAI, '0x26Cf1Dc84694E04277F2Fe4C13E43597c6010C2A': ADDRESSES.ethereum.USDe, '0x30147A4989a0282aab8C9477aE9341dA4D09d3B1': '0x6c3ea9036406852006290770bedfcaba0e23a0e8', '0x76624ff43d610f64177bb9c194a2503642e9b803': ADDRESSES.ethereum.LBTC, // reya '0xdff78a949e47c1e90f3dd6dd7fe2fa72b42a75f7': ADDRESSES.ethereum.USDC, '0x79823110827d38Ac7cE63C23a486b9708247CC6a': ADDRESSES.ethereum.USDT, '0x4229c4550045AA0d7534aa72c91EfFCA5824acd4': ADDRESSES.ethereum.DAI, '0xcA253a468B1Baf6b52a41bC3ac2fd5cCb3889aa2': ADDRESSES.null, '0x2344621d5aA6e784e8C6f4c54b0B29Dd9c3Ad4B6': ADDRESSES.ethereum.WBTC, '0x64dF894688c5052BeAdC35371cF69151Ebc5D658': ADDRESSES.ethereum.WETH, '0xaA2f2B6cD33Eaabb795c6DB60AAec599C8450F35': ADDRESSES.ethereum.USDe, '0x052B82b3A096A592F3F28d4736c4796445BB98Ef': ADDRESSES.ethereum.WSTETH, '0x5F3B301B4967623fDb3AE52Bb8FF4dB01C460Cd3': ADDRESSES.ethereum.sUSDe, '0x0A5A19376064fED2A0A9f3120B2426c957BC289D': '0x5c5b196abe0d54485975d1ec29617d42d9198326', '0x0b4447344fAAA340bcD2B0FdBD8f0CEcd161bC9E': ADDRESSES.ethereum.deUSD, // hook '0x855Aaf2f690Ef6e5EF451D7AE73EC3fa61c50981': ADDRESSES.ethereum.USDC, '0xB39DF6BBB1Cf2B609DeE43F109caFEFF1A7CCBEa': ADDRESSES.ethereum.WETH, // polynomial [ADDRESSES.polynomial.SDAI]: ADDRESSES.ethereum.SDAI, '0xDE1617Ddb7C8A250A409D986930001985cfad76F': ADDRESSES.ethereum.USDC, '0xC6cfb996A7CFEB89813A68CD13942CD75553032b': ADDRESSES.ethereum.sUSDe, '0xDf9Fa2b420689384E8DD55a706262DC0ED37020F': '0x35D8949372D46B7a3D5A56006AE77B215fc69bC0', // kinto '0x12Cf431BdF7F143338cC09A0629EDcCEDCBCEcB5': ADDRESSES.ethereum.DAI, '0xc5d01939Af7Ce9Ffc505F0bb36eFeDde7920f2dc': ADDRESSES.ethereum.WSTETH, '0x00A0c9d82B95a17Cdf2D46703F2DcA13EB0E8A94': ADDRESSES.ethereum.WETH, '0x755cD5d147036E11c76F1EeffDd94794fC265f0d': ADDRESSES.ethereum.USDC, '0x351d8894fB8bfa1b0eFF77bFD9Aab18eA2da8fDd': '0x57e114B691Db790C35207b2e685D4A43181e6061', '0xdf34E61B6e7B9e348713d528fEB019d504d38c1e': ADDRESSES.ethereum.USDe, '0xdb161cdc9c11892922F7121a409b196f3b00e640': ADDRESSES.ethereum.EIGEN, '0xc7a542f73049C11f9719Be6Ff701fCA882D60020': ADDRESSES.ethereum.EETH, '0x5B8Ae1C9c5970e2637Cf3Af431acAAebEf7aFb85': ADDRESSES.ethereum.SDAI, '0x43b718Aa5e678b08615CA984cbe25f690B085b32': ADDRESSES.ethereum.sUSDe, '0xD357F7Ec4826Bd1234CDA2277B623F6dE7dA56Dc': '0x57F5E098CaD7A3D1Eed53991D4d66C45C9AF7812', '0xeB66259d2eBC3ed1d3a98148f6298927d8A36397': ADDRESSES.ethereum.WEETH, '0x95d60E34aB2E626407d98dF8C240e6174e5D37E5': ADDRESSES.ethereum.ETHFI, '0x2f87464d5F5356dB350dcb302FE28040986783a7': '0x2367C8395a283f0285c6E312D5aA15826f1fEA25', '0x0fC783f611A888A2cAbC3dA482Add3215334dCc2': ADDRESSES.ethereum.MKR, '0x25f0D71Da51A77Ca231484eBbAD1f588A0230ef2': '0x45804880De22913dAFE09f4980848ECE6EcbAf78', '0xd04Bc056BE36a6127267E4F71d3b43D1BEEfE8bF': '0x68749665FF8D2d112Fa859AA293F07A622782F38', '0xA2bc0DaA9BF98820632bCa0663a9616f6bC180f8': ADDRESSES.ethereum.WSOL, '0xDB0e855F55ff35dA8754e5297925bd6c4Cb1Fa48': ADDRESSES.ethereum.EUSD, '0x210189fb61cE8776990403E8010B6aE300ad37AB': '0x7e0209ab6fa3c7730603b68799bbe9327dab7e88', '0x329AF0B874BD2A926935D6e5435B97ab787aD5e0': '0x890b6afc834c2a2cc6cb9b6627272ab4ecfd8271', }, [CHAIN.OPTIMISM]: { // derive '0xDEf0bfBdf7530C75AB3C73f8d2F64d9eaA7aA98e': ADDRESSES.optimism.USDC_CIRCLE, '0xBb9CF28Bc1B41c5c7c76Ee1B2722C33eBB8fbD8C': ADDRESSES.optimism.USDC, '0xdD4c717a69763176d8B7A687728e228597eAB86d': ADDRESSES.optimism.WETH_1, '0xE5967877065f111a556850d8f05b8DaD88edCEc9': ADDRESSES.optimism.WBTC, '0x44343AE5e9319b61c9DaD7876919eFdB03241b02': ADDRESSES.optimism.USDT, '0x8574CBC539c26Df9ec11bA283218268101ff10e1': '0x8700daec35af8ff88c16bdf0418774cb3d7599b4', '0xAA8f9D05599F1a5d5929c40342c06a5Da063a4dE': ADDRESSES.optimism.WSTETH, '0x44ed9cE901B367B1EF9DDBD4974C82A514c50DEc': '0x87eEE96D50Fb761AD85B1c982d28A042169d61b1', '0x5324c6d731a3d9D740e880929E2c952bA27408De': ADDRESSES.arbitrum.sUSDe, '0x43b019139946466A010c936a85df14C17C4159c0': ADDRESSES.optimism.DAI, '0x0464B37C067a60d391403d4bD1197870fB6aF2D0': '0x2218a117083f5b482b0bb821d27056ba9c04b1d3', '0x76E57c252A86e7a9C7E06D2e0c427f878805eaB2': ADDRESSES.arbitrum.USDe, // aevo '0xFff4A34925301d231ddF42B871c3b199c1E80584': ADDRESSES.optimism.USDC, '0x7809621a6D7e61E400853C64b61568aA773A28Ef': ADDRESSES.optimism.USDC_CIRCLE, '0x5c7Dd6cb73d93879E94F20d103804C495A10aE7e': ADDRESSES.optimism.WETH_1, // mode '0x2BBc2ED3931234E803618202Fe2F060e56625626': ADDRESSES.optimism.USDC, // reya '0x9239609eED7c40C6DDcEC25D247Ef205103590B6': ADDRESSES.optimism.USDC, '0x88CE86D198C8ebeAb680DD0350FBAEfe298a6965': ADDRESSES.optimism.USDT, '0x3Bb3B7d1cA52c55d93896290B59516372Ff35984': ADDRESSES.optimism.DAI, '0xe8FEA3de2749Ee4fe15fc749d0c31761373dFa99': ADDRESSES.null, '0x4436ba5E61E1e7F9721980741B6403859C576E72': ADDRESSES.optimism.WBTC, '0xAd7bdD85fdA879fe7771A2546939972F202C1BaE': ADDRESSES.optimism.WETH_1, '0xe9f2Ed94dEe821bd23716ED90672d6e3dc9e0415': ADDRESSES.arbitrum.sUSDe, '0xCbEcd69ceFA64F55b72F8ac288FC5c452819B608': ADDRESSES.optimism.USDC_CIRCLE, // hook '0xdBfE75271E3427D5b5480A1B4a4279e92518AB39': ADDRESSES.optimism.USDC_CIRCLE, '0xB39DF6BBB1Cf2B609DeE43F109caFEFF1A7CCBEa': ADDRESSES.optimism.WETH_1, // polynomial '0xc374967634133F5Ed1DF5050276e5B33986625D3': ADDRESSES.optimism.USDC_CIRCLE, }, [CHAIN.ARBITRUM]: { // derive '0x5e027ad442e031424b5a2C0ad6f656662Be32882': ADDRESSES.arbitrum.USDC_CIRCLE, '0xFB7B06538d837e4212D72E2A38e6c074F9076E0B': ADDRESSES.arbitrum.USDC, '0x8e9f58E6c206CB9C98aBb9F235E0f02D65dFc922': ADDRESSES.arbitrum.WETH, '0x3D20c6A2b719129af175E0ff7B1875DEb360896f': ADDRESSES.arbitrum.WBTC, '0xb2Cb9aDA6e00118dA8E83a6A53dF1EC6331A60a6': ADDRESSES.arbitrum.USDT, '0x8574CBC539c26Df9ec11bA283218268101ff10e1': ADDRESSES.arbitrum.WSTETH, '0x3FBFD80EF7591658d1D7DdEC067F413eFd6f985c': ADDRESSES.arbitrum.weETH, '0x486936FB1CE805e8C46E71C69256e72f3f550d38': ADDRESSES.berachain.rsETH, '0x3c143EA5eBaB50ad6D2B2d14FA719234d1d38F1b': ADDRESSES.arbitrum.sUSDe, '0x2B93891dc80ab9696814615f553fd15a3b98d3a2': ADDRESSES.optimism.DAI, '0x5fAA613365331A5062F3A00126954b742aBEb2FF': ADDRESSES.arbitrum.USDe, // aevo '0x80d40e32FAD8bE8da5C6A42B8aF1E181984D137c': ADDRESSES.arbitrum.USDC, '0x7711C90bD0a148F3dd3f0e587742dc152c3E9DDB': ADDRESSES.arbitrum.USDC_CIRCLE, '0x90bFB3C35ddfBbA42D998414F0ff1eADD430E161': ADDRESSES.arbitrum.WETH, // mode '0x0825266F72e8841D7FEA350B20DD65AA861ACeE9': ADDRESSES.arbitrum.USDC, // reya '0xa0E9B6DA89BD0303A8163B81B8702388bE0Fde77': ADDRESSES.arbitrum.USDC, '0xb371300517915190AEB8Be5C4AE0b986DBc68901': ADDRESSES.arbitrum.USDT, '0x492BaF2D8d9Ac9Cc7892C1e9924E483F5FE9dA07': ADDRESSES.optimism.DAI, '0x4Ed9ed34Ee9e502E4b320b8c2eeEFc714E743553': ADDRESSES.null, '0x3fAF4983dB89E651270AeA1b15e871236969D990': ADDRESSES.arbitrum.WBTC, '0xD7BBE2f6D1B52A27D2dAC28298DE3974a3d13047': ADDRESSES.arbitrum.WETH, '0xed902143F4129BE7Be73Bc355e77B67D47Df7bc3': ADDRESSES.arbitrum.sUSDe, '0x11B3a7E08Eb2FdEa2745e4CB64648b10B28524A8': ADDRESSES.arbitrum.USDC_CIRCLE, // hook '0xCa34d7cc253b47E0248b80c859F38a658db7BcCC': ADDRESSES.arbitrum.WETH, '0x7b017d4fcC370D32Fe13e60cA7424037BDEEcba6': ADDRESSES.arbitrum.USDC_CIRCLE, // polynomial [ADDRESSES.polynomial.SDAI]: ADDRESSES.arbitrum.USDC_CIRCLE, // kinto '0x36E2DBe085eE4d028fD60f70670f662365d0E978': ADDRESSES.optimism.DAI, '0x6F855dE562CC9d019757f5F68a15Cd392FF52962': ADDRESSES.arbitrum.WSTETH, '0x4D585D346DFB27b297C37F480a82d4cAB39491Bb': ADDRESSES.arbitrum.WETH, '0xC88A469B96A62d4DA14Dc5e23BDBC495D2b15C6B': ADDRESSES.arbitrum.USDC_CIRCLE, '0x7C852c2a3e367453Ce3a68A4D12c313BaD0565e3': ADDRESSES.arbitrum.USDe, '0x8bD30d8c5d5cBb5e41Af7B9A4bD654b34772e890': ADDRESSES.arbitrum.weETH, '0x500c8337782a9f82C5376Ea71b66A749cE42b507': '0x57F5E098CaD7A3D1Eed53991D4d66C45C9AF7812', '0x25a1baC7314Ff40Ee8CD549251924D066D7d5bC6': '0x3647c54c4c2c65bc7a2d63c0da2809b399dbbdc0', '0x97bf1f0F7A929bE866F7Fbeb35545f5429Addf26': '0x0022228a2cc5E7eF0274A7Baa600d44da5aB5776', '0x8446981bC2168395497e6D0709169BdF81682E5c': ADDRESSES.celo.STEUR, '0x830dE29a70D4665329919D5f7E63BD44CBB22dc7': '0xb74da9fe2f96b9e0a5f4a3cf0b92dd2bec617124', }, [CHAIN.BASE]: { // derive '0x4e798659b9846F1da7B6D6B5d09d581270aB6FEC': ADDRESSES.base.USDC, '0x2805B908a0F9CA58a2b3b7900341b4EBd0B994e9': ADDRESSES.base.wstETH, '0xBd282333710B9C7e33E8a37d027885A7C079Ae23': ADDRESSES.optimism.WETH_1, '0xF982c812099d03AFFa0c8062aa1abcb584c23329': ADDRESSES.bsc.weETH, '0xC4Cb2F82A01dC896a4d423231E60d7B500252e19': '0xEDfa23602D0EC14714057867A78d01e94176BEA0', '0xFE00C281729fa7E7AaB453690ed184284F51268C': ADDRESSES.arbitrum.sUSDe, '0xb57D0EBC142eE63160d7B68B6E4C72D98053C539': ADDRESSES.base.DAI, '0xb2aD65aEffD5EEb28ce13d318A83c89461B2b444': '0x99ac4484e8a1dbd6a185380b3a811913ac884d87', '0x3BcB0FF2D4B674784ac1c33bc85a047b5a726E71': ADDRESSES.arbitrum.USDe, // mode '0x4C9faD010D8be90Aba505c85eacc483dFf9b8Fa9': ADDRESSES.base.USDbC, // reya '0x77e61C6fcAEe80CA578B818DD583d2b78f99289C': ADDRESSES.base.DAI, '0xd29950bE28D36182599f9B3ec82D08A043e1bf40': ADDRESSES.null, '0xD71629697B71E2Df26B4194f43F6eaed3B367ac0': ADDRESSES.base.USDC, '0x2b3A8ABa1E055e879594cB2767259e80441E0497': ADDRESSES.optimism.WETH_1, '0x3FC5c9C4860b51D92e3d84B3e450D1b8e81Df592': ADDRESSES.arbitrum.sUSDe, // hook '0x3411942F8FdAd5995Fbecb66bc07aA839D738500': ADDRESSES.base.USDC, '0xB39DF6BBB1Cf2B609DeE43F109caFEFF1A7CCBEa': ADDRESSES.optimism.WETH_1, // polynomial '0x038bc0f438C6b46FaCc5C83475925F4Dc111d79F': ADDRESSES.base.USDC, }, [CHAIN.POLYGON]: { // reya '0xC0acBb471465FCf848746D1837d8358aB891546c': ADDRESSES.polygon.USDC, '0x90105A04f47c08c14651320Bf4CD24A9E71fd9f5': ADDRESSES.polygon.USDT, '0x9Fd1857560c6f25b6Cf4AeC202137F54D6E8B292': ADDRESSES.polygon.DAI, '0x72384be7092144cD9a57526B486827E4eA632351': ADDRESSES.polygon.WETH_1, '0x0825266F72e8841D7FEA350B20DD65AA861ACeE9': ADDRESSES.polygon.WBTC, '0xBC31ec84bd7BC2c97B9413F6E473cE96Be153a25': ADDRESSES.polygon.USDC_CIRCLE, // aavegotchi '0xBdc2420b1E7F1f97d45b55a2ea9d3b4eB2675B75': '0x403e967b044d4be25170310157cb1a4bf10bdd0f', '0x321fCfC2cc0d45d2eb252A11bBA8274543819feB': '0x44a6e0be76e1d9620a7f76588e4509fe4fa8e8c8', '0xc87653358D5EDc7716057c865b8cD9ac5eB44A16': '0x6a3E7C3c6EF65Ee26975b12293cA1AAD7e1dAeD2', '0x3D57A1a3429825C35B7C432F8885fA1D0Eede460': '0x42E5E06EF5b90Fe15F853F59299Fc96259209c5C', '0x8B2D15F61B99De5Fd53dfCFFf8AF995f17f9536d': '0x3801C3B3B5c98F88a9c9005966AA96aa440B9Afc', '0xef8d3a1fd0F9a0E04D19e29e03a16CaE0b4eD1f8': '0xF606bd19b1E61574ED625d9ea96C841D4E247A32', '0x8B745d1979879e686E326c5274EF64E7dB4170dF': '0x094553F42B44Ea1492b0dcA5f4134F23f45db742', '0xac03f33BdDc7C7D002B9426cdA0f1f5Ad366E26b': '0x17AfF554423D2C40A1BBF51b443E9d43dd8AE1eb', '0xE24007Ea3fAC1EC3fb580d40658600E31c73dDD1': '0xB0B2Ef34D412d73b0Ff90A709D1779A20655165A', '0x9CF6f370fC5cDf5Fb81783f26c064d142AA1Bc56': '0xbCF339DF10d78f2b44AA760EAd0F715A7A7d7269', '0x68E85149bCF40E717Be880a2B8798946794054DF': '0x5e24d4e71d8fc876af3D45499f6b9E8A296EC694', }, } ================================================ FILE: bridge-aggregators/socket/index.ts ================================================ import { Interface } from "ethers"; import { FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { SocketVaults } from "./contracts"; import * as sdk from '@defillama/sdk' const SocketVaultAbis = { TokensDeposited: 'event TokensDeposited(address connector, address depositor, address receiver, uint256 depositAmount)', TokensUnlocked: 'event TokensUnlocked(address connector, address receiver, uint256 unlockedAmount)', TokensBridged: 'event TokensBridged(address connecter, address receiver, uint256 amount, bytes32 messageId)', BridgingTokens: 'event BridgingTokens(address connector, address sender, address receiver, uint256 amount, bytes32 messageId)', } export function getToken(chain: string, vaultAddress: string): string | null { vaultAddress = sdk.util.normalizeAddress(vaultAddress) if (SocketVaults[chain]) { for (const [vault, token] of Object.entries(SocketVaults[chain])) { if (sdk.util.normalizeAddress(vault) === vaultAddress) { return token; } } } return null; } const fetch: any = async (options: FetchOptions): Promise => { const dailyBridgeVolume = options.createBalances() const vaultContract = new Interface(Object.values(SocketVaultAbis)) // deposit to layer 2 const depositEvents = (await options.getLogs({ eventAbi: SocketVaultAbis.TokensDeposited, entireLog: true, targets: Object.keys(SocketVaults[options.chain]), })).map(log => { const decoded = vaultContract.parseLog(log) const token = getToken(options.chain, log.address) if (decoded && token) { return { vault: log.address, token: token, amount: decoded.args.depositAmount, } } return null; }).filter(event => event !== null) const tokensBridgedEvents = (await options.getLogs({ eventAbi: SocketVaultAbis.TokensBridged, entireLog: true, targets: Object.keys(SocketVaults[options.chain]), })).map(log => { const decoded = vaultContract.parseLog(log) const token = getToken(options.chain, log.address) if (decoded && token) { return { vault: log.address, token: token, amount: decoded.args.amount, } } return null; }).filter(event => event !== null) const bridgingTokensEvents = (await options.getLogs({ eventAbi: SocketVaultAbis.BridgingTokens, entireLog: true, targets: Object.keys(SocketVaults[options.chain]), })).map(log => { const decoded = vaultContract.parseLog(log) const token = getToken(options.chain, log.address) if (decoded && token) { return { vault: log.address, token: token, amount: decoded.args.amount, } } return null; }).filter(event => event !== null) // withdraw from layer 2 const withdrawEvents = (await options.getLogs({ eventAbi: SocketVaultAbis.TokensUnlocked, entireLog: true, targets: Object.keys(SocketVaults[options.chain]), })).map(log => { const decoded = vaultContract.parseLog(log) const token = getToken(options.chain, log.address) if (decoded && token) { return { vault: log.address, token: token, amount: decoded.args.unlockedAmount, } } return null; }).filter(event => event !== null) // counting volumes for (const event of depositEvents.concat(tokensBridgedEvents).concat(bridgingTokensEvents).concat(withdrawEvents)) { dailyBridgeVolume.add(event.token, event.amount) } return { dailyBridgeVolume }; }; const adapter: SimpleAdapter = { version: 2, adapter: Object.keys(SocketVaults).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2023-08-10', } } }, {}) }; export default adapter; ================================================ FILE: bridge-aggregators/stableflow/index.ts ================================================ import { Fetch, FetchResult, FetchV2, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; interface ApiResponse { chain: string; date_time: number; volume: string; } const api = "https://api.stableflow.ai/v1/dashboard/chain/daily"; const chainMap: Record = { [CHAIN.ETHEREUM]: "eth", [CHAIN.ARBITRUM]: "arb", [CHAIN.POLYGON]: "pol", [CHAIN.BSC]: "bsc", [CHAIN.OPTIMISM]: "op", [CHAIN.AVAX]: "avax", [CHAIN.BERACHAIN]: "bera", [CHAIN.XLAYER]: "xlayer", [CHAIN.PLASMA]: "plasma", [CHAIN.SOLANA]: "sol", [CHAIN.NEAR]: "near", [CHAIN.TRON]: "tron", [CHAIN.APTOS]: "aptos", [CHAIN.BASE]: "base", [CHAIN.TON]: "ton", [CHAIN.MANTLE]: "mantle", [CHAIN.MEGAETH]: "megaeth", [CHAIN.INK]: "ink", [CHAIN.STABLE]: "stable", [CHAIN.CELO]: "celo", [CHAIN.SEI]: "sei", [CHAIN.FLARE]: "flare", [CHAIN.FRAXTAL]: "frax", [CHAIN.SUI]: "sui", [CHAIN.KATANA]: "katana", }; const prefetch: FetchV2 = async () => { const url = new URL(api); url.searchParams.set("project", "stableflow"); const res = await fetchURL(url.toString()); return res.data; }; const fetch: Fetch = async (_timestamp, _chainBlocks, options): Promise => { const { chain: currentChainBlock, startTimestamp, endTimestamp, preFetchedResults: data, } = options; const record = Array.isArray(data) && data.find((item: ApiResponse) => { return item.chain === chainMap[currentChainBlock] && item.date_time >= startTimestamp && item.date_time < endTimestamp; }); return { dailyBridgeVolume: record?.volume || 0, }; }; const adapter: SimpleAdapter = { version: 1, prefetch, fetch, chains: Object.keys(chainMap), start: "2025-10-10", }; export default adapter; ================================================ FILE: bridge-aggregators/swing/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; const baseURL = 'https://swap.prod.swing.xyz' const chains: Record = { [CHAIN.SOLANA]: 'solana', [CHAIN.ETHEREUM]: 'ethereum', [CHAIN.BSC]: 'bsc', [CHAIN.AVAX]: 'avalanche', [CHAIN.POLYGON]: 'polygon', [CHAIN.ARBITRUM]: 'arbitrum', [CHAIN.ARCHWAY]: 'archway-1', [CHAIN.BSQUARED]: 'b2-network', [CHAIN.BASE]: 'base', [CHAIN.BITCOIN]: 'bitcoin', [CHAIN.BITLAYER]: 'bitlayer', [CHAIN.BLAST]: 'blast', [CHAIN.BOB]: 'bob', [CHAIN.CORE]: 'core-blockchain', [CHAIN.COSMOS]: 'cosmoshub-4', [CHAIN.FANTOM]: 'fantom', [CHAIN.XDAI]: 'gnosis', [CHAIN.GRAVITY]: 'gravity', [CHAIN.INJECTIVE]: 'injective-1', [CHAIN.LINEA]: 'linea', [CHAIN.MANTA]: 'manta-pacific', [CHAIN.MANTLE]: 'mantle', [CHAIN.METIS]: 'metis', [CHAIN.MODE]: 'mode', [CHAIN.MOONBEAM]: 'moonbeam', [CHAIN.MORPH]: 'morph', [CHAIN.CELESTIA]: 'cataclysm-1', [CHAIN.OPTIMISM]: 'optimism', [CHAIN.OSMOSIS]: 'osmosis-1', [CHAIN.SCROLL]: 'scroll', [CHAIN.TAIKO]: 'taiko', [CHAIN.WC]: 'world-chain', [CHAIN.ZKSYNC]: 'zksync-era', }; const fetch = async (_t: any, _b: any, options: FetchOptions) => { const startOfDay = options.startOfDay; const endOfDay = startOfDay + 24 * 60 * 60; const dailyRes = await httpGet(`${baseURL}/v0/metrics/stats`, { headers: { 'Content-Type': 'application/json', }, params: { startDate: startOfDay, endDate: endOfDay }, }); const chainVolumes = dailyRes?.historicalVolumeCrossChainChain?.map((history: any) => { const chainVol = history?.volume?.find((vol: any) => { return vol?.chainSlug?.toLowerCase() === chains[options.chain].toLowerCase(); }) return chainVol; }); const chainVolume = chainVolumes?.reduce((acc: number, curr: any) => { return acc + Number(curr?.value || 0); }, 0); return { dailyBridgeVolume: chainVolume || 0, }; }; const adapter: SimpleAdapter = { adapter: { ...Object.entries(chains).reduce((acc, [key, _]) => { return { ...acc, [key]: { fetch, start: '2022-11-01', // 2022-11-01 }, }; }, {}), }, version: 1 }; export default adapter; ================================================ FILE: bridge-aggregators/virtus/index.ts ================================================ import { Adapter, FetchOptions } from '../../adapters/types'; import { httpGet } from '../../utils/fetchURL'; import { CHAIN } from '../../helpers/chains'; import { getEnv } from '../../helpers/env'; const BACKEND_BASE = getEnv('VIRTUS_BACKEND_BASE'); const UNIFORM_START = '2025-09-03'; const CHAINS: Record = { [CHAIN.ETHEREUM]: { id: 'ethereum' }, [CHAIN.SOLANA]: { id: 'solana' }, [CHAIN.BSC]: { id: 'bsc' }, [CHAIN.SCROLL]: { id: 'scroll' }, [CHAIN.BASE]: { id: 'base' }, [CHAIN.BITCOIN]: { id: 'bitcoin' }, [CHAIN.ARBITRUM]: { id: 'arbitrum' }, [CHAIN.POLYGON]: { id: 'polygon' }, [CHAIN.OPTIMISM]: { id: 'optimism' }, [CHAIN.LINEA]: { id: 'linea' }, [CHAIN.CELO]: { id: 'celo' }, [CHAIN.AVAX]: { id: 'avax' }, [CHAIN.ERA]: { id: 'era' }, [CHAIN.MODE]: { id: 'mode' }, [CHAIN.TRON]: { id: 'tron' }, [CHAIN.ZORA]: { id: 'zora' }, [CHAIN.BLAST]: { id: 'blast' }, [CHAIN.OSMOSIS]: { id: 'osmosis' }, [CHAIN.COSMOS]: { id: 'cosmos' }, [CHAIN.FANTOM]: { id: 'fantom' }, [CHAIN.MOONRIVER]: { id: 'moonriver' }, [CHAIN.TAIKO]: { id: 'taiko' }, [CHAIN.STARKNET]: { id: 'starknet' }, [CHAIN.POLYGON_ZKEVM]: { id: 'polygon_zkevm' }, [CHAIN.SUI]: { id: 'sui' }, [CHAIN.CRONOS]: { id: 'cronos' }, [CHAIN.NOBLE]: { id: 'noble' }, [CHAIN.BOBA]: { id: 'boba' }, [CHAIN.THORCHAIN]: { id: 'thorchain' }, [CHAIN.FUSE]: { id: 'fuse' }, [CHAIN.XDAI]: { id: 'xdai' }, [CHAIN.HARMONY]: { id: 'harmony' }, [CHAIN.MOONBEAM]: { id: 'moonbeam' }, [CHAIN.TERRA]: { id: 'terra' }, [CHAIN.SONIC]: { id: 'sonic' }, [CHAIN.TON]: { id: 'ton' }, [CHAIN.BERACHAIN]: { id: 'berachain' }, [CHAIN.AURORA]: { id: 'aurora' }, [CHAIN.ROOTSTOCK]: { id: 'rsk' }, [CHAIN.KLAYTN]: { id: 'klaytn' }, [CHAIN.KAVA]: { id: 'kava' }, [CHAIN.EVMOS]: { id: 'evmos' }, [CHAIN.OKEXCHAIN]: { id: 'okexchain' }, [CHAIN.FILECOIN]: { id: 'filecoin' }, [CHAIN.CORE]: { id: 'core' }, [CHAIN.KROMA]: { id: 'kroma' }, [CHAIN.XLAYER]: { id: 'xlayer' }, [CHAIN.BITLAYER]: { id: 'btr' }, [CHAIN.MERLIN]: { id: 'merlin' }, [CHAIN.BOB]: { id: 'bob' }, [CHAIN.ZKLINK]: { id: 'zklink' }, [CHAIN.ZETA]: { id: 'zeta' }, [CHAIN.PULSECHAIN]: { id: 'pulse' }, }; const fetch = async (options: FetchOptions) => { const { chain, endTimestamp } = options; const info = CHAINS[chain]; if (!info) return { dailyBridgeVolume: 0, timestamp: endTimestamp }; const url = `${BACKEND_BASE}/defillama/bridge-volume?chain=${info.id}×tamp=${endTimestamp}`; const res = await httpGet(url) as { dailyBridgeVolume: number }; return { dailyBridgeVolume: res?.dailyBridgeVolume || 0, timestamp: endTimestamp }; }; const adapter: Adapter = { fetch, start: UNIFORM_START, chains: Object.keys(CHAINS), }; export default adapter; ================================================ FILE: bridge-aggregators/xy-finance/index.ts ================================================ import { Chain } from "../../adapters/types"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; type Contract = { [c: string | Chain]: { yBridge: string, xyRouter: string, }; } const contract: Contract = { [CHAIN.ETHEREUM]: { yBridge: '0x4315f344a905dC21a08189A117eFd6E1fcA37D57', xyRouter: "0xFfB9faf89165585Ad4b25F81332Ead96986a2681" }, [CHAIN.SCROLL]: { yBridge: "0x778C974568e376146dbC64fF12aD55B2d1c4133f", xyRouter: "0x22bf2A9fcAab9dc96526097318f459eF74277042" }, [CHAIN.MANTLE]: { yBridge: "0x73Ce60416035B8D7019f6399778c14ccf5C9c7A1", xyRouter: "0x52075Fd1fF67f03beABCb5AcdA9679b02d98cA37" }, [CHAIN.LINEA]: { yBridge: "0x73Ce60416035B8D7019f6399778c14ccf5C9c7A1", xyRouter: "0xc693C8AAD9745588e95995fef4570d6DcEF98000" }, [CHAIN.BASE]: { yBridge: "0x73Ce60416035B8D7019f6399778c14ccf5C9c7A1", xyRouter: "0x6aCd0Ec9405CcB701c57A88849C4F1CD85a3f3ab" }, [CHAIN.ARBITRUM]: { yBridge: "0x33383265290421C704c6b09F4BF27ce574DC4203", xyRouter: "0x062b1Db694F6A437e3c028FC60dd6feA7444308c" }, [CHAIN.ERA]: { yBridge: "0xe4e156167cc9C7AC4AbD8d39d203a5495F775547", xyRouter: "0x30E63157bD0bA74C814B786F6eA2ed9549507b46" }, [CHAIN.BSC]: { yBridge: "0x7D26F09d4e2d032Efa0729fC31a4c2Db8a2394b1", xyRouter: "0xDF921bc47aa6eCdB278f8C259D6a7Fef5702f1A9" }, [CHAIN.POLYGON]: { yBridge: "0x0c988b66EdEf267D04f100A879db86cdb7B9A34F", xyRouter: "0xa1fB1F1E5382844Ee2D1BD69Ef07D5A6Abcbd388" }, [CHAIN.KLAYTN]: { yBridge: "0x52075Fd1fF67f03beABCb5AcdA9679b02d98cA37", xyRouter: "0x252eA5AebEB648e7e871DAD7E0aB6cb49096BdD5" }, [CHAIN.POLYGON_ZKEVM]: { yBridge: "0x3689D3B912d4D73FfcAad3a80861e7caF2d4F049", xyRouter: "0x218Ef86b88765df568E9D7d7Fd34B5Dc88098080" }, [CHAIN.AVAX]: { yBridge: "0x2C86f0FF75673D489b7D72D9986929a2b0Ed596C", xyRouter: "0xa0c0F962DECD78D7CDE5707895603CBA74C02989" }, [CHAIN.OPTIMISM]: { yBridge: "0x7a6e01880693093abACcF442fcbED9E0435f1030", xyRouter: "0xF8d342db903F266de73B10a1e46601Bb08a3c195" }, [CHAIN.CRONOS]: { yBridge: "0xF103b5B479d2A629F422C42bb35E7eEceE1ad55E", xyRouter: "0x5d6e7E537cb4a8858C8B733A2A307B4aAFDc42ca" }, [CHAIN.FANTOM]: { yBridge: "0xDa241399697fa3F6cD496EdAFab6191498Ec37F5", xyRouter: "0x1E1a70eDb9cd26ccc05F01C66B882cef0E4f7d2D" }, [CHAIN.ASTAR]: { yBridge: "0x5C6C12Fd8b1f7E60E5B60512712cFbE0192E795E", xyRouter: "0x9c83E6F9E8DA12af8a0Cb8E276b722EB3D7668aF" }, [CHAIN.KCC]: { yBridge: "0x7e803b54295Cd113Bf48E7f069f0531575DA1139", xyRouter: "0x562afa22b2Fc339fd7Fa03E734E7008C3EccF8CF" }, [CHAIN.MOONRIVER]: { yBridge: "0xc67Dd7054915a2B0aA3e48f35DA714Ff861e71BD", xyRouter: "0x64d17beaE666cC435B9d40a21f058b379b2a0194" }, [CHAIN.THUNDERCORE]: { yBridge: "0xF103b5B479d2A629F422C42bb35E7eEceE1ad55E", xyRouter: "0xbF26ca7cf925e9EA0765c737B066253CF80e0E09" }, [CHAIN.NUMBERS]: { yBridge: "", xyRouter: "0x1acCfC3a45313f8F862BE7fbe9aB25f20A93d598" }, [CHAIN.WEMIX]: { yBridge: "0x73Ce60416035B8D7019f6399778c14ccf5C9c7A1", xyRouter: "0x6471fAd467ac2854b403e7FE3e95FBbB3287a7ee" }, [CHAIN.BLAST]: { yBridge: "0x73Ce60416035B8D7019f6399778c14ccf5C9c7A1", xyRouter: "0x43A86823EBBe2ECF9A384aDfD989E26A30626458" }, // [CHAIN.XLAYER]: { // yBridge: "0x6be1fe9dd10a4fbfce5552ca9add122341ec6c04", // xyRouter: "0x6A816cEE105a9409D8df0A83d8eeaeD9EB4309fE" // }, [CHAIN.TAIKO]: { yBridge: "0x6be1fe9dd10a4fbfce5552ca9add122341ec6c04", xyRouter: "0xedC061306A79257f15108200C5B82ACc874C239d" }, [CHAIN.CRONOS_ZKEVM]: { yBridge: "0xE22747472A565e96D0867741811193895b9538f2", xyRouter: "0x986138f6ed1350a85De6B18280f7d139F74B7282" }, } const yBridgeContractTopic = '0xb0e9a29a6096a927bd389ba0d0d1a15f82df21a331d23a33eeb7de1cf7ab2684' const xyRouterContractTopic = '0xcfdc06da1b80f541716b9dc11dba02141fbc401b0d152e9286df44c79b9d4000' const yBridgeContractEventAbi = 'event SwapRequested(uint256 _swapId, address indexed _aggregatorAdaptor, tuple(uint32 dstChainId, address dstChainToken, address dstAggregatorAdaptor, uint256 expectedDstChainTokenAmount, uint32 slippage) _dstChainDesc, address _srcToken, address indexed _vaultToken, uint256 _vaultTokenAmount, address _receiver, uint256 _srcTokenAmount, uint256 _expressFeeAmount, address indexed _referrer)' const xyRouterContractEventAbi = `event XYRouterRequested( uint256 xyRouterRequestId, address indexed sender, address srcToken, uint256 amountIn, address indexed bridgeAddress, address bridgeToken, uint256 bridgeAmount, uint256 dstChainId, bytes bridgeAssetReceiver, tuple( tuple(bool hasTip, address tipReceiver) tipInfo, tuple( bool hasDstChainSwap, tuple( tuple(address srcToken, address dstToken, uint256 minReturnAmount, address receiver) swapRequest, address dexAddress, address approveToAddress, bytes dexCalldata ) swapAction ) dstChainSwapInfo, tuple(bool hasIM, address xApp, address refundReceiver, bytes message) imInfo ) dstChainAction, address indexed affiliate)` const fetch = async ({ chain, getLogs, createBalances }: FetchOptions) => { const dailyVolume = createBalances(); try { const yBridgeContract = contract[chain].yBridge; const xyRouterContract = contract[chain].xyRouter; const logPromises: (Promise)[] = []; if (yBridgeContract) { logPromises.push(getLogs({ target: yBridgeContract, topics: [yBridgeContractTopic], eventAbi: yBridgeContractEventAbi, })) } if (xyRouterContract) { logPromises.push(getLogs({ target: xyRouterContract, topics: [xyRouterContractTopic], eventAbi: xyRouterContractEventAbi, })) } const [yBridgeData, xyRouterData] = await Promise.all(logPromises); yBridgeData?.forEach((e: any) => { dailyVolume.add(e._vaultToken, e._vaultTokenAmount) }); xyRouterData?.forEach((e: any) => { dailyVolume.add(e.bridgeToken, e.bridgeAmount); }); } catch (error) { console.error(`XY Finance fetch chain ${chain} error: ${JSON.stringify(error)}`); } finally { return { dailyBridgeVolume: dailyVolume }; } } const adapter: SimpleAdapter = { version: 2, adapter: Object.keys(contract).reduce((acc, chain) => { return { ...acc, [chain]: { fetch, start: '2023-08-10', } } }, {}) } export default adapter ================================================ FILE: cli/buildModules.ts ================================================ // console.log("Building import files for tvl/dimensions/emissions/liquidations adapters") import { readdir, writeFile } from "fs/promises"; import { ADAPTER_TYPES, AdapterType, whitelistedBaseAdapterKeys } from "../adapters/types"; import { setModuleDefaults } from "../adapters/utils/runAdapter"; import { listHelperProtocols, deadAdapters } from "../factory/registry"; const extensions = ['ts', 'md', 'js'] run().catch(console.error).then(() => process.exit(0)) async function run() { const outputFile = __dirname + "/dimensionModules.json" const excludeKeys = new Set(["index", "README", '.gitkeep', 'GUIDELINES.md']) const baseFolderPath = __dirname + "/.." // path relative to current working directory -> `cd /defi` const dimensionsImports: any = {} for (const folderPath of ADAPTER_TYPES) await addAdapterType(folderPath) // Add helper-based adapters for all adapter types await addFactoryAdapters() addDeadAdapters() await writeFile(outputFile, JSON.stringify(dimensionsImports)) async function addAdapterType(folderPath: string) { if (folderPath === AdapterType.DERIVATIVES) { return; // skip derivatives as they use the same folder as dexs } dimensionsImports[folderPath] = {} try { const paths_keys = await getDirectoriesAsync(`${baseFolderPath}/${folderPath}`) // console.log(`Found ${paths_keys.length} adapters in ${folderPath}`) const promises = paths_keys.map(async (path) => { if (excludeKeys.has(path)) return; await createDimensionAdaptersModule(path, folderPath) }) return Promise.all(promises) } catch (error) { console.error(`Error getting directories for ${folderPath}:`, error) } } async function addFactoryAdapters() { // Get all protocols from factory registry const factoryProtocols = listHelperProtocols(); for (let { protocolName, factoryName, adapterType, sourcePath, exportName } of factoryProtocols) { if (!dimensionsImports[adapterType]) { dimensionsImports[adapterType] = {}; } // Guard: Skip if file-based adapter already exists (file-based takes precedence) if (dimensionsImports[adapterType][protocolName]) { // console.log(`Skipping factory adapter ${protocolName} in ${adapterType} - file-based adapter already exists`); continue; } try { // Import based on source path if (sourcePath === 'users.ts') sourcePath = 'users/list.ts' // special case for users factory which has named exports let helperModule = sourcePath.startsWith('factory/') ? await import(`../${sourcePath.replace('.ts', '')}`) : sourcePath.includes('/') ? await import(`../${sourcePath}`) : await import(`../helpers/${factoryName}`); if (exportName) helperModule = helperModule[exportName]; const adapter = helperModule.getAdapter(protocolName); if (adapter.adapter) { Object.keys(adapter.adapter).forEach(chain => { const obj = adapter.adapter[chain] const keys = Object.keys(obj) for (const key of keys) { if (!whitelistedBaseAdapterKeys.has(key)) { delete obj[key] // remove non base adapter keys to avoid confusion, we only want the fetch/start/runAtCurrTime keys for the dimension modules } } }) } if (!adapter) continue; await setModuleDefaults(adapter); const mockedAdapter = mockFunctions({ default: adapter }); dimensionsImports[adapterType][protocolName] = { moduleFilePath: `${adapterType}/${protocolName}`, codePath: sourcePath, module: mockedAdapter.default, }; } catch (error: any) { console.log(`Error creating helper module for ${protocolName} from ${factoryName}:`, error.message); } } } async function createDimensionAdaptersModule(path: string, adapterType: string) { try { const fileKey = removeDotTs(path) const moduleFilePath = `${adapterType}/${fileKey}` const importPath = `../${adapterType}/${fileKey}` let module = await import(importPath) if (!module.default) { throw new Error(`Module ${moduleFilePath} does not have a default export`) } await setModuleDefaults(module.default) module = mockFunctions(module) dimensionsImports[adapterType][fileKey] = { moduleFilePath, codePath: `${adapterType}/${path}`, module: module.default, } } catch (error: any) { console.log(`Error creating module for ${path} in ${adapterType}:`, error.message) return '' } } function addDeadAdapters() { const defaultCommitHash = "1e8620166b5772c02e5e68e9dcd2cbb818724d69" // /dead folder is deleted after this step for (const [adapterType, adapters] of Object.entries(deadAdapters)) { if (!dimensionsImports[adapterType]) { dimensionsImports[adapterType] = {}; } for (const [protocolName, adapterInfo] of Object.entries(adapters as any)) { if (dimensionsImports[adapterType][protocolName]) continue; (adapterInfo as any).commit = (adapterInfo as any).commit ?? defaultCommitHash dimensionsImports[adapterType][protocolName] = adapterInfo; } } } } //Replace all fuctions with mock functions in an object all the way down function mockFunctions(obj: any) { if (typeof obj === "function") { return '_f' // llamaMockedTVLFunction } else if (typeof obj === "bigint") { return Number(obj) } else if (typeof obj === "object" && obj !== null) { Object.keys(obj).forEach((key) => obj[key] = mockFunctions(obj[key])) } return obj } function removeDotTs(s: string) { const splitted = s.split('.') if (splitted.length > 1 && extensions.includes(splitted[splitted.length - 1])) splitted.pop() return splitted.join('.') } // Async version of getDirectories async function getDirectoriesAsync(source: string): Promise { try { const dirents = await readdir(source, { withFileTypes: true }); return dirents.map(dirent => dirent.name); } catch (error) { let sourceDir = source.split('/').pop() || source; if (!['nft-volume', 'active-users', 'new-users'].includes(sourceDir)) { console.log(`Error reading directories from ${sourceDir}:`, (error as any).message); } return []; } } ================================================ FILE: cli/compareModules.js ================================================ const fs = require("fs"); const path = require("path"); const SKIP_FIELDS = new Set(["moduleFilePath", "codePath", "_randomUID"]); const currentPath = path.join(__dirname, "dimensionModules.json"); const safePath = path.join(__dirname, "..", "safe.json.log"); if (!fs.existsSync(currentPath)) { console.error("dimensionModules.json not found. Run buildModules first."); process.exit(1); } if (!fs.existsSync(safePath)) { console.error("safe.json.log not found."); process.exit(1); } const whitelistedBaseAdapterKeys = new Set([ 'start', 'deadFrom', 'fetch', 'runAtCurrTime' ]) const current = JSON.parse(fs.readFileSync(currentPath, "utf8")); const safe = JSON.parse(fs.readFileSync(safePath, "utf8")); cleanup(safe); let missingCount = 0; let extraCount = 0; let diffCount = 0; // --- 1. Missing & extra keys --- console.log("=".repeat(80)); console.log("MISSING & EXTRA KEYS (comparing dimensionModules.json against safe.json.log)"); console.log("=".repeat(80)); const allTypes = new Set([...Object.keys(safe), ...Object.keys(current)]); const ignoredModules = [ 'canto-dex', 'auragi', 'dyorswap', 'swapmode-v2', 'viperswap', 'xswap-v2', 'zkswap-finance', 'mare-finance-v2', 'mux-protocol', 'koi-finance', 'alphasec-spot', ] for (const adapterType of [...allTypes].sort()) { const safeAdapters = safe[adapterType] || {}; const currentAdapters = current[adapterType] || {}; ignoredModules.forEach(m => { delete safeAdapters[m]; delete currentAdapters[m]; }) const safeKeys = new Set(Object.keys(safeAdapters)); const currentKeys = new Set(Object.keys(currentAdapters)); const missingFromCurrent = [...safeKeys].filter((k) => !currentKeys.has(k)); const extraInCurrent = [...currentKeys].filter((k) => !safeKeys.has(k)); if (missingFromCurrent.length > 0) { console.log( `\n[${adapterType}] Missing from current build (${missingFromCurrent.length}):` ); for (const k of missingFromCurrent.sort()) { console.log(` - ${k}`); missingCount++; } } /* if (extraInCurrent.length > 0) { console.log( `\n[${adapterType}] New in current build (not in safe) (${extraInCurrent.length}):` ); for (const k of extraInCurrent.sort()) { console.log(` + ${k}`); extraCount++; } } */ } // --- 2. Deep comparison --- console.log("\n" + "=".repeat(80)); console.log("VALUE DIFFERENCES (skipping moduleFilePath, codePath, _randomUID)"); console.log("=".repeat(80)); function deepCompare(a, b, path) { const diffs = []; if (a === b) return diffs; if (a === null || b === null || typeof a !== typeof b) { if (path.endsWith('runAtCurrTime') && a === false && b === true) { // Ignore this specific change as it's intentional and doesn't affect output return diffs; } diffs.push({ path, safe: a, current: b }); return diffs; } if (typeof a !== "object") { if (a !== b) { diffs.push({ path, safe: a, current: b }); } return diffs; } // Both are objects/arrays const isArrayA = Array.isArray(a); const isArrayB = Array.isArray(b); if (isArrayA !== isArrayB) { diffs.push({ path, safe: a, current: b }); return diffs; } if (isArrayA) { const maxLen = Math.max(a.length, b.length); for (let i = 0; i < maxLen; i++) { if (i >= a.length) { diffs.push({ path: `${path}[${i}]`, safe: undefined, current: b[i] }); } else if (i >= b.length) { diffs.push({ path: `${path}[${i}]`, safe: a[i], current: undefined }); } else { diffs.push(...deepCompare(a[i], b[i], `${path}[${i}]`)); } } return diffs; } // Object comparison const allKeys = new Set([...Object.keys(a), ...Object.keys(b)]); for (const key of allKeys) { if (SKIP_FIELDS.has(key)) continue; const childPath = path ? `${path}.${key}` : key; if (!(key in a)) { diffs.push({ path: childPath, safe: undefined, current: b[key] }); } else if (!(key in b)) { diffs.push({ path: childPath, safe: a[key], current: undefined }); } else { diffs.push(...deepCompare(a[key], b[key], childPath)); } } return diffs; } for (const adapterType of [...allTypes].sort()) { const safeAdapters = safe[adapterType] || {}; const currentAdapters = current[adapterType] || {}; const commonKeys = Object.keys(safeAdapters).filter( (k) => k in currentAdapters ); const typeDiffs = []; for (const key of commonKeys.sort()) { let diffs = deepCompare( safeAdapters[key], currentAdapters[key], `${adapterType}.${key}` ); const ignoredPatterns = (str) => ([ 'ethodology', // 'dyorswap', // 'swapmode-v2', // 'viperswap', // 'canto-dex', ]).some(i => str.includes(i)) diffs = diffs.filter(i => { const filter = i.safe !== undefined && !i.path.endsWith('pullHourly') && !ignoredPatterns(i.path) if (!filter) return false if(i.path.endsWith('runAtCurrTime') && i.safe === false && i.current === true) { return false } const paths = i.path.split('.') const safeJSON = safe[paths[0]]?.[paths[1]]?.[paths[2]] const currJSON = current[paths[0]]?.[paths[1]]?.[paths[2]] const currentAdapterJSONStr = JSON.stringify(currJSON); if (i.path.endsWith('.module.fetch')) { if (currentAdapterJSONStr?.includes('fetch')) return false } if (i.path.endsWith('.module.chains') && !currJSON?.chains) { const someChainIsMissing = safeJSON?.module?.chains?.some(chain => currentAdapterJSONStr?.includes(chain)) return someChainIsMissing } if (i.path.endsWith('.start')) { return currentAdapterJSONStr?.includes(i.safe) } if (i.path.endsWith('.version')) { return i.safe > i.current } return true }) if (diffs.length > 0) { typeDiffs.push({ key, diffs }); } } if (typeDiffs.length > 0) { console.log(`\n[${adapterType}] ${typeDiffs.length} adapter(s) with differences:`); for (const { key, diffs } of typeDiffs) { console.log(`\n ${key}:`); for (const d of diffs) { const safeFmt = fmt(d.safe); const currFmt = fmt(d.current); console.log(` ${d.path}`); console.log(` safe: ${safeFmt}`); console.log(` current: ${currFmt}`); diffCount++; } } } } // --- Summary --- console.log("\n" + "=".repeat(80)); console.log("SUMMARY"); console.log("=".repeat(80)); console.log(` Missing from current build : ${missingCount}`); console.log(` New in current build : ${extraCount}`); console.log(` Value differences : ${diffCount}`); function fmt(v) { if (v === undefined) return "(missing)"; if (typeof v === "object") return JSON.stringify(v); return String(v); } function cleanup(obj) { const adapterTypes = Object.keys(obj) for (const type of adapterTypes) { const adapters = obj[type] for (const adapterName in adapters) { const adapter = adapters[adapterName] if (adapter.module?.adapter) { for (const key of Object.keys(adapter.module.adapter)) { if (!whitelistedBaseAdapterKeys.has(key)) { delete adapter.module.adapter[key]; } } } if (adapter.module?.breakdown) delete adapters[adapterName] // Remove breakdown adapters entirely since they are no longer used at all } } return obj } ================================================ FILE: cli/interactive.js ================================================ const inquirer = require('inquirer') const childProcess = require('child_process') inquirer.registerPrompt('fuzzypath', require('inquirer-fuzzy-path')) console.log('Starting directory: ' + process.cwd()); const args = process.argv.slice(2); // The first two elements are 'node' and the script filename const NEW_DIR = './' + (args[0] ?? '') try { process.chdir(NEW_DIR); console.log('New directory: ' + process.cwd()); } catch (err) { console.log('chdir: ' + err); } const adapterPrompt = { type: 'fuzzypath', name: 'adapterPath', excludePath: nodePath => ['node_modules', '.git', 'cli', '.github', 'adapters', 'helpers', 'utils', '.gitignore', 'README.md' ].includes(nodePath), excludeFilter: nodePath => { if (nodePath == '.') return true return false }, itemType: 'any', rootPath: '.', message: 'Select an adapter to run:', suggestOnly: false, depthLimit: 1, } async function run() { let adapterPath const { debugMode, ...response } = await inquirer.prompt([ adapterPrompt, ]) adapterPath = response.adapterPath while (true) { // eslint-disable-line adapterPrompt.default = adapterPath await runAdapter(adapterPath, true) const answer = await inquirer.prompt([adapterPrompt]) adapterPath = answer.adapterPath } } async function runAdapter(adapterPath, debugMode) { return new Promise((resolve, reject) => { const env = { ...process.env, LLAMA_SDK_MAX_PARALLEL: 100, LLAMA_DEBUG_MODE: !!debugMode } const startTime = Date.now() const child = childProcess.spawn('npx', ['ts-node', '--transpile-only', 'cli/testAdapter.ts', ...adapterPath.split('/')], { env, }) child.stdout.pipe(process.stdout); child.stderr.pipe(process.stderr); child.on('error', reject) child.on('close', function (code) { console.log(` Run time: ${(Date.now() - startTime) / 1000} (seconds) `) resolve() }) }) } run() ================================================ FILE: cli/migrateDeadProjects.ts ================================================ import { readdir, writeFile, rm, mkdir } from "fs/promises"; import { existsSync, readFileSync, statSync } from "fs"; import { execSync } from "child_process"; import { ADAPTER_TYPES, AdapterType } from "../adapters/types"; import { setModuleDefaults } from "../adapters/utils/runAdapter"; const extensions = ['ts', 'md', 'js'] const baseFolderPath = __dirname + "/.." const outputPath = `${baseFolderPath}/factory/deadAdapters.json` // Get current git commit hash const currentCommit = execSync('git rev-parse HEAD', { cwd: baseFolderPath }).toString().trim() // Load existing dead adapters if file exists let deadAdapters: Record> = {} if (existsSync(outputPath)) { try { deadAdapters = JSON.parse(readFileSync(outputPath, 'utf-8')) } catch (e) { deadAdapters = {} } } // Track which adapters have been processed const processedAdapters = new Set() // Store dead adapter info for dependency resolution interface DeadAdapterInfo { adapterType: string path: string fileKey: string fullPath: string // imports: string[] // list of imported adapter paths (e.g., "dexs/uniswap") } const deadAdapterInfos: Map = new Map() function sortObjectByKey(obj: Record) { return Object.keys(obj).sort().reduce((sorted: Record, key) => { sorted[key] = obj[key] return sorted }, {}) } function mockFunctions(obj: any): any { if (typeof obj === "function") { return '_f' } else if (typeof obj === "object" && obj !== null) { Object.keys(obj).forEach((key) => obj[key] = mockFunctions(obj[key])) } return obj } function removeDotTs(s: string) { const splitted = s.split('.') if (splitted.length > 1 && extensions.includes(splitted[splitted.length - 1])) splitted.pop() return splitted.join('.') } async function getDirectoriesAsync(source: string): Promise { const dirents = await readdir(source, { withFileTypes: true }); return dirents.map(dirent => dirent.name); } async function deleteAdapter(info: DeadAdapterInfo): Promise { const moduleKey = `${info.adapterType}/${info.fileKey}` if (processedAdapters.has(moduleKey)) { return false // Already processed } try { const importPath = `../${info.adapterType}/${info.fileKey}` let module = await import(importPath) if (!module.default) return false await setModuleDefaults(module.default) delete module.default._randomUID // Initialize adapter type in deadAdapters if not exists if (!deadAdapters[info.adapterType]) { deadAdapters[info.adapterType] = {} } const mockedModule = mockFunctions({ ...module.default }) deadAdapters[info.adapterType][info.fileKey] = { commit: currentCommit, codePath: `${info.adapterType}/${info.path}`, module: mockedModule } console.log(`Found dead adapter: ${moduleKey} (deadFrom: ${module.default.deadFrom})`) // Delete the adapter file/folder const isDir = existsSync(info.fullPath) && statSync(info.fullPath).isDirectory() await rm(info.fullPath, { recursive: isDir }) console.log(` Deleted: ${info.fullPath}`) processedAdapters.add(moduleKey) return true } catch (error: any) { console.log(error) // Skip modules that fail to import } return false } async function scanAdapter(adapterType: string, path: string): Promise { const excludeKeys = new Set(["index", "README", '.gitkeep']) if (excludeKeys.has(path)) return null try { const fileKey = removeDotTs(path) const moduleKey = `${adapterType}/${fileKey}` const importPath = `../${adapterType}/${fileKey}` const fullPath = `${baseFolderPath}/${adapterType}/${path}` let module = await import(importPath) if (!module.default) return null await setModuleDefaults(module.default) const adapterChainExports = Object.values(module.default.adapter || {}) let allChainsAreDead = false if (adapterChainExports.length > 0 && adapterChainExports.every((chainExport: any) => chainExport.deadFrom)) allChainsAreDead = true if (allChainsAreDead) console.log(`Scanned ${moduleKey}, all chains dead: ${allChainsAreDead}`) if (module.default.deadFrom !== undefined || allChainsAreDead) { // const imports = extractImports(fullPath) return { adapterType, path, fileKey, fullPath, // imports } } } catch (error: any) { // Skip modules that fail to import } return null } async function run() { // Phase 1: Scan all adapters and identify dead ones with their dependencies console.log('Scanning for dead adapters...\n') for (const adapterType of ADAPTER_TYPES) { if (adapterType === AdapterType.DERIVATIVES) { continue // skip derivatives as they use the same folder as dexs } const folderPath = `${baseFolderPath}/${adapterType}` try { const entries = await getDirectoriesAsync(folderPath) for (const entry of entries) { const info = await scanAdapter(adapterType, entry) if (info) { const moduleKey = `${info.adapterType}/${info.fileKey}` deadAdapterInfos.set(moduleKey, info) } } } catch (error) { // Folder doesn't exist, skip } } console.log(`Found ${deadAdapterInfos.size} dead adapters\n`) // Phase 2: Delete dead adapters and record their info let totalDead = 0 for (const [_, info] of deadAdapterInfos) { const deleted = await deleteAdapter(info) if (deleted) totalDead++ } // Sort dead adapters by key for (const adapterType of Object.keys(deadAdapters)) { deadAdapters[adapterType] = sortObjectByKey(deadAdapters[adapterType]) } deadAdapters = sortObjectByKey(deadAdapters) // Ensure the output directory exists const outputDir = outputPath.substring(0, outputPath.lastIndexOf('/')) if (!existsSync(outputDir)) { await mkdir(outputDir, { recursive: true }) } await writeFile(outputPath, JSON.stringify(deadAdapters, null, 2)) console.log(`\nDeleted ${totalDead} dead adapters, wrote registry to ${outputPath}`) console.log(`Total dead adapters in registry: ${Object.values(deadAdapters).reduce((acc, obj) => acc + Object.keys(obj).length, 0)}`) process.exit(0) } run().catch((e) => { console.error(e) process.exit(1) }) ================================================ FILE: cli/moduleStats.js ================================================ const data = require('./dimensionModules.json'); function newStat() { return { total: 0, noVersion: 0, version1: 0, version2: 0, dead: 0, pullHourly: 0, runAtCurrTime: 0, notPullHourly: 0 }; } function isFactory(codePath) { return codePath.startsWith('factory/') || codePath.startsWith('helpers/'); } const factory = {}; const individual = {}; for (const [adapterType, protocols] of Object.entries(data)) { factory[adapterType] = newStat(); individual[adapterType] = newStat(); for (const [name, info] of Object.entries(protocols)) { const bucket = isFactory(info.codePath) ? factory[adapterType] : individual[adapterType]; bucket.total++; const mod = info.module; const version = mod.version const isDead = mod.deadFrom if (isDead) bucket.dead++; else if (version === undefined || version === null) bucket.noVersion++; else if (version === 1) bucket.version1++; else if (version === 2) bucket.version2++; if (!isDead && mod.pullHourly) bucket.pullHourly++; else if (!isDead && !mod.pullHourly) bucket.notPullHourly++; if (!isDead && mod.runAtCurrTime) bucket.runAtCurrTime++; } } function printTable(title, stats) { console.log('='.repeat(100)); console.log(title); console.log('='.repeat(100)); const header = [ 'Type'.padEnd(25), 'Total'.padStart(7), 'No Ver'.padStart(8), 'V1'.padStart(6), 'V2'.padStart(6), 'Dead'.padStart(8), 'PullHrly'.padStart(10), 'RunAtCurr'.padStart(11), 'NotPullHrly'.padStart(13), ].join(' | '); console.log(header); console.log('-'.repeat(100)); const grand = newStat(); for (const [type, s] of Object.entries(stats)) { if (s.total === 0) continue; const row = [ type.padEnd(25), String(s.total).padStart(7), String(s.noVersion).padStart(8), String(s.version1).padStart(6), String(s.version2).padStart(6), String(s.dead).padStart(8), String(s.pullHourly).padStart(10), String(s.runAtCurrTime).padStart(11), String(s.notPullHourly).padStart(13), ].join(' | '); console.log(row); for (const k of Object.keys(grand)) grand[k] += s[k]; } console.log('-'.repeat(100)); const totalRow = [ 'TOTAL'.padEnd(25), String(grand.total).padStart(7), String(grand.noVersion).padStart(8), String(grand.version1).padStart(6), String(grand.version2).padStart(6), String(grand.dead).padStart(8), String(grand.pullHourly).padStart(10), String(grand.runAtCurrTime).padStart(11), String(grand.notPullHourly).padStart(13), ].join(' | '); console.log(totalRow); console.log(''); } printTable('FACTORY ADAPTERS (codePath starts with factory/ or helpers/)', factory); printTable('INDIVIDUAL ADAPTERS (own file)', individual); ================================================ FILE: cli/testAdapter.ts ================================================ require('dotenv').config() import { execSync } from 'child_process'; import * as path from 'path'; import * as sdk from '@defillama/sdk'; import { AdapterType, SimpleAdapter, } from '../adapters/types'; import runAdapter, { isHourlyAdapter, isPlainDateArg } from '../adapters/utils/runAdapter'; import { getUniqStartOfTodayTimestamp } from '../helpers/getUniSubgraphVolume'; import { camelCaseToSpaces, checkArguments, ERROR_STRING, printBreakdownFeesByLabel, printVolumes2, timestampLast } from './utils'; import { importAdapter } from '../adapters/utils/importAdapter'; const DEBUG_MODE = Boolean(process.env.DEBUG_MODE) function formatHourLabel(timestamp: number) { const d = new Date(timestamp * 1e3) let hour = d.getUTCHours() const ampm = hour >= 12 ? 'PM' : 'AM' hour = hour % 12 if (hour === 0) hour = 12 const day = String(d.getUTCDate()).padStart(2, '0') const month = String(d.getUTCMonth() + 1).padStart(2, '0') return `${hour} ${ampm} - ${day}/${month}` } function checkIfFileExistsInMasterBranch(filePath: any) { const res = execSync(`git ls-tree --name-only -r master`) const resString = res.toString() if (!resString.includes(filePath)) { console.log("\n\n\nERROR: Use Adapter v2 format for new adapters\n\n\n") process.exit(1) } } // tmp const handleError = (e: Error) => console.error(e) // Add handler to rejections/exceptions process.on('unhandledRejection', handleError) process.on('uncaughtException', handleError) // Check if all arguments are present checkArguments(process.argv) function getTimestamp30MinutesAgo() { return Math.trunc(Date.now() / 1000) - 60 * 60 * 2.5 } function toTimestamp(timeArg: string) { if (Number.isNaN(Number(timeArg))) { return Math.round(new Date(timeArg).getTime() / 1e3) } else { return Number(timeArg) } } // Get path of module import — support "dexs/kodiak-v3" as a single arg let adapterType: AdapterType | string = process.argv[2] as AdapterType let moduleArg = process.argv[3] if (!moduleArg && adapterType?.includes('/')) { const parts = adapterType.split('/') adapterType = parts[0] as AdapterType moduleArg = parts.slice(1).join('/') } let adapterModule: SimpleAdapter; let usedHelper: string | null | undefined = null; (async () => { const file = `${adapterType}/${moduleArg}` const passedFile = path.resolve(process.cwd(), `./${file}`); // Skip documentation files (e.g., GUIDELINES.md, guidelines) const docFiles = ['guidelines', 'readme', 'changelog']; const baseName = path.basename(moduleArg).toLowerCase().replace('.md', ''); if (moduleArg.endsWith('.md') || docFiles.includes(baseName)) { console.info(`Skipping documentation file: ${moduleArg}`); process.exit(0); } // throw error if module doesnt start with lowercase letters if (!/^[a-z0-9]/.test(moduleArg)) { throw new Error("Module name should start with a lowercase letter: " + moduleArg); } try { const result = await importAdapter(adapterType, moduleArg, passedFile); adapterModule = result.adapter; if (result.source === 'factory') { usedHelper = result.factoryName; console.info(`🦙 Running ${moduleArg.toUpperCase()} adapter from ${usedHelper} factory 🦙`); } else { console.info(`🦙 Running ${moduleArg.toUpperCase()} adapter 🦙`); } } catch (error: any) { console.error(error.message); process.exit(1); } console.info(`---------------------------------------------------`) const rawTimeArg = process.argv[4] const cleanDayTimestamp = rawTimeArg ? toTimestamp(rawTimeArg) : getUniqStartOfTodayTimestamp(new Date()) let endCleanDayTimestamp = cleanDayTimestamp; // console.info(`🦙 Running ${process.argv[3].toUpperCase()} adapter 🦙`) // console.info(`---------------------------------------------------`) // Import module to test let module: SimpleAdapter = adapterModule const adapterVersion = module.version const isHourly = isHourlyAdapter(module) const isPlainDate = isPlainDateArg(rawTimeArg) function mergeAggregated(target: any, source: any) { if (!source) return for (const [metric, data] of Object.entries(source)) { const src = data as any if (!target[metric]) target[metric] = { value: 0, chains: {} as any } const dst = target[metric] dst.value += src.value || 0 if (src.chains) { for (const [chain, val] of Object.entries(src.chains)) { if (val === undefined || val === null) continue dst.chains[chain] = (dst.chains[chain] || 0) + (val as number) } } } } if (isHourly && !rawTimeArg) { const rollingEnd = getTimestamp30MinutesAgo() const rollingEndSafe = rollingEnd - (rollingEnd % (60 * 60)) const rollingStart = rollingEndSafe - 24 * 60 * 60 console.info(`Start Date:\t${new Date(rollingStart * 1e3).toUTCString()}`) console.info(`End Date:\t${new Date(rollingEndSafe * 1e3).toUTCString()}`) console.info(`---------------------------------------------------\n`) const dayStart = rollingStart const lastHour = 23 await runHourlyMultiSlot(dayStart, lastHour) process.exit(0) } if (isHourly && isPlainDate) { const endOfWindow = toTimestamp(rawTimeArg) // 2025-12-09 00:00:00 const dayStart = endOfWindow - 24 * 60 * 60 // 2025-12-08 00:00:00 console.info(`Start Date:\t${new Date(dayStart * 1e3).toUTCString()}`) console.info(`End Date:\t${new Date(endOfWindow * 1e3).toUTCString()}`) console.info(`---------------------------------------------------\n`) await runHourlyMultiSlot(dayStart, 23) process.exit(0) } let endTimestamp = endCleanDayTimestamp if (adapterVersion === 2) { endTimestamp = (rawTimeArg ? toTimestamp(rawTimeArg) : getTimestamp30MinutesAgo()) // 1 day; } else { // checkIfFileExistsInMasterBranch(file) } const windowSeconds = isHourly ? 60 * 60 : 3600 * 24 console.info(`Start Date:\t${new Date((endTimestamp - windowSeconds) * 1e3).toUTCString()}`) console.info(`End Date:\t${new Date(endTimestamp * 1e3).toUTCString()}`) console.info(`---------------------------------------------------\n`) // Get adapter const debugBreakdownFees = Boolean(process.env.DEBUG_BREAKDOWN_FEES) const volumes: any = await runAdapter({ module: adapterModule, endTimestamp, withMetadata: debugBreakdownFees, isTest: true, name: usedHelper ? `${adapterType}/${moduleArg} (from ${usedHelper})` : moduleArg }) if (debugBreakdownFees) { printVolumes2(volumes.response.map((volume: any) => timestampLast(volume))) printBreakdownFeesByLabel(volumes.adaptorRecordV2JSON.breakdownByLabel) } else { printVolumes2(volumes.map((volume: any) => timestampLast(volume))) } console.info("\n") process.exit(0) async function runHourlyMultiSlot(dayStart: number, lastHour: number) { const dailyByChain: Record> = {} const aggregatedDaily: any = {} const jobs: { hour: number, startTimestamp: number, endTimestamp: number }[] = [] for (let hour = 0; hour <= lastHour; hour++) { const endTimestamp = dayStart + (hour + 1) * 3600 const startTimestamp = endTimestamp - 3600 jobs.push({ hour, startTimestamp, endTimestamp }) } const MAX_PARALLEL = 2 for (let i = 0; i < jobs.length; i += MAX_PARALLEL) { const batch = jobs.slice(i, i + MAX_PARALLEL) const results = await Promise.all( batch.map(job => runAdapter({ module, endTimestamp: job.endTimestamp, withMetadata: true, runWindowInSeconds: 60 * 60 })) ) results.forEach((res: any, idx) => { const job = batch[idx] const { startTimestamp, endTimestamp, hour } = job const volumes = res.response const adaptorRecordV2JSON = res.adaptorRecordV2JSON const aggHour = adaptorRecordV2JSON?.aggregated const lastPerChain = volumes.map((volume: any) => timestampLast(volume)) if (DEBUG_MODE) { console.info(`Slice ${hour}:`) console.info(`Start Date:\t${new Date(startTimestamp * 1e3).toUTCString()}`) console.info(`End Date:\t${new Date(endTimestamp * 1e3).toUTCString()}`) console.info(`---------------------------------------------------\n`) printVolumes2(lastPerChain) } else { const parts: string[] = [] if (aggHour) { for (const [metric, data] of Object.entries(aggHour)) { const value = (data as any)?.value if (typeof value !== 'number') continue const label = camelCaseToSpaces(metric).replace(/^Daily /, '').toLowerCase() parts.push(`${label} - ${sdk.humanizeNumber(value)}`) } } const slotLabel = `(${hour + 1}/${lastHour + 1})`.padStart(7, ' ') console.info(`${slotLabel} start: ${formatHourLabel(startTimestamp)} | ${parts.join(' | ')}`) } for (const row of lastPerChain) { const chain = (row as any).chain if (!chain) continue if (!dailyByChain[chain]) dailyByChain[chain] = {} const agg = dailyByChain[chain] for (const [key, value] of Object.entries(row as any)) { if (key === 'chain' || key === 'timestamp' || key === 'startTimestamp') continue if (typeof value !== 'number') continue agg[key] = (agg[key] ?? 0) + value } } mergeAggregated(aggregatedDaily, aggHour) }) } const dailyRows = Object.entries(dailyByChain).map(([chain, metrics]) => ({ chain, timestamp: dayStart + (lastHour + 1) * 3600 - 1, ...metrics, })) console.info(`\n====== TOTAL DAILY AGGREGATED (sum of slots per chain) ======\n`) printVolumes2(dailyRows) } })().catch((e) => { console.log(ERROR_STRING) console.error(e.stack?.split('\n')?.slice(0, 3)?.join('\n')) console.log(e.message ?? e) process.exit(1) }) ================================================ FILE: cli/utils.ts ================================================ import { SimpleAdapter, whitelistedDimensionKeys } from "../adapters/types"; import * as sdk from "@defillama/sdk"; const humanizeNumber = sdk.humanizeNumber; const getLatestBlock = sdk.blocks.getLatestBlock; export const ERROR_STRING = "------ ERROR ------"; export function checkArguments(argv: string[]) { const adapterArg = argv[2] if (argv.length < 4 && (!adapterArg || !adapterArg.includes('/'))) { console.error(`Missing arguments, you need to provide the folder name of the adapter to test. Eg: yarn test volume uniswap`); process.exit(1); } } export async function getLatestBlockRetry(chain: string) { for (let i = 0; i < 5; i++) { try { return await getLatestBlock(chain); } catch (e) { throw new Error(`Couln't get block heights for chain "${chain}"\n${e}`); } } } export function printVolumes(volumes: any[], _?: SimpleAdapter) { const exclude2Print = ["startTimestamp", "chain"]; let keys = volumes.map((element) => Object.keys(element)).flat(); keys.forEach((key) => { if (!whitelistedDimensionKeys.has(key)) throw new Error( `"${key}" is not a supported metric.Supported metrics can be found in adapters/types.ts`, ); }); volumes.forEach((element) => { // const methodology = module?.methodology if (typeof element.chain === "string") console.info(element.chain.toUpperCase(), "👇"); if (element.startTimestamp !== undefined && element.startTimestamp !== 0) console.info( `Backfill start time: ${formatTimestampAsDate(String(element.startTimestamp))}`, ); // else console.info("Backfill start time not defined") // if (typeof methodology === 'string') console.log("Methodology:", methodology) // else if (!methodology) console.log("NO METHODOLOGY SPECIFIED") Object.entries(element).forEach(([attribute, value]) => { if (attribute === "timestamp" && !value) return; if (!exclude2Print.includes(attribute)) { const valueFormatted = typeof value === "object" ? JSON.stringify(value, null, 2) : attribute === "timestamp" ? value + ` (${new Date((value as any) * 1e3).toISOString()})` : humanizeNumber(Number(value)); console.info( `${camelCaseToSpaces(attribute === "timestamp" ? "endTimestamp" : attribute)}: ${valueFormatted}`, ); // if (valueFormatted !== undefined && typeof methodology === 'object' && methodology[attribute.slice(5)]) // console.log("└─ Methodology:", methodology?.[attribute.slice(5)]) } }); console.info("\n"); }); if (volumes.length > 1) { const aggregated: { [key: string]: any; } = { chain: "---- aggregate", timestamp: volumes[0].timestamp, }; const ignoredKeySet = new Set(["chain", "timestamp", "startTimestamp"]); volumes.forEach((element) => { for (const [key, value] of Object.entries(element)) { if (!ignoredKeySet.has(key)) { if (aggregated[key] === undefined) aggregated[key] = 0; aggregated[key] += value; } } }); printVolumes([aggregated]); } } export function printVolumes2(volumes: any[]) { if (volumes?.length < 2) return printVolumes(volumes); const exclude2Print = ["startTimestamp", "chain", "timestamp", "block"]; const printTable: any = {}; let keys = volumes.map((element) => Object.keys(element)).flat(); keys.forEach((key) => { if (!whitelistedDimensionKeys.has(key)) throw new Error( `"${key}" is not a supported metric.Supported metrics can be found in adapters/types.ts`, ); }); volumes.forEach((element) => { const item: any = {}; Object.entries(element).forEach(([attribute, value]) => { if (attribute === "timestamp" && !value) return; if (!exclude2Print.includes(attribute)) { const valueFormatted = typeof value === "object" ? JSON.stringify(value, null, 2) : attribute === "timestamp" ? value + ` (${new Date((value as any) * 1e3).toISOString()})` : humanizeNumber(Number(value)); item[getLabel(attribute)] = valueFormatted; } }); if (element.startTimestamp !== undefined && element.startTimestamp !== 0) item["Start Time"] = formatTimestampAsDate( String(element.startTimestamp), ); printTable[element.chain] = item; }); if (volumes.length > 1) { const aggregated: any = {}; const aggData: any = {}; const ignoredKeySet = new Set(exclude2Print); volumes.forEach((element) => { for (const [key, value] of Object.entries(element)) { if (!ignoredKeySet.has(key)) { if (aggData[key] === undefined) aggData[key] = 0; aggData[key] += value; } } }); Object.entries(aggData).forEach(([key, value]) => { aggregated[getLabel(key)] = typeof value === "object" ? JSON.stringify(value, null, 2) : humanizeNumber(Number(value)); }); printTable["Aggregate"] = aggregated; } // console.table(printTable) const entries = Object.entries(printTable).map(([key, value]: any) => ({ chain: key, ...value, })); console.log(sdk.util.tableToString(entries)); } function getLabel(key: string) { return camelCaseToSpaces(key === "timestamp" ? "endTimestamp" : key); } export function formatTimestampAsDate(timestamp: string) { const date = new Date(Number(timestamp) * 1000); return `${date.getUTCDate()}/${date.getUTCMonth() + 1}/${date.getUTCFullYear()}`; } export function upperCaseFirst(t: string) { return t[0].toUpperCase() + t.slice(1); } export function camelCaseToSpaces(s: string) { const withSpaces = s // insert a space before all caps .replace(/([A-Z])/g, " $1") // uppercase the first character .replace(/^./, function (str) { return str.toUpperCase(); }); return withSpaces[0] + withSpaces.slice(1).toLowerCase(); } // move timestamp attr to the end of given object const timestampKey = "timestamp"; export function timestampLast(item: any): any { const newItem: any = {}; // iterate over all keys in the original object for (const key in item) { if (key !== timestampKey) { // Add keys that are not the one to move to the new object first newItem[key] = item[key]; } } // Add the key to move at the end if (item.hasOwnProperty(timestampKey)) { newItem[timestampKey] = item[timestampKey]; } return newItem; } export function printBreakdownFeesByLabel(breakdownByLabel: any) { if (breakdownByLabel) { console.log('') console.log('') console.info('FEES BREAKDOWN', '👇'); console.log('') const entries: any = {} for (const dataKey of Object.values(['dailyFees', 'dailySupplySideRevenue', 'dailyRevenue', 'dailyHoldersRevenue'])) { if (breakdownByLabel[dataKey]) { for (const [label, value] of Object.entries(breakdownByLabel[dataKey])) { entries[label] = entries[label] || { label: label }; const dataKeyLabel = getLabel(dataKey); entries[label][dataKeyLabel] = entries[label][dataKeyLabel] ? entries[label][dataKeyLabel] + value : value; } } } console.log(sdk.util.tableToString(Object.values(entries))); } } ================================================ FILE: dexs/0x-limit.ts ================================================ import { SimpleAdapter, FetchV2 } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; const config = { [CHAIN.ETHEREUM]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.POLYGON]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.BSC]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.OPTIMISM]: { exchange: '0xdef1abe32c034e558cdd535791643c58a13acc10' }, [CHAIN.FANTOM]: { exchange: '0xdef189deaef76e379df891899eb5a00a94cbc250' }, [CHAIN.CELO]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.AVAX]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.ARBITRUM]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.BASE]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, } as { [chain: string]: { exchange: string } } const fetchERCLimit: FetchV2 = async ({ getLogs, chain, createBalances }) => { const dailyVolume = createBalances() const logs = await getLogs({ target: config[chain].exchange, eventAbi: "event LimitOrderFilled(bytes32 orderHash, address maker, address taker, address feeRecipient, address makerToken, address takerToken, uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount, uint128 takerTokenFeeFilledAmount, uint256 protocolFeePaid, bytes32 pool)" }) logs.forEach(log => dailyVolume.add(log.makerToken, log.makerTokenFilledAmount)) return { dailyVolume } } const adapters: any = {} Object.keys(config).forEach(chain => { adapters[chain] = { fetch: fetchERCLimit } }) const adapter: SimpleAdapter = { pullHourly: true, version: 2, adapter: adapters, } export default adapter; ================================================ FILE: dexs/0x-otc.ts ================================================ import { SimpleAdapter, FetchV2 } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; const config = { [CHAIN.ETHEREUM]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.POLYGON]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.BSC]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.OPTIMISM]: { exchange: '0xdef1abe32c034e558cdd535791643c58a13acc10' }, [CHAIN.FANTOM]: { exchange: '0xdef189deaef76e379df891899eb5a00a94cbc250' }, [CHAIN.CELO]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.AVAX]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.ARBITRUM]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.BASE]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, } as { [chain: string]: { exchange: string } } const fetchOTC: FetchV2 = async ({ getLogs, chain, createBalances }) => { const dailyVolume = createBalances() const logs = await getLogs({ target: config[chain].exchange, eventAbi: "event OtcOrderFilled(bytes32 orderHash, address maker, address taker, address makerToken, address takerToken, uint128 makerTokenFilledAmount, uint128 takerTokenFilledAmount)" }) logs.forEach(log => dailyVolume.add(log.makerToken, log.makerTokenFilledAmount)) return { dailyVolume } } const adapters: any = {} Object.keys(config).forEach(chain => { adapters[chain] = { fetch: fetchOTC } }) const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: adapters, } export default adapter; ================================================ FILE: dexs/0x-rfq.ts ================================================ import { SimpleAdapter, FetchV2 } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; const config = { [CHAIN.ETHEREUM]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.POLYGON]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.BSC]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.OPTIMISM]: { exchange: '0xdef1abe32c034e558cdd535791643c58a13acc10' }, [CHAIN.FANTOM]: { exchange: '0xdef189deaef76e379df891899eb5a00a94cbc250' }, [CHAIN.CELO]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.AVAX]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.ARBITRUM]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, [CHAIN.BASE]: { exchange: '0xdef1c0ded9bec7f1a1670819833240f027b25eff' }, } as { [chain: string]: { exchange: string } } const fetchRFQ: FetchV2 = async ({ getLogs, chain, createBalances }) => { const dailyVolume = createBalances() const logs = await getLogs({ target: config[chain].exchange, eventAbi: "event RfqOrderFilled(bytes32 orderHash, address maker, address taker, address makerToken, address takerToken, uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount, bytes32 pool)" }) logs.forEach(log => dailyVolume.add(log.makerToken, log.makerTokenFilledAmount)) return { dailyVolume } } const adapters: any = {} Object.keys(config).forEach(chain => { adapters[chain] = { fetch: fetchRFQ } }) const adapter: SimpleAdapter = { pullHourly: true, version: 2, adapter: adapters, } export default adapter; ================================================ FILE: dexs/10kswap/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; const historicalVolumeEndpoint = "https://api.10kswap.com/analytics" interface IVolumeall { volume: string; date: string; } const fetch = async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const historicalVolume: IVolumeall[] = (await fetchURL(historicalVolumeEndpoint))?.data.volumes; const dailyVolume = historicalVolume .find(dayItem => (new Date(dayItem.date).getTime() / 1000) === dayTimestamp)?.volume return { dailyVolume: dailyVolume, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.STARKNET]: { fetch, start: '2022-09-19' }, }, }; export default adapter; ================================================ FILE: dexs/1776meme/index.ts ================================================ import { Adapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; // Addresses const memeCenterAddr = "0xDFcB2aB25b7978C112E9E08a2c70d52b035F1776"; // Abi const buyAbi = "event BuyExecuted(address indexed token, address indexed baseToken, address indexed user, uint256 amountIn, uint256 amountOut, uint256 totalFee)"; const sellAbi = "event SellExecuted(address indexed token, address indexed baseToken, address indexed user, uint256 amountIn, uint256 amountOut, uint256 totalFee)"; const fetch = async ({ createBalances, getLogs, chain }: FetchOptions) => { const dailyVolume = createBalances(); const buyLogs = await getLogs({ target: memeCenterAddr, eventAbi: buyAbi }); for (const log of buyLogs) { dailyVolume.addToken(log.baseToken, log.amountIn); } const sellLogs = await getLogs({ target: memeCenterAddr, eventAbi: sellAbi }); for (const log of sellLogs) { dailyVolume.addToken(log.baseToken, log.amountOut); } return { dailyVolume, }; }; const methodology = { UserFees: "User pays 1% fees on each swap.", ProtocolRevenue: "Treasury receives 0.6% of each swap and 5% raised amount when token reached graduated MCP", Revenue: "All revenue generated comes from user fees.", Fees: "All fees comes from the user.", }; const adapter: Adapter = { version: 2, pullHourly: true, adapter: { [CHAIN.ETHEREUM]: {}, }, fetch, methodology, }; export default adapter; ================================================ FILE: dexs/1dex/index.ts ================================================ import { CHAIN } from "../../helpers/chains" import { httpGet } from "../../utils/fetchURL" async function fetch() { const endpoint = `https://api.1dex.com/24h-trade-info` const { data: { volume_usdt: dailyVolume } } = await httpGet(endpoint) return { dailyVolume, } } export default { adapter: { [CHAIN.EOS]: { fetch, start: "2025-04-15", runAtCurrTime: true, }, }, } ================================================ FILE: dexs/4swap/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { type SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = "https://safe-swap-api.pando.im/api/pairs" interface IAPIResponse { volume_24h: string; }; const fetch = async () => { const response: IAPIResponse[] = (await fetchURL(URL))?.data.pairs; const dailyVolume = response .reduce((acc, { volume_24h }) => acc + Number(volume_24h), 0); return { dailyVolume }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.MIXIN]: { fetch, runAtCurrTime: true, }, } }; export default adapter; ================================================ FILE: dexs/ArbitrumExchange-v2.ts ================================================ import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniV2LogAdapter } from "../helpers/uniswap"; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.ARBITRUM]: { fetch: getUniV2LogAdapter({ factory: '0x1C6E968f2E6c9DEC61DB874E28589fd5CE3E1f2c' }), }, }, } export default adapter; ================================================ FILE: dexs/ArbitrumExchange-v3.ts ================================================ import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniV3LogAdapter } from "../helpers/uniswap"; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.ARBITRUM]: { fetch: getUniV3LogAdapter({ factory: '0x855f2c70cf5cb1d56c15ed309a4dfefb88ed909e' }), start: '2023-05-09', }, }, } export default adapter; ================================================ FILE: dexs/FeeFree/index.ts ================================================ import { FetchOptions, FetchV2, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from "../../helpers/prices"; const SWAP_EVENT_ABI = "event Swap(address indexed sender, address indexed input, address indexed output, uint256 amountIn, uint256 amountOut, uint256 swapFee)"; const CONFIG = { [CHAIN.ZORA]: "0x0FeeCCFaa507d20c2b18a6381080C062d52DbF00", [CHAIN.BASE]: "0x0Fee3Fa06550723cbf8590AC2f769F2F603e4000", [CHAIN.SCROLL]: "0x0Feeb68668672B3d6bF3E01455164a24B266c400", }; const fetch: FetchV2 = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const address = CONFIG[options.chain]; const logs = await options.getLogs({ target: address, eventAbi: SWAP_EVENT_ABI, }); logs.forEach((log: any) => { const [,input, output, amountIn, amountOut, swapFee] = log; addOneToken({ balances: dailyVolume, chain: options.chain, token0: input, token1: output, amount0: amountIn, amount1: amountOut, }); dailyFees.addGasToken(swapFee); }); return { dailyVolume, dailyFees, } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.ZORA]: { fetch, start: '2024-12-17', }, [CHAIN.BASE]: { fetch, start: '2024-12-17', }, [CHAIN.SCROLL]: { fetch, start: '2024-12-17', }, } } export default adapter; ================================================ FILE: dexs/GUIDELINES.md ================================================ # DEX Volume Adapter Guidelines These guidelines apply to all adapters in the `dexs/` directory. ## Required Dimensions | Dimension | Required | Description | |-----------|----------|-------------| | `dailyVolume` | YES | Trading volume for the period | ## Volume Calculation Rules ### Spot DEX Volume - Track actual trading volume from swap events - Use on-chain data where possible - especially for chains with our indexer or significant volume - Watch for wash trading - be vigilant on low-fee chains ### Perpetual/Derivatives Volume - **Track TAKER volume ONLY** - do NOT double count by adding both taker and maker volumes - The taker is the party that initiates the trade against existing orders - This prevents inflating volume by 2x ## Data Sources (Preferred Order) 1. **On-chain event logs** - Most reliable, use `options.getLogs()` 2. **Subgraphs** - Good for protocols with maintained subgraphs 3. **Query engines** (Dune, Flipside, Allium) - For complex queries 4. **Protocol APIs** - Last resort, verify data accuracy ## Common Patterns ### Uniswap V2-style DEX ```typescript import { uniV2Exports } from '../helpers/uniswap'; export default uniV2Exports({ [CHAIN.ETHEREUM]: { factories: ['0x...'], fees: { type: 'fixed', feesPercentage: 0.3 } } }); ``` ### Uniswap V3-style DEX ```typescript import { uniV3Exports } from '../helpers/uniswap'; export default uniV3Exports({ [CHAIN.ETHEREUM]: { factory: '0x...' } }); ``` ### Custom Implementation ```typescript const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const logs = await options.getLogs({ target: CONTRACT, eventAbi: 'event Swap(address sender, uint256 amount0, uint256 amount1)' }); logs.forEach(log => { dailyVolume.add(token0, log.amount0); }); return { dailyVolume }; }; ``` ## Wash Trading Detection - Apply minimum TVL percentage rules for pools with very low fee percentages (like 0.01%) - Be extra vigilant on Solana due to lower transaction fees - Remove affected pairs during farming campaigns that incentivize wash trading ## Fees/Revenue Tracking If this adapter also tracks fees/revenue dimensions, follow the guidelines in `fees/GUIDELINES.md`. Include: - `dailyFees` - All swap fees collected - `dailyRevenue` - Protocol's portion of fees - `dailySupplySideRevenue` - LP's portion of fees - Appropriate breakdown labels and `breakdownMethodology` ## Common Mistakes to Avoid 1. Double-counting volume (counting both sides of a swap, or both taker+maker in perps) 2. Not filtering out wash trading 3. Missing multi-chain support when protocol exists on multiple chains 4. Not using helper functions when available (uniV2Exports, uniV3Exports) 5. Counting maker+taker volume for perpetuals instead of just taker volume ================================================ FILE: dexs/ICDex/index.ts ================================================ import { Adapter, FetchResultVolume } from "../../adapters/types" import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const fetch = async (): Promise => { let historicalVolume = (await fetchURL('https://gwhbq-7aaaa-aaaar-qabya-cai.raw.icp0.io/v1/latest')); let dailyVolume = 0; for (let key in historicalVolume) { dailyVolume = dailyVolume + Number(historicalVolume[key].usd_24h_volume); } return { dailyVolume: dailyVolume, } }; const adapter: Adapter = { adapter: { [CHAIN.ICP]: { fetch: fetch, runAtCurrTime: true, start: '2024-01-16', }, } }; export default adapter; ================================================ FILE: dexs/MantisSwap/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import type { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; type PoolData = { total_volume: number; daily_volume: number; }; const fetch = (chain: string) => async (timestamp: number) => { const from = timestamp - 86400; // 60*60*24 const to = timestamp; const stats: PoolData = await fetchURL( `https://api.mantissa.finance/api/pool/stats/volume/${chain}/?from_timestamp=${from}&to_timestamp=${to}` ); return { dailyVolume: `${stats.daily_volume}`, timestamp, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.POLYGON]: { fetch: fetch("137"), start: '2023-03-20', }, [CHAIN.POLYGON_ZKEVM]: { fetch: fetch("1101"), start: '2023-05-29', }, [CHAIN.MODE]: { fetch: fetch("34443"), start: '2024-03-06', }, }, }; export default adapter; ================================================ FILE: dexs/Scopuly/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; const historicalVolumeEndpoint = "https://api.scopuly.com/api/liquidity_pools_volume" interface IVolumeall { vol: number; time: number; } const fetch = async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const historicalVolume: IVolumeall[] = (await fetchURL(historicalVolumeEndpoint)); const dailyVolume = historicalVolume .find(dayItem => getUniqStartOfTodayTimestamp(new Date(Number(dayItem.time))) === dayTimestamp)?.vol return { dailyVolume: dailyVolume, timestamp: dayTimestamp, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.STELLAR]: { fetch, start: '2024-01-30', }, }, }; export default adapter; ================================================ FILE: dexs/SecuredFinance/index.ts ================================================ import { gql, request } from 'graphql-request'; import { FetchOptions, SimpleAdapter } from '../../adapters/types'; import { CHAIN } from '../../helpers/chains'; import ADDRESSES from '../../helpers/coreAssets.json'; const RECORDS = { [CHAIN.ETHEREUM]: { tokens: { '0x5553444300000000000000000000000000000000000000000000000000000000': ADDRESSES.ethereum.USDC, // USDC '0x5742544300000000000000000000000000000000000000000000000000000000': ADDRESSES.ethereum.WBTC, // WBTC '0x4554480000000000000000000000000000000000000000000000000000000000': ADDRESSES.ethereum.WETH, // WETH '0x61786c46494c0000000000000000000000000000000000000000000000000000': '0x6A7b717aE5Ed65F85BA25403D5063D368239828e', // axlFIL '0x4a50594300000000000000000000000000000000000000000000000000000000': '0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29', // JPYC Stablecoin }, subgraphEndpoint: 'https://api.studio.thegraph.com/query/64582/sf-prd-mainnet/version/latest', }, [CHAIN.ARBITRUM]: { tokens: { '0x5553444300000000000000000000000000000000000000000000000000000000': ADDRESSES.arbitrum.USDC_CIRCLE, // USDC '0x5742544300000000000000000000000000000000000000000000000000000000': ADDRESSES.arbitrum.WBTC, // WBTC '0x4554480000000000000000000000000000000000000000000000000000000000': ADDRESSES.arbitrum.WETH, // WETH }, subgraphEndpoint: 'https://api.studio.thegraph.com/query/64582/sf-prd-arbitrum-one/version/latest', }, [CHAIN.FILECOIN]: { tokens: { '0x46494c0000000000000000000000000000000000000000000000000000000000': '0x60E1773636CF5E4A227d9AC24F20fEca034ee25A', // WFIL '0x6946494c00000000000000000000000000000000000000000000000000000000': '0x690908f7fa93afC040CFbD9fE1dDd2C2668Aa0e0', // iFIL '0x777046494c000000000000000000000000000000000000000000000000000000': '0x57E3BB9F790185Cfe70Cc2C15Ed5d6B84dCf4aDb', // wpFIL '0x5553444643000000000000000000000000000000000000000000000000000000': '0x80B98d3aa09ffff255c3ba4A241111Ff1262F045', // USDFC }, subgraphEndpoint: 'https://api.goldsky.com/api/public/project_cm8i6ca9k24d601wy45zzbsrq/subgraphs/sf-filecoin-mainnet/latest/gn', }, }; const fetch = async (options: FetchOptions) => { // Get the UTC day start timestamp // GraphQL query to get the volume data for that day const chain = options.chain as CHAIN; const dateStr = new Date(options.startOfDay * 1000) .toISOString() .split('T')[0]; const query = gql` { dailyVolumes(where: { day: "${dateStr}" }) { volume currency } } `; // Make the request to The Graph const response = await request(RECORDS[chain].subgraphEndpoint, query); const dailyVolumes = response.dailyVolumes; const dailyVolume = options.createBalances(); dailyVolumes.forEach(v => { // Assuming volumeUSD needs conversion if not directly usable dailyVolume.add(RECORDS[chain].tokens[v.currency], v.volume); }); return { dailyVolume, }; }; // 🔁 Wrap it in the DeFiLlama adapter structure const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.ETHEREUM]: { fetch, start: '2023-12-15', }, [CHAIN.ARBITRUM]: { fetch, start: '2024-01-12', }, [CHAIN.FILECOIN]: { fetch, start: '2024-06-21', }, }, }; export default adapter; ================================================ FILE: dexs/SmarDex/abis.ts ================================================ export const usdnAbi = { vaultDepositEvent: "event ValidatedDeposit(address indexed to, address indexed validator, uint256 amountAfterFees, uint256 usdnMinted, uint256 timestamp)", vaultWithdrawalEvent: "event ValidatedWithdrawal(address indexed to, address indexed validator, uint256 amountWithdrawnAfterFees, uint256 usdnBurned, uint256 timestamp)", longOpenPositionEvent: "event InitiatedOpenPosition(address indexed owner, address indexed validator, uint40 timestamp, uint128 totalExpo, uint128 amount, uint128 startPrice, tuple(int24 tick, uint256 tickVersion, uint256 index) posId)", longClosePositionEvent: "event ValidatedClosePosition(address indexed validator, address indexed to, tuple(int24 tick, uint256 tickVersion, uint256 index) posId, uint256 amountReceived, int256 profit)", rebalancerDepositEvent: "event AssetsDeposited(address indexed user, uint256 amount, uint256 positionVersion)", rebalancerWithdrawalEvent: "event AssetsWithdrawn(address indexed user, address indexed to, uint256 amount)", liquidatedTickEvent: "event LiquidatedTick(int24 indexed tick, uint256 indexed oldTickVersion, uint256 liquidationPrice, uint256 effectiveTickPrice, int256 remainingCollateral)", liquidatorRewarded: "event LiquidatorRewarded (address indexed liquidator, uint256 rewards)", }; ================================================ FILE: dexs/SmarDex/config.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { getEnv } from "../../helpers/env"; import ADDRESSES from "../../helpers/coreAssets.json"; export const CONFIG = { SUBGRAPH: { API_KEY: getEnv("SMARDEX_SUBGRAPH_API_KEY"), GATEWAY: "https://subgraph.smardex.io/defillama", }, TOKENS: { USDN: "0xde17a000ba631c5d7c2bd9fb692efea52d90dee2", WSTETH: ADDRESSES.ethereum.WSTETH, }, CONTRACTS: { USDN: "0x656cb8c6d154aad29d8771384089be5b5141f01a", DIP_ACCUMULATOR: "0xaebcc85a5594e687f6b302405e6e92d616826e03", }, }; export const CHAIN_CONFIG = { GRAPH_URLS: { [CHAIN.ARBITRUM]: `${CONFIG.SUBGRAPH.GATEWAY}/arbitrum`, [CHAIN.BASE]: `${CONFIG.SUBGRAPH.GATEWAY}/base`, [CHAIN.BSC]: `${CONFIG.SUBGRAPH.GATEWAY}/bsc`, [CHAIN.ETHEREUM]: `${CONFIG.SUBGRAPH.GATEWAY}/ethereum`, [CHAIN.POLYGON]: `${CONFIG.SUBGRAPH.GATEWAY}/polygon`, }, START_TIMES: { [CHAIN.ARBITRUM]: 1689582249, [CHAIN.BASE]: 1691491872, [CHAIN.BSC]: 1689581494, [CHAIN.ETHEREUM]: 1678404995, [CHAIN.POLYGON]: 1689582144, }, }; export function getGraphHeaders() { const defaultHeaders = { "x-api-key": CONFIG.SUBGRAPH.API_KEY, }; return Object.keys(CHAIN_CONFIG.GRAPH_URLS).reduce( (acc, chain) => ({ ...acc, [chain]: defaultHeaders }), {} ); } ================================================ FILE: dexs/SmarDex/index.ts ================================================ import { ethers, Interface } from "ethers"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { DEFAULT_TOTAL_VOLUME_FIELD, getGraphDimensions2, } from "../../helpers/getUniSubgraph"; import { CHAIN_CONFIG, getGraphHeaders } from "./config"; import { USDNVolumeService } from "./usdn-volume"; const graphs = getGraphDimensions2({ graphUrls: CHAIN_CONFIG.GRAPH_URLS, graphRequestHeaders: getGraphHeaders(), totalVolume: { factory: "smardexFactories", field: DEFAULT_TOTAL_VOLUME_FIELD, }, }); const adapter: SimpleAdapter = { adapter: {}, version: 2 }; Object.keys(CHAIN_CONFIG.GRAPH_URLS).forEach((chain: string) => { const subgraphFetching = graphs; adapter.adapter![chain] = { fetch: async (options: FetchOptions) => { try { const smardexDimensions = await subgraphFetching(options); if (chain === CHAIN.ETHEREUM) { const volumeService = new USDNVolumeService(options); const usdnVolume = await volumeService.getUsdnVolume(); smardexDimensions.dailyVolume = usdnVolume + Number(smardexDimensions.dailyVolume); } return { ...smardexDimensions, }; } catch (error) { console.error(`Error fetching data for ${chain}:`, error); return subgraphFetching(options) } }, start: CHAIN_CONFIG.START_TIMES[chain], }; }); export default adapter; ================================================ FILE: dexs/SmarDex/usdn-volume.ts ================================================ import { FetchOptions } from "../../adapters/types"; import { formatEther, ethers } from "ethers"; import { usdnAbi } from "./abis"; import { CONFIG } from "./config"; import { getPrices } from "../../utils/prices"; export class USDNVolumeService { private options: FetchOptions; constructor(options: FetchOptions) { this.options = options; } private getEventConfigs() { const { USDN, DIP_ACCUMULATOR } = CONFIG.CONTRACTS; const { USDN: USDN_TOKEN, WSTETH } = CONFIG.TOKENS; return [ { abi: usdnAbi.vaultDepositEvent, token: USDN_TOKEN, valueIndex: 3, contract: USDN, }, { abi: usdnAbi.vaultWithdrawalEvent, token: USDN_TOKEN, valueIndex: 3, contract: USDN, }, { abi: usdnAbi.longOpenPositionEvent, token: WSTETH, valueIndex: 3, contract: USDN, }, { abi: usdnAbi.longClosePositionEvent, token: WSTETH, valueIndex: 3, contract: USDN, }, { abi: usdnAbi.liquidatedTickEvent, token: WSTETH, valueIndex: 4, contract: USDN, }, { abi: usdnAbi.liquidatorRewarded, token: WSTETH, valueIndex: 1, contract: USDN, }, { abi: usdnAbi.rebalancerDepositEvent, token: WSTETH, valueIndex: 1, contract: DIP_ACCUMULATOR, }, { abi: usdnAbi.rebalancerWithdrawalEvent, token: WSTETH, valueIndex: 2, contract: DIP_ACCUMULATOR, }, ]; } public async getUsdnVolume(): Promise { let totalVolumeUsd = 0; const eventConfigs = this.getEventConfigs(); for (const config of eventConfigs) { const logs = await this.fetchEventLogs(config.abi, config.contract); const eventVolume = await this.calculateEventVolumeUsd(logs, config); totalVolumeUsd += eventVolume; } return totalVolumeUsd; } private async calculateEventVolumeUsd( logs: any[], config: { abi: any; token: string; valueIndex: number } ): Promise { if (!logs.length) return 0; let eventVolumeUsd = 0; const tokenApiKey = `ethereum:${config.token.toLowerCase()}`; const batchSize = 10; for (let i = 0; i < logs.length; i += batchSize) { const batch = logs.slice(i, i + batchSize); const volumes = await Promise.all( batch.map(async (log) => { try { const decodedData = this.decodeLog(log, config.abi); if (!decodedData) return 0; const block = await this.options.api.provider.getBlock( log.blockNumber ); if (!block) return 0; const priceData = await getPrices([tokenApiKey], block.timestamp); const price = this.validateNumber(priceData[tokenApiKey]?.price); const valueRaw = decodedData[config.valueIndex] || BigInt(0); const valueEther = parseFloat(formatEther(valueRaw)); return valueEther * price; } catch (error) { console.error("Error processing log:", error); return 0; } }) ); eventVolumeUsd += volumes.reduce((sum, val) => sum + val, 0); } return eventVolumeUsd; } private decodeLog(log: any, eventAbi: any): any { try { const i = new ethers.Interface([eventAbi]); return i.decodeEventLog(eventAbi, log.data, log.topics); } catch { return null; } } private async fetchEventLogs(eventAbi: any, target: string) { return this.options.getLogs({ eventAbi, target, }); } private validateNumber(value: any): number { if (value === undefined || value === null) return 0; const num = Number(value); return isNaN(num) ? 0 : num; } } ================================================ FILE: dexs/SubstanceX/index.ts ================================================ import * as sdk from "@defillama/sdk"; import { Adapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { request, gql, GraphQLClient } from "graphql-request"; import type { ChainEndpoints } from "../../adapters/types"; import { Chain } from "../../adapters/types"; const endpoints = { [CHAIN.ARBITRUM]: "https://gql.substancex.io/subgraphs/name/substanceexchangedevelop/coreprod", [CHAIN.ZETA]: "https://gql-zeta.substancex.io/subgraphs/name/substanceexchangedevelop/zeta" }; const blockNumberGraph = { [CHAIN.ARBITRUM]: "https://gql.substancex.io/subgraphs/name/substanceexchangedevelop/blocks", [CHAIN.ZETA]: "https://gql-zeta.substancex.io/subgraphs/name/substanceexchangedevelop/zeta-blocks" } const headers = { 'sex-dev': 'ServerDev' } as any const graphs = (graphUrls: ChainEndpoints) => { return (chain: Chain) => { return async (timestamp: number) => { // Get blockNumers const blockNumerQuery = gql` { blocks( where: {timestamp_lte:${timestamp}} orderBy: timestamp orderDirection: desc first: 1 ) { id number } } `; const last24hBlockNumberQuery = gql` { blocks( where: {timestamp_lte:${timestamp - 24 * 60 * 60}} orderBy: timestamp orderDirection: desc first: 1 ) { id number } } `; const blockNumberGraphQLClient = new GraphQLClient(blockNumberGraph[chain], { headers: chain === CHAIN.ZETA ? headers : headers, }); const graphQLClient = new GraphQLClient(graphUrls[chain], { headers: chain === CHAIN.ZETA ? headers : headers, }); const blockNumber = ( await blockNumberGraphQLClient.request(blockNumerQuery) ).blocks[0].number; const last24hBlockNumber = ( await blockNumberGraphQLClient.request(last24hBlockNumberQuery) ).blocks[0].number; // get total volume const tradeVolumeQuery = gql` { protocolMetrics(block:{number:${blockNumber}}){ totalVolume } } `; // get total volume 24 hours ago const lastTradeVolumeQuery = gql` { protocolMetrics(block:{number:${last24hBlockNumber}}){ totalVolume } } `; let tradeVolume = ( await graphQLClient.request(tradeVolumeQuery, { headers }) ).protocolMetrics[0].totalVolume let last24hTradeVolume = ( await graphQLClient.request(lastTradeVolumeQuery, { headers }) ).protocolMetrics[0].totalVolume const dailyVolume = (Number(tradeVolume) - Number(last24hTradeVolume)) / 10 ** 6 return { timestamp, dailyVolume: dailyVolume.toString(), }; } }; }; const adapter: Adapter = { adapter: { [CHAIN.ARBITRUM]: { fetch: graphs(endpoints)(CHAIN.ARBITRUM) as any, start: '2023-11-18', }, [CHAIN.ZETA]: { fetch: graphs(endpoints)(CHAIN.ZETA) as any, }, }, deadFrom: "2025-10-11", }; export default adapter; ================================================ FILE: dexs/aark/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const MoonOrderOpenedV2 = "event MoonOrderOpenedV2(address user, uint32 moonIndex, uint32 marketId, uint32 timestamp, uint64 entryPrice, int64 qty, uint16 leverage, int64 lastAccFundingFactor, uint64 takeProfit, uint48 initMargin, uint48 openFee, uint16 executionFee)"; const MoonOrderClosedV2 = "event MoonOrderClosedV2(address user, uint256 moonIndex, uint32 marketId, uint64 indexPrice, int48 pnl, uint48 closeFee, int48 fundingFee, uint48 userPayback, uint256 timestamp)"; const FuturesManager = '0x0b848a8A5eC8950E67d19E7a21A6Be29F44F685e'; export const inflatedMarkets = { "2026-04-23": [62n], "2026-04-24": [62n] //1000PEPE actual price 0.003 , but showing as 5$ due to glitch } const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const openData: any[] = await options.getLogs({ target: FuturesManager, eventAbi: MoonOrderOpenedV2, }); const positionQty = new Map(); const todaysInflatedMarkets = inflatedMarkets[options.dateString] || []; openData.forEach((log: any) => { if(todaysInflatedMarkets.includes(log.marketId)) { return; } const entryPrice = Number(log.entryPrice) / 1e8; const qty = Math.abs(Number(log.qty)) / (1e10); const openVolume = entryPrice * qty; positionQty.set(log.moonIndex, qty); dailyVolume.addUSDValue(openVolume); }); const closeData: any[] = await options.getLogs({ target: FuturesManager, eventAbi: MoonOrderClosedV2, }); closeData.forEach((log: any) => { if (positionQty.has(log.moonIndex)) { const qty = positionQty.get(log.moonIndex)!; if(todaysInflatedMarkets.includes(log.marketId)) { return; } const indexPrice = Number(log.indexPrice) / 1e8; const closeVolume = indexPrice * qty; dailyVolume.addUSDValue(closeVolume); positionQty.delete(log.moonIndex); } }); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, chains: [CHAIN.ARBITRUM], start: '2024-11-01', } export default adapter; ================================================ FILE: dexs/aborean/index.ts ================================================ import * as sdk from '@defillama/sdk'; import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from '../../helpers/prices'; import { ethers } from "ethers"; import PromisePool from "@supercharge/promise-pool"; import { handleBribeToken } from "./utils"; const CONFIG = { PoolFactory: '0xF6cDfFf7Ad51caaD860e7A35d6D4075d74039a6B', voter: '0xC0F53703e9f4b79fA2FB09a2aeBA487FA97729c9', GaugeFactory: '0x29BfEd845b1C10e427766b21d4533800B6f4e111' } const event_topics = { swap: '0xb3e2773606abfd36b5bd91394b3a54d1398336c65005baf7bf7a05efeffaf75b' } const eventAbis = { event_pool_created: 'event PoolCreated(address indexed token0,address indexed token1,bool indexed stable,address pool,uint256)', event_swap: 'event Swap(address indexed sender, address indexed to, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out)', event_gaugeCreated: 'event GaugeCreated(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory, address pool, address bribeVotingReward, address feeVotingReward, address gauge, address creator)', event_notify_reward: 'event NotifyReward(address indexed from, address indexed reward, uint256 indexed epoch, uint256 amount)', event_claim_rewards: 'event ClaimRewards(address indexed from, address indexed reward, uint256 amount)' } const abis = { fees: 'function getFee(address pool, bool _stable) external view returns (uint256)' } const getBribes = async (fetchOptions: FetchOptions): Promise<{ dailyBribesRevenue: sdk.Balances }> => { const { createBalances, startTimestamp } = fetchOptions const iface = new ethers.Interface([eventAbis.event_notify_reward]); const dailyBribesRevenue = createBalances() const logs_gauge_created = await fetchOptions.getLogs({ target: CONFIG.voter, fromBlock: 20524597, eventAbi: eventAbis.event_gaugeCreated, skipIndexer: true, cacheInCloud: true, }) if (!logs_gauge_created?.length) return { dailyBribesRevenue }; const bribes_contract: string[] = logs_gauge_created .filter((log) => log[2].toLowerCase() === CONFIG.GaugeFactory.toLowerCase()) .map((log) => log[4].toLowerCase()) const bribeSet = new Set(bribes_contract) // need to manually parse logs, auto parsing fails for some reason const logs = await fetchOptions.getLogs({ noTarget: true, eventAbi: eventAbis.event_notify_reward, entireLog: true, }) logs.forEach((log: any) => { const contract = (log.address || log.source).toLowerCase() if (!bribeSet.has(contract)) return; const parsedLog = iface.parseLog(log) const token = parsedLog!.args.reward.toLowerCase() const amount = parsedLog!.args.amount handleBribeToken(token, amount, startTimestamp, dailyBribesRevenue) }) return { dailyBribesRevenue } } const getVolumeAndFees = async (fromBlock: number, toBlock: number, fetchOptions: FetchOptions) => { const { createBalances, api, chain } = fetchOptions const dailyVolume = createBalances() const dailyFees = createBalances() const rawPools = await fetchOptions.getLogs({ target: CONFIG.PoolFactory, fromBlock: 20524597, eventAbi: eventAbis.event_pool_created, onlyArgs: true, cacheInCloud: true, skipIndexer: true, }) const fees = await api.multiCall({ abi: abis.fees, target: CONFIG.PoolFactory, calls: rawPools.map(i => ({ params: [i.pool, i.stable] })) }) const poolInfoMap = {} as any const aeroPoolSet = new Set() rawPools.forEach(({ token0, token1, stable, pool }, index) => { pool = pool.toLowerCase() const fee = fees[index] / 1e4 poolInfoMap[pool] = { token0, token1, stable, fee } aeroPoolSet.add(pool) }) const blockStep = 2000; let i = 0; let startBlock = fromBlock; let ranges: any = [] while (startBlock < toBlock) { const endBlock = Math.min(startBlock + blockStep - 1, toBlock) ranges.push([startBlock, endBlock]) startBlock += blockStep } let errorFound = false await PromisePool .withConcurrency(5) .for(ranges) .process(async ([startBlock, endBlock]: any) => { if (errorFound) return; try { const logs = await fetchOptions.getLogs({ noTarget: true, fromBlock: startBlock, toBlock: endBlock, eventAbi: eventAbis.event_swap, topics: [event_topics.swap], entireLog: true, skipCache: true, }) sdk.log(`Aborean got logs (${logs.length}) for ${i++}/ ${Math.ceil((toBlock - fromBlock) / blockStep)}`) const iface = new ethers.Interface([eventAbis.event_swap]); logs.forEach((log: any) => { const pool = (log.address || log.source).toLowerCase() if (!aeroPoolSet.has(pool)) return; const parsedLog = iface.parseLog(log) const { token0, token1, fee } = poolInfoMap[pool] const amount0 = Number(parsedLog!.args.amount0In) + Number(parsedLog!.args.amount0Out) const amount1 = Number(parsedLog!.args.amount1In) + Number(parsedLog!.args.amount1Out) const fee0 = amount0 * fee const fee1 = amount1 * fee addOneToken({ chain, balances: dailyVolume, token0, token1, amount0, amount1 }) addOneToken({ chain, balances: dailyFees, token0, token1, amount0: fee0, amount1: fee1 }) }) } catch (e) { errorFound = e throw e } }) if (errorFound) throw errorFound return { dailyVolume, dailyFees } } const fetch = async (_t: any, _a: any, options: FetchOptions): Promise => { const { getToBlock, getFromBlock } = options const [toBlock, fromBlock] = await Promise.all([getToBlock(), getFromBlock()]) const { dailyVolume, dailyFees } = await getVolumeAndFees(fromBlock, toBlock, options); const { dailyBribesRevenue } = await getBribes(options); return { dailyFees, dailyRevenue: dailyFees, dailyHoldersRevenue: dailyFees, dailyVolume, dailyBribesRevenue } } const adapters: SimpleAdapter = { version: 1, fetch, chains: [CHAIN.ABSTRACT], start: '2025-10-02' } export default adapters ================================================ FILE: dexs/aborean/utils.ts ================================================ import * as sdk from '@defillama/sdk'; export const handleBribeToken = ( token: string, amount: string, currentTimestamp: number, dailyBribesRevenue: sdk.Balances ): void => { dailyBribesRevenue.add(token, amount) return } ================================================ FILE: dexs/aborean-cl/index.ts ================================================ import * as sdk from '@defillama/sdk'; import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from '../../helpers/prices'; import { ethers } from "ethers"; import PromisePool from "@supercharge/promise-pool"; import { handleBribeToken } from "../aborean/utils"; const CONFIG = { factory: '0x8cfE21F272FdFDdf42851f6282c0f998756eEf27', voter: '0xC0F53703e9f4b79fA2FB09a2aeBA487FA97729c9', GaugeFactory: '0xF0361d1aD99971791C002E9c281B18739e9abad8' } const eventAbis = { event_poolCreated: 'event PoolCreated(address indexed token0, address indexed token1, int24 indexed tickSpacing, address pool)', event_swap: 'event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)', event_gaugeCreated: 'event GaugeCreated(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory, address pool, address bribeVotingReward, address feeVotingReward, address gauge, address creator)', event_notify_reward: 'event NotifyReward(address indexed from, address indexed reward, uint256 indexed epoch, uint256 amount)', event_claim_rewards: 'event ClaimRewards(address indexed from, address indexed reward, uint256 amount)', } const abis = { fee: 'uint256:fee' } const getBribes = async (fetchOptions: FetchOptions): Promise<{ dailyBribesRevenue: sdk.Balances }> => { const { createBalances, getLogs, startTimestamp } = fetchOptions const iface = new ethers.Interface([eventAbis.event_notify_reward]); const dailyBribesRevenue = createBalances() const logs_gauge_created = await getLogs({ target: CONFIG.voter, fromBlock: 20524597, eventAbi: eventAbis.event_gaugeCreated, cacheInCloud: true, }) if (!logs_gauge_created?.length) return { dailyBribesRevenue }; const bribes_contract: string[] = logs_gauge_created .filter((log) => log[2].toLowerCase() === CONFIG.GaugeFactory.toLowerCase()) .map((log) => log[4].toLowerCase()) const bribeSet = new Set(bribes_contract) const logs = await getLogs({ noTarget: true, eventAbi: eventAbis.event_notify_reward, entireLog: true, }) logs.forEach((log: any) => { const contract = (log.address || log.source).toLowerCase() if (!bribeSet.has(contract)) return; const parsedLog = iface.parseLog(log) const token = parsedLog!.args.reward.toLowerCase() const amount = parsedLog!.args.amount // Try to handle pre-launch token conversion handleBribeToken(token, amount, startTimestamp, dailyBribesRevenue) }) return { dailyBribesRevenue } } const fetch = async (_: any, _1: any, fetchOptions: FetchOptions): Promise => { const { api, createBalances, getToBlock, getFromBlock, chain, getLogs } = fetchOptions const dailyVolume = createBalances() const dailyFees = createBalances() const [toBlock, fromBlock] = await Promise.all([getToBlock(), getFromBlock()]) const rawPools = await getLogs({ target: CONFIG.factory, fromBlock: 20524597, toBlock, eventAbi: eventAbis.event_poolCreated, cacheInCloud: true, }) const _pools = rawPools.map((i: any) => i.pool.toLowerCase()) const fees = await api.multiCall({ abi: abis.fee, calls: _pools }) const aeroPoolSet = new Set() const poolInfoMap = {} as any rawPools.forEach(({ token0, token1, pool }, index) => { pool = pool.toLowerCase() const fee = fees[index] / 1e6 poolInfoMap[pool] = { token0, token1, fee } aeroPoolSet.add(pool) }) const blockStep = 1000; let i = 0; let startBlock = fromBlock; let ranges: any = [] const iface = new ethers.Interface([eventAbis.event_swap]); while (startBlock < toBlock) { const endBlock = Math.min(startBlock + blockStep - 1, toBlock) ranges.push([startBlock, endBlock]) startBlock += blockStep } let errorFound: any await PromisePool .withConcurrency(5) .for(ranges) .process(async ([startBlock, endBlock]: any) => { if (errorFound) return; try { const logs = await fetchOptions.getLogs({ noTarget: true, fromBlock: startBlock, toBlock: endBlock, eventAbi: eventAbis.event_swap, entireLog: true, skipCache: true, }) sdk.log(`Aborean cl got logs (${logs.length}) for ${i++}/ ${Math.ceil((toBlock - fromBlock) / blockStep)}`) logs.forEach((log: any) => { const pool = (log.address || log.source).toLowerCase() if (!aeroPoolSet.has(pool)) return; const { token0, token1, fee } = poolInfoMap[pool] const parsedLog = iface.parseLog(log) const amount0 = Number(parsedLog!.args.amount0) const amount1 = Number(parsedLog!.args.amount1) const fee0 = amount0 * fee const fee1 = amount1 * fee addOneToken({ chain, balances: dailyVolume, token0, token1, amount0, amount1 }) addOneToken({ chain, balances: dailyFees, token0, token1, amount0: fee0, amount1: fee1 }) }) } catch (e) { errorFound = e throw e } }) if (errorFound) throw errorFound const { dailyBribesRevenue } = await getBribes(fetchOptions) return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyHoldersRevenue: dailyFees, dailyBribesRevenue } } const adapters: SimpleAdapter = { version: 1, fetch, chains: [CHAIN.ABSTRACT], start: '2025-10-02', } export default adapters; ================================================ FILE: dexs/acala-swap/index.ts ================================================ import { gql, GraphQLClient } from "graphql-request"; import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const getDailyVolume = () => { return gql`{ dailyDexes(first:50, orderBy: TIMESTAMP_DESC) { nodes { timestamp dailyTradeVolumeUSD } } }` } const graphQLClient = new GraphQLClient(" https://api.polkawallet.io/acala-dex-subql"); const getGQLClient = () => { return graphQLClient } interface IGraphResponse { timestamp: string; dailyTradeVolumeUSD: string; } const fetch = async (timestamp: number) => { const dateString = new Date(timestamp * 1000).toISOString().split("T")[0]; const historicalVolume: IGraphResponse[] = (await getGQLClient().request(getDailyVolume())).dailyDexes.nodes; const dailyVolume = historicalVolume .find(dayItem => dayItem.timestamp.split('T')[0] === dateString)?.dailyTradeVolumeUSD if (Number(Number(dailyVolume) / 10 ** 18) > 250_000_000) throw new Error("Daily volume is too high"); return { dailyVolume: dailyVolume ? `${Number(dailyVolume) / 10 ** 18}` : undefined, }; } const adapter: SimpleAdapter = { adapter: { [CHAIN.ACALA]: { fetch, start: '2022-12-22' }, }, }; export default adapter; ================================================ FILE: dexs/adrena/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; const apiEndpoint = (fromTimestamp: number, toTimestamp: number) => { let url = `https://datapi.adrena.trade/poolinfodaily?start_date=${new Date(fromTimestamp * 1000).toISOString()}&end_date=${new Date(toTimestamp * 1000).toISOString()}`; url += '&cumulative_referrer_fee_usd=true'; url += '&cumulative_swap_fee_usd=true'; url += '&cumulative_liquidity_fee_usd=true'; url += '&cumulative_close_position_fee_usd=true'; url += '&cumulative_liquidation_fee_usd=true'; url += '&cumulative_borrow_fee_usd=true'; url += '&cumulative_trading_volume_usd=true'; return url; } async function fetch(_a: any, _b: any, options: FetchOptions) { const apiRes = await httpGet(apiEndpoint(options.fromTimestamp, options.toTimestamp)) const dailyVolume = apiRes.data.cumulative_trading_volume_usd[1] - apiRes.data.cumulative_trading_volume_usd[0]; if (apiRes.data.cumulative_trading_volume_usd[0] === 0 && options.dateString != '2024-11-19') { //throw new Error('Invalid data') return { dailyVolume: 0, dailyFees: 0, dailySupplySideRevenue: 0, dailyRevenue: 0, dailyHoldersRevenue: 0, dailyProtocolRevenue: 0, } } const cumulative_swap_fee_usd = apiRes.data.cumulative_swap_fee_usd[1] - apiRes.data.cumulative_swap_fee_usd[0]; const cumulative_liquidity_fee_usd = apiRes.data.cumulative_liquidity_fee_usd[1] - apiRes.data.cumulative_liquidity_fee_usd[0]; const cumulative_referrer_fee_usd = apiRes.data.cumulative_referrer_fee_usd[1] - apiRes.data.cumulative_referrer_fee_usd[0]; const cumulative_close_position_fee_usd = apiRes.data.cumulative_close_position_fee_usd[1] - apiRes.data.cumulative_close_position_fee_usd[0]; const cumulative_liquidation_fee_usd = apiRes.data.cumulative_liquidation_fee_usd[1] - apiRes.data.cumulative_liquidation_fee_usd[0]; const cumulative_borrow_fee_usd = apiRes.data.cumulative_borrow_fee_usd[1] - apiRes.data.cumulative_borrow_fee_usd[0]; const dailyFees = cumulative_swap_fee_usd + cumulative_liquidity_fee_usd + cumulative_referrer_fee_usd + cumulative_close_position_fee_usd + cumulative_liquidation_fee_usd + cumulative_borrow_fee_usd; const dailySupplySideRevenue = dailyFees * 0.7 const dailyRevenue = dailyFees - dailySupplySideRevenue; return { dailyVolume, dailyFees, dailySupplySideRevenue, dailyRevenue: dailyRevenue, dailyHoldersRevenue: dailyRevenue, dailyProtocolRevenue: 0, } } const adapter: SimpleAdapter = { adapter: { [CHAIN.SOLANA]: { start: '2024-11-18', } }, fetch, methodology: { Volume: 'Sum of all open/close/increase/liquidate position volumes.', Fees: 'All fees accrued by liquidity pools.', Revenue: '20% to gov token holder, 10% to buyback gov token, 0% to protocol.', SupplySideRevenue: "70% to pool token holders.", HoldersRevenue: '20% to gov token holder, 10% to buyback gov token, 0% to protocol.', }, } export default adapter; ================================================ FILE: dexs/aerodrome/index.ts ================================================ import * as sdk from '@defillama/sdk'; import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from '../../helpers/prices'; import { ethers } from "ethers"; import PromisePool from "@supercharge/promise-pool"; import { handleBribeToken } from "./utils"; const CONFIG = { PoolFactory: '0x420DD381b31aEf6683db6B902084cB0FFECe40Da', voter: '0x16613524e02ad97eDfeF371bC883F2F5d6C480A5', GaugeFactory: '0x35f35ca5b132cadf2916bab57639128eac5bbcb5' } const event_topics = { swap: '0xb3e2773606abfd36b5bd91394b3a54d1398336c65005baf7bf7a05efeffaf75b' } const eventAbis = { event_pool_created: 'event PoolCreated(address indexed token0,address indexed token1,bool indexed stable,address pool,uint256)', event_swap: 'event Swap(address indexed sender, address indexed to, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out)', event_gaugeCreated: 'event GaugeCreated(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory, address pool, address bribeVotingReward, address feeVotingReward, address gauge, address creator)', event_notify_reward: 'event NotifyReward(address indexed from, address indexed reward, uint256 indexed epoch, uint256 amount)', event_claim_rewards: 'event ClaimRewards(address indexed from, address indexed reward, uint256 amount)' } const abis = { fees: 'function getFee(address pool, bool _stable) external view returns (uint256)' } // One pass over GaugeCreated supplies both: pool->gauge (for staked-LP share) and // the bribe-contract set (for NotifyReward filtering). Filtered to the canonical // non-CL gauge factory. const getGaugeMetadata = async ( fetchOptions: FetchOptions, ): Promise<{ poolToGauge: Map; bribeSet: Set }> => { const logs = await fetchOptions.getLogs({ target: CONFIG.voter, fromBlock: 3200601, eventAbi: eventAbis.event_gaugeCreated, skipIndexer: true, cacheInCloud: true, }) const poolToGauge = new Map() const bribeSet = new Set() const factory = CONFIG.GaugeFactory.toLowerCase() for (const log of logs as any[]) { if (String(log[2]).toLowerCase() !== factory) continue poolToGauge.set(String(log[3]).toLowerCase(), String(log[6]).toLowerCase()) bribeSet.add(String(log[4]).toLowerCase()) } return { poolToGauge, bribeSet } } const getBribes = async ( fetchOptions: FetchOptions, bribeSet: Set, ): Promise<{ dailyBribesRevenue: sdk.Balances }> => { const { createBalances, startTimestamp } = fetchOptions const iface = new ethers.Interface([eventAbis.event_notify_reward]) const dailyBribesRevenue = createBalances() if (bribeSet.size === 0) return { dailyBribesRevenue } // need to manually parse logs, auto parsing fails for some reason const logs = await fetchOptions.getLogs({ noTarget: true, eventAbi: eventAbis.event_notify_reward, entireLog: true }) logs.forEach((log: any) => { const contract = (log.address || log.source).toLowerCase() if (!bribeSet.has(contract)) return const parsedLog = iface.parseLog(log) const token = parsedLog!.args.reward.toLowerCase() const amount = parsedLog!.args.amount handleBribeToken(token, amount, startTimestamp, dailyBribesRevenue) }) return { dailyBribesRevenue } } // Strategy A: per-pool staked share = pool.balanceOf(gauge) / pool.totalSupply. // Non-CL Aerodrome v2 has no unstaked-LP rake module, so all unstaked fees stay // with LPs. For each swap fee we split: holders = fee × stakedShare, // supplySide = fee × (1 - stakedShare). Pools without a gauge contribute 0 to // holders. Snapshot ratio is read at the cron block. const getVolumeFeesAndRevenue = async ( fromBlock: number, toBlock: number, fetchOptions: FetchOptions, poolToGauge: Map, ) => { const { createBalances, api, chain } = fetchOptions const dailyVolume = createBalances() const dailyFees = createBalances() const dailyHoldersRevenue = createBalances() const dailySupplySideRevenue = createBalances() const rawPools = await fetchOptions.getLogs({ target: CONFIG.PoolFactory, fromBlock: 3200668, eventAbi: eventAbis.event_pool_created, onlyArgs: true, cacheInCloud: true, skipIndexer: true }) const fees = await api.multiCall({ abi: abis.fees, target: CONFIG.PoolFactory, calls: rawPools.map(i => ({ params: [i.pool, i.stable] })) }) const ZERO_ADDR = '0x0000000000000000000000000000000000000000' const gaugeForPool = rawPools.map((p: any) => poolToGauge.get(String(p.pool).toLowerCase()) ?? ZERO_ADDR) const [stakedBalances, totalSupplies] = await Promise.all([ api.multiCall({ abi: 'function balanceOf(address) view returns (uint256)', calls: rawPools.map((p: any, i: number) => ({ target: p.pool, params: [gaugeForPool[i]] })), permitFailure: true, }), api.multiCall({ abi: 'erc20:totalSupply', calls: rawPools.map((p: any) => p.pool), permitFailure: true, }), ]) const poolInfoMap = {} as any const aeroPoolSet = new Set() rawPools.forEach(({ token0, token1, stable, pool }: any, index: number) => { pool = String(pool).toLowerCase() const fee = Number(fees[index]) / 1e4 const hasGauge = poolToGauge.has(pool) const totalSupply = Number(totalSupplies[index] ?? 0) const stakedSupply = Number(stakedBalances[index] ?? 0) let stakedShare = 0 if (hasGauge && totalSupply > 0) { stakedShare = Math.min(1, stakedSupply / totalSupply) } poolInfoMap[pool] = { token0, token1, stable, fee, stakedShare } aeroPoolSet.add(pool) }) const blockStep = 2000; let i = 0; let startBlock = fromBlock; let ranges: any = [] while (startBlock < toBlock) { const endBlock = Math.min(startBlock + blockStep - 1, toBlock) ranges.push([startBlock, endBlock]) startBlock += blockStep } let errorFound: any = false await PromisePool .withConcurrency(5) .for(ranges) .process(async ([startBlock, endBlock]: any) => { if (errorFound) return; try { const logs = await fetchOptions.getLogs({ noTarget: true, fromBlock: startBlock, toBlock: endBlock, eventAbi: eventAbis.event_swap, topics: [event_topics.swap], entireLog: true, skipCache: true, }) sdk.log(`Aerodrome got logs (${logs.length}) for ${i++}/ ${Math.ceil((toBlock - fromBlock) / blockStep)}`) const iface = new ethers.Interface([eventAbis.event_swap]); logs.forEach((log: any) => { const pool = (log.address || log.source).toLowerCase() if (!aeroPoolSet.has(pool)) return; const parsedLog = iface.parseLog(log) const { token0, token1, fee, stakedShare } = poolInfoMap[pool] const amount0 = Number(parsedLog!.args.amount0In) + Number(parsedLog!.args.amount0Out) const amount1 = Number(parsedLog!.args.amount1In) + Number(parsedLog!.args.amount1Out) const fee0 = amount0 * fee const fee1 = amount1 * fee addOneToken({ chain, balances: dailyVolume, token0, token1, amount0, amount1 }) addOneToken({ chain, balances: dailyFees, token0, token1, amount0: fee0, amount1: fee1 }) if (stakedShare > 0) { addOneToken({ chain, balances: dailyHoldersRevenue, token0, token1, amount0: fee0 * stakedShare, amount1: fee1 * stakedShare }) } if (stakedShare < 1) { const supplyShare = 1 - stakedShare addOneToken({ chain, balances: dailySupplySideRevenue, token0, token1, amount0: fee0 * supplyShare, amount1: fee1 * supplyShare }) } }) } catch (e) { errorFound = e throw e } }) if (errorFound) throw errorFound return { dailyVolume, dailyFees, dailyHoldersRevenue, dailySupplySideRevenue } } const fetch = async (options: FetchOptions): Promise => { const { getToBlock, getFromBlock } = options const [toBlock, fromBlock] = await Promise.all([getToBlock(), getFromBlock()]) const { poolToGauge, bribeSet } = await getGaugeMetadata(options) const [{ dailyVolume, dailyFees, dailyHoldersRevenue, dailySupplySideRevenue }, { dailyBribesRevenue }] = await Promise.all([ getVolumeFeesAndRevenue(fromBlock, toBlock, options, poolToGauge), getBribes(options, bribeSet), ]) return { dailyFees, dailyRevenue: dailyHoldersRevenue, dailyHoldersRevenue, dailySupplySideRevenue, dailyVolume, dailyBribesRevenue, } } const methodology = { Fees: "Total swap fees paid by traders. Per-pool fee rate read from PoolFactory.getFee (default sAMM 0.05%, vAMM 0.30%; customizable per pool) applied to each swap's input amount.", Revenue: "veAERO holders' share of swap fees, equal to HoldersRevenue (Aerodrome's zero-leak model routes all protocol revenue to voters).", HoldersRevenue: "Fees earned by LPs staked in the gauge — forwarded to FeeVotingReward for distribution to veAERO voters. Computed per pool as fees × pool.balanceOf(gauge) / pool.totalSupply.", SupplySideRevenue: "Unstaked LPs' pro-rata share of swap fees, claimable directly from the pool. Computed per pool as fees × (1 − stakedShare). Aerodrome v2 has no unstaked-LP rake module, so unstaked LPs keep 100% of their share.", BribesRevenue: "External bribes deposited to BribeVotingReward contracts (NotifyReward events filtered to the v2 GaugeFactory). Pre-launch tokens are priced via hardcoded conversion rates until each token's cutoff timestamp; afterwards DefiLlama spot pricing is used.", } const breakdownMethodology = { Fees: { 'Swap fees': 'All swap fees paid by traders on Aerodrome v2 pools.', }, Revenue: { 'Holders fees': 'Staked-LP share of swap fees, forwarded to veAERO voters via FeeVotingReward.', }, HoldersRevenue: { 'Holders fees': 'Staked-LP share of swap fees, forwarded to veAERO voters via FeeVotingReward.', }, SupplySideRevenue: { 'LP fees': 'Unstaked-LP pro-rata share of swap fees, claimable directly from the pool.', }, BribesRevenue: { 'External bribes': "Token deposits to a pool's BribeVotingReward contract that veAERO voters claim by voting for the pool's gauge.", }, } const adapters: SimpleAdapter = { version: 2, // pullHourly: true, fetch, chains: [CHAIN.BASE], start: '2023-08-28', methodology, breakdownMethodology, } export default adapters ================================================ FILE: dexs/aerodrome/utils.ts ================================================ import * as sdk from '@defillama/sdk'; export const PRE_LAUNCH_TOKEN_PRICING = { '0x11dc28d01984079b7efe7763b533e6ed9e3722b9': { decimals: 18, conversionRate: 1.5887, cutoffTimestamp: 1758240000 }, '0xf732a566121fa6362e9e0fbdd6d66e5c8c925e49': { decimals: 18, conversionRate: 0.15, cutoffTimestamp: 1761782400 }, '0x9126236476efba9ad8ab77855c60eb5bf37586eb': { decimals: 18, conversionRate: 0.025, cutoffTimestamp: 1766188800 }, '0x194f360d130f2393a5e9f3117a6a1b78abea1624': { decimals: 18, conversionRate: 0.01208, cutoffTimestamp: 1769126400 }, '0x8e4cbbcc33db6c0a18561fde1f6ba35906d4848b': { decimals: 18, conversionRate: 0.07245, cutoffTimestamp: 1775088000 }, '0x6E84030FA86EBf585E3E18fe557e5612f7e93Bff': { decimals: 18, conversionRate: 0.06, cutoffTimestamp: 1778716800 } } // Pricing rule for tokens in PRE_LAUNCH_TOKEN_PRICING: // currentTimestamp < cutoffTimestamp → hardcoded conversionRate (token has no market price yet) // currentTimestamp >= cutoffTimestamp → DefiLlama spot price via balances.add (token is live) // Tokens not in the map always use balances.add. export const handleBribeToken = ( token: string, amount: string, currentTimestamp: number, dailyBribesRevenue: sdk.Balances ): void => { const tokenConfig = PRE_LAUNCH_TOKEN_PRICING[token.toLowerCase()] if (!tokenConfig || currentTimestamp >= tokenConfig.cutoffTimestamp) { dailyBribesRevenue.add(token, amount) return } const convertedAmount = (Number(amount) * tokenConfig.conversionRate) / (10 ** tokenConfig.decimals) dailyBribesRevenue.addUSDValue(convertedAmount) } ================================================ FILE: dexs/aerodrome-slipstream/index.ts ================================================ import * as sdk from '@defillama/sdk'; import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from '../../helpers/prices'; import { ethers } from "ethers"; import PromisePool from "@supercharge/promise-pool"; import { handleBribeToken } from "../aerodrome/utils"; const CONFIG = { factories: [ { address: '0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A', fromBlock: 13843704, skipIndexer: true, }, { address: '0xaDe65c38CD4849aDBA595a4323a8C7DdfE89716a', fromBlock: 36953918, skipIndexer: false, }, { address: '0xf8f2eB4940CFE7d13603DDDD87f123820Fc061Ef', fromBlock: 44394724, skipIndexer: false, } ], voter: '0x16613524e02ad97eDfeF371bC883F2F5d6C480A5', gaugeFactories: [ '0xd30677bd8dd15132f251cb54cbda552d2a05fb08', '0xB630227a79707D517320b6c0f885806389dFcbB3', ].map(f => f.toLowerCase()), } const eventAbis = { event_poolCreated: 'event PoolCreated(address indexed token0, address indexed token1, int24 indexed tickSpacing, address pool)', event_swap: 'event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)', event_gaugeCreated: 'event GaugeCreated(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory, address pool, address bribeVotingReward, address feeVotingReward, address gauge, address creator)', event_notify_reward: 'event NotifyReward(address indexed from, address indexed reward, uint256 indexed epoch, uint256 amount)', event_claim_rewards: 'event ClaimRewards(address indexed from, address indexed reward, uint256 amount)', // Emitted by CLPool when the gauge withdraws accumulated gaugeFees via collectFees(recipient, ...). event_collect_fees: 'event CollectFees(address indexed recipient, uint128 amount0, uint128 amount1)', } const abis = { fee: 'uint256:fee', // Per-token accumulator of fees waiting for the gauge to collect. Per Aerodrome team's // confirmation, this is the on-chain ground truth for "fee rewards to voters" — capturing // the staked-LP share plus the unstaked-LP rake routed to the gauge. Resets when // collectFees() is called. gaugeFees: 'function gaugeFees() view returns (uint128 token0, uint128 token1)', } const getGaugeMetadata = async ( fetchOptions: FetchOptions, ): Promise<{ bribeSet: Set }> => { const logs = await fetchOptions.getLogs({ target: CONFIG.voter, fromBlock: 13843704, eventAbi: eventAbis.event_gaugeCreated, skipIndexer: true, cacheInCloud: true, }) const bribeSet = new Set() for (const log of logs as any[]) { if (!CONFIG.gaugeFactories.includes(String(log[2]).toLowerCase())) continue bribeSet.add(String(log[4]).toLowerCase()) } return { bribeSet } } const getBribes = async ( fetchOptions: FetchOptions, bribeSet: Set, ): Promise<{ dailyBribesRevenue: sdk.Balances }> => { const { createBalances, getLogs, startTimestamp } = fetchOptions const iface = new ethers.Interface([eventAbis.event_notify_reward]) const dailyBribesRevenue = createBalances() if (bribeSet.size === 0) return { dailyBribesRevenue } const logs = await getLogs({ noTarget: true, eventAbi: eventAbis.event_notify_reward, entireLog: true }) logs.forEach((log: any) => { const contract = (log.address || log.source).toLowerCase() if (!bribeSet.has(contract)) return const parsedLog = iface.parseLog(log) const token = parsedLog!.args.reward.toLowerCase() const amount = parsedLog!.args.amount // Try to handle pre-launch token conversion handleBribeToken(token, amount, startTimestamp, dailyBribesRevenue) }) return { dailyBribesRevenue } } const fetch = async (fetchOptions: FetchOptions): Promise => { const { api, fromApi, createBalances, getToBlock, getFromBlock, chain, getLogs } = fetchOptions const dailyVolume = createBalances() const dailyFees = createBalances() // Strategy B (slipstream): per-pool exact split. // holders_per_token = gaugeFees(toBlock) - gaugeFees(fromBlock) + Σ CollectFees in [fromBlock, toBlock] // total_per_token = Σ (input-side amount × feeRate) over swaps in this pool // supplySide_per_token = total_per_token − holders_per_token // gaugeFees resets when the gauge calls collectFees(); CollectFees event captures the drain. const dailyHoldersRevenue = createBalances() const dailySupplySideRevenue = createBalances() const [toBlock, fromBlock] = await Promise.all([getToBlock(), getFromBlock()]) const { bribeSet } = await getGaugeMetadata(fetchOptions) let rawPools: Array = [] for (const factory of CONFIG.factories) { const factoryLogs = await getLogs({ target: factory.address, fromBlock: factory.fromBlock, toBlock, eventAbi: eventAbis.event_poolCreated, skipIndexer: factory.skipIndexer, cacheInCloud: true, }) rawPools = rawPools.concat(factoryLogs) } const _pools = rawPools.map((i: any) => i.pool.toLowerCase()) const [fees, gaugeFeesStart, gaugeFeesEnd] = await Promise.all([ api.multiCall({ abi: abis.fee, calls: _pools }), fromApi.multiCall({ abi: abis.gaugeFees, calls: _pools, permitFailure: true }), api.multiCall({ abi: abis.gaugeFees, calls: _pools, permitFailure: true }), ]) const aeroPoolSet = new Set() const poolInfoMap = {} as any rawPools.forEach(({ token0, token1, pool }, index) => { pool = pool.toLowerCase() const fee = Number(fees[index]) / 1e6 poolInfoMap[pool] = { token0, token1, fee } aeroPoolSet.add(pool) }) // Per-pool, per-token input-only fee accumulators (fee taken on the input side // only — matches the on-chain accounting and is what totals must reconcile to // when split into holders + supplySide). const poolFeeTotals: Record = {} const blockStep = 1000; let i = 0; let startBlock = fromBlock; let ranges: any = [] const iface = new ethers.Interface([eventAbis.event_swap]); while (startBlock < toBlock) { const endBlock = Math.min(startBlock + blockStep - 1, toBlock) ranges.push([startBlock, endBlock]) startBlock += blockStep } let errorFound: any = false await PromisePool .withConcurrency(5) .for(ranges) .process(async ([startBlock, endBlock]: any) => { if (errorFound) return; try { const logs = await fetchOptions.getLogs({ noTarget: true, fromBlock: startBlock, toBlock: endBlock, eventAbi: eventAbis.event_swap, entireLog: true, skipCache: true, }) sdk.log(`Aerodrome slipstream got logs (${logs.length}) for ${i++}/ ${Math.ceil((toBlock - fromBlock) / blockStep)}`) logs.forEach((log: any) => { const pool = (log.address || log.source).toLowerCase() if (!aeroPoolSet.has(pool)) return; const { token0, token1, fee } = poolInfoMap[pool] const parsedLog = iface.parseLog(log) const amount0 = Number(parsedLog!.args.amount0) const amount1 = Number(parsedLog!.args.amount1) addOneToken({ chain, balances: dailyVolume, token0, token1, amount0, amount1 }) // Fees are taken from the input side. amount0 > 0 means token0 was input. if (!poolFeeTotals[pool]) poolFeeTotals[pool] = { fee0: 0, fee1: 0 } if (amount0 > 0) poolFeeTotals[pool].fee0 += amount0 * fee if (amount1 > 0) poolFeeTotals[pool].fee1 += amount1 * fee }) } catch (e) { errorFound = e throw e } }) if (errorFound) throw errorFound // Drains of gaugeFees in [fromBlock, toBlock]: needed so gaugeFees(end) − gaugeFees(start) // doesn't go negative across an epoch boundary where collectFees() was called. const collectIface = new ethers.Interface([eventAbis.event_collect_fees]) const collectLogs = await getLogs({ noTarget: true, fromBlock, toBlock, eventAbi: eventAbis.event_collect_fees, entireLog: true, skipCache: true, }) const collectedByPool: Record = {} for (const log of collectLogs as any[]) { const pool = String(log.address ?? log.source ?? '').toLowerCase() if (!aeroPoolSet.has(pool)) continue const parsed = collectIface.parseLog(log) if (!collectedByPool[pool]) collectedByPool[pool] = { c0: 0, c1: 0 } collectedByPool[pool].c0 += Number(parsed!.args.amount0) collectedByPool[pool].c1 += Number(parsed!.args.amount1) } // Roll up per-pool totals into the three balances. rawPools.forEach(({ token0, token1, pool }, index) => { pool = String(pool).toLowerCase() const totals = poolFeeTotals[pool] if (!totals || (totals.fee0 === 0 && totals.fee1 === 0)) return const start = gaugeFeesStart[index] ?? null const end = gaugeFeesEnd[index] ?? null const startToken0 = Number(start?.token0 ?? start?.[0] ?? 0) const startToken1 = Number(start?.token1 ?? start?.[1] ?? 0) const endToken0 = Number(end?.token0 ?? end?.[0] ?? 0) const endToken1 = Number(end?.token1 ?? end?.[1] ?? 0) const collected = collectedByPool[pool] ?? { c0: 0, c1: 0 } let holders0 = endToken0 - startToken0 + collected.c0 let holders1 = endToken1 - startToken1 + collected.c1 // Negative deltas can show up only from data noise (state read at a block past the // window's end, or a missed CollectFees log). Clamp to [0, totals] so the breakdown // can't push supplySide negative. if (holders0 < 0) holders0 = 0 if (holders1 < 0) holders1 = 0 if (holders0 > totals.fee0) holders0 = totals.fee0 if (holders1 > totals.fee1) holders1 = totals.fee1 const supply0 = totals.fee0 - holders0 const supply1 = totals.fee1 - holders1 // Sum both sides per pool — fee0 is the input-side fees from token0-input swaps, // fee1 is from token1-input swaps; they're independent contributions and must // BOTH be priced and added. addOneToken would drop one side because it's // designed for per-swap calls (where exactly one side carries the fee), not for // the per-pool rollup we have here after summing input-side fees separately. if (totals.fee0 > 0) dailyFees.add(token0, totals.fee0) if (totals.fee1 > 0) dailyFees.add(token1, totals.fee1) if (holders0 > 0) dailyHoldersRevenue.add(token0, holders0) if (holders1 > 0) dailyHoldersRevenue.add(token1, holders1) if (supply0 > 0) dailySupplySideRevenue.add(token0, supply0) if (supply1 > 0) dailySupplySideRevenue.add(token1, supply1) }) const { dailyBribesRevenue } = await getBribes(fetchOptions, bribeSet) return { dailyVolume, dailyFees, dailyRevenue: dailyHoldersRevenue, dailyHoldersRevenue, dailySupplySideRevenue, dailyBribesRevenue, } } const methodology = { Fees: "Total swap fees paid by traders. Per-pool fee rate read from CLPool.fee() (tickSpacing-based default, customizable) applied to each swap's input amount.", Revenue: "veAERO holders' share of swap fees, equal to HoldersRevenue (Aerodrome's zero-leak model routes all protocol revenue to voters).", HoldersRevenue: "Sum of (a) staked-LP fees and (b) the unstaked-LP rake (CLFactory.getUnstakedFee, default 10% of unstaked share), both routed into the gauge's CLPool.gaugeFees() accumulator. Measured on-chain as gaugeFees(toBlock) − gaugeFees(fromBlock) plus CollectFees event amounts (which drain the accumulator each Voter.distribute call).", SupplySideRevenue: "Unstaked LPs' net share of swap fees after the rake, accruing via the pool's feeGrowthGlobal. Computed per pool as Fees − HoldersRevenue.", BribesRevenue: "External bribes deposited to BribeVotingReward contracts (NotifyReward events filtered to slipstream GaugeFactories). Pre-launch tokens are priced via hardcoded conversion rates until each token's cutoff timestamp; afterwards DefiLlama spot pricing is used.", } const breakdownMethodology = { Fees: { 'Swap fees': 'All swap fees paid by traders on Aerodrome Slipstream pools.', }, Revenue: { 'Staked-LP fees + unstaked-LP rake': "Both flow into the gauge's gaugeFees accumulator and are distributed to veAERO voters via FeeVotingReward.", }, HoldersRevenue: { 'Staked-LP fees + unstaked-LP rake': "Both flow into the gauge's gaugeFees accumulator and are distributed to veAERO voters via FeeVotingReward.", }, SupplySideRevenue: { 'Unstaked-LP fees': "Unstaked LPs' pro-rata share of swap fees, net of the unstaked-LP rake redirected to the gauge.", }, BribesRevenue: { 'External bribes': "Token deposits to a pool's BribeVotingReward contract that veAERO voters claim by voting for the pool's gauge.", }, } const adapters: SimpleAdapter = { version: 2, // pullHourly: true, methodology, breakdownMethodology, adapter: { [CHAIN.BASE]: { fetch: fetch as any, start: '2024-05-03', } } } export default adapters; ================================================ FILE: dexs/aevo/index.ts ================================================ import { SimpleAdapter } from "../../adapters/types"; import fetchURL from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { getTimestampAtStartOfNextDayUTC } from "../../utils/date"; interface IAevoVolumeResponse { daily_volume: string; total_volume: string; } // endTime is in nanoseconds export const aevoVolumeEndpoint = (endTime: number) => { return ( "https://api.aevo.xyz/statistics?instrument_type=PERPETUAL&end_time=" + endTime ); }; const adapter: SimpleAdapter = { adapter: { [CHAIN.ETHEREUM]: { fetch: fetchAevoVolumeData, start: '2023-04-14', }, }, }; export async function fetchAevoVolumeData( /** Timestamp representing the end of the 24 hour period */ timestamp: number ) { const dayTimestamp = getTimestampAtStartOfNextDayUTC(timestamp); const url = aevoVolumeEndpoint(dayTimestamp * 1e9); const aevoVolumeData = await getAevoVolumeData(url); const dailyVolume = Number(aevoVolumeData.daily_volume).toFixed(2); return { timestamp, dailyVolume, }; } async function getAevoVolumeData( endpoint: string ): Promise { return await fetchURL(endpoint); } export default adapter; ================================================ FILE: dexs/aftermath-fi-amm/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import { FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = "https://aftermath.finance/api/pools/volume-24hrs"; const fetch = async (): Promise => { return { dailyVolume: await fetchURL(URL) }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.SUI]: { fetch, runAtCurrTime: true, start: '2023-07-20' }, }, }; export default adapter; ================================================ FILE: dexs/aftermath-fi-perp/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet, httpPost } from "../../utils/fetchURL"; import PromisePool from "@supercharge/promise-pool"; const CCXT_MARKETS_URL = "https://aftermath.finance/api/ccxt/markets"; const CCXT_OHLCV_URL = "https://aftermath.finance/api/ccxt/OHLCV"; const fetch = async (_: any, __: any, options: FetchOptions) => { const markets: any[] = await httpGet(CCXT_MARKETS_URL); let dailyVolume = 0; const since = options.startOfDay * 1000; await PromisePool.withConcurrency(3).for( markets) .process(async (m: any) => { const candles = await httpPost(CCXT_OHLCV_URL, { chId: m.id, timeframe: "1d", since, limit: 1 }); if (Array.isArray(candles) && candles.length > 0) { dailyVolume += candles[0][5] || 0; // [ts, o, h, l, c, volume] } return candles; }); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 1, adapter: { [CHAIN.SUI]: { fetch, start: "2025-02-18", }, }, }; export default adapter; ================================================ FILE: dexs/agdex/index.ts ================================================ import { httpGet } from "../../utils/fetchURL"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { METRIC } from "../../helpers/metrics"; const url = "https://prod.backend.agdex.io/stats/data?timestamp="; const fetch = async (_timestamp: number, _t: any, options: FetchOptions) => { const date = options.startOfDay.toString(); const res: any = await httpGet(url + date); const data = res.data; const dailyFees = options.createBalances(); dailyFees.addUSDValue(Number(data.syncSqlResponse.result.rows[0].dailyFee), METRIC.SWAP_FEES); return { dailyVolume: `${ data.syncSqlResponse.result.rows[0].dailyVolume / Math.pow(10, 18) }`, dailyFees, }; }; const methodology = "Agdex is a DEX on Aptos. Fees are collected from token swaps."; const breakdownMethodology = { Fees: { [METRIC.SWAP_FEES]: 'Trading fees collected from token swaps on the Aptos DEX', } }; const adapter: SimpleAdapter = { adapter: { [CHAIN.APTOS]: { fetch, start: "2024-11-26", }, }, methodology, breakdownMethodology, deadFrom: "2025-09-01", }; export default adapter; ================================================ FILE: dexs/airswap/index.ts ================================================ import { Fetch, FetchOptions, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const event_swap = 'event SwapERC20(uint256 indexed nonce,address indexed signerWallet,address signerToken,uint256 signerAmount,uint256 protocolFee,address indexed senderWallet,address senderToken,uint256 senderAmount)'; type TAddress = { [c: string]: string; } const address: TAddress = { [CHAIN.ETHEREUM]: '0xd82fa167727a4dc6d6f55830a2c47abbb4b3a0f8', [CHAIN.POLYGON]: '0xd82fa167727a4dc6d6f55830a2c47abbb4b3a0f8', [CHAIN.AVAX]: '0xd82FA167727a4dc6D6F55830A2c47aBbB4b3a0F8', [CHAIN.BSC]: '0xd82fa167727a4dc6d6f55830a2c47abbb4b3a0f8', [CHAIN.ARBITRUM]: '0xd82FA167727a4dc6D6F55830A2c47aBbB4b3a0F8' } const fetch = (async (timestamp: number, _: any, { getLogs, createBalances, chain }: FetchOptions): Promise => { const dailyVolume = createBalances(); const logs = (await getLogs({ target: address[chain], eventAbi: event_swap, })) logs.forEach(i => dailyVolume.add(i.signerToken, i.signerAmount)) return { dailyVolume, timestamp, }; }) as Fetch const adapter: SimpleAdapter = { adapter: { [CHAIN.ETHEREUM]: { fetch, start: '2023-04-01', }, [CHAIN.POLYGON]: { fetch, start: '2023-04-01', }, [CHAIN.AVAX]: { fetch, start: '2023-04-01', }, [CHAIN.BSC]: { fetch, start: '2023-04-01', }, [CHAIN.ARBITRUM]: { fetch, start: '2023-07-20', }, } }; export default adapter; ================================================ FILE: dexs/alex/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { Chain } from "../../adapters/types"; import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; const historicalVolumeEndpoint = "https://alexgo-io.metabaseapp.com/api/public/dashboard/66cca0ba-7735-46c5-adfb-d80535506f4a/dashcard/464/card/496?parameters=%5B%5D" interface IVolumeall { volume: string; time: string; } const fetch = async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const callhistoricalVolume = (await fetchURL(historicalVolumeEndpoint)).data.rows; const historicalVolume: IVolumeall[] = callhistoricalVolume.map((e: string[] | number[]) => { const [time, volume] = e; return { time, volume }; }); const dailyVolume = historicalVolume .find(dayItem => (new Date(dayItem.time).getTime() / 1000) === dayTimestamp)?.volume return { dailyVolume: dailyVolume, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.STACKS]: { fetch, }, }, }; export default adapter; ================================================ FILE: dexs/allbridge-classic/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { BaseAdapter, Chain, FetchResultVolume, IJSON, SimpleAdapter } from '../../adapters/types'; import fetchURL from '../../utils/fetchURL'; interface ChainData { id: string; volume?: number; } const getVolume = async (chainCode: string, fromDate: string, toDate: string): Promise => { const url = `https://stats.a11bd.net/aggregated?dateFrom=${fromDate}&dateTo=${toDate}`; const responseBody = (await fetchURL(url)); const chainData = responseBody.data.chains .filter((d: ChainData) => d.id === chainCode) .pop(); return chainData?.volume ?? 0; } const getVolumeFunction = (chain: Chain) => { return async (timestamp: number): Promise => { if (chain === CHAIN.HECO) { return {}} // skip HECO for now const chainCode = chainCodeMap[chain]; const dateString = formatTimestampAsIsoDate(timestamp); const dailyVolume = await getVolume(chainCode, dateString, dateString); return { timestamp, dailyVolume: dailyVolume !== undefined ? String(dailyVolume) : undefined, } as FetchResultVolume; } } function formatTimestampAsIsoDate(timestamp: number) { return new Date(timestamp * 1000).toISOString().split("T")[0]; } const chainCodeMap: {[key: Chain]: string} = { [CHAIN.ETHEREUM]: "ETH", [CHAIN.BSC]: "BSC", [CHAIN.TERRA]: "TRA", [CHAIN.AURORA]: "AURO", [CHAIN.POLYGON]: "POL", [CHAIN.HECO]: "HECO", [CHAIN.CELO]: "CELO", [CHAIN.AVAX]: "AVA", [CHAIN.FANTOM]: "FTM", [CHAIN.FUSE]: "FUSE", [CHAIN.SOLANA]: "SOL", [CHAIN.NEAR]: "NEAR", [CHAIN.HARMONY]: "HRM", [CHAIN.TEZOS]: "TEZ", [CHAIN.KLAYTN]: "KLAY", [CHAIN.WAVES]: "WAVE", [CHAIN.STELLAR]: "XLM", [CHAIN.STACKS]: "STKS", } const startTimes = { [CHAIN.ETHEREUM]: 1636761600, [CHAIN.BSC]: 1636761600, [CHAIN.TERRA]: 1639008000, [CHAIN.AURORA]: 1639440000, [CHAIN.POLYGON]: 1636502400, [CHAIN.HECO]: 1636761600, [CHAIN.CELO]: 1636761600, [CHAIN.AVAX]: 1636761600, [CHAIN.FANTOM]: 1637452800, [CHAIN.FUSE]: 1640995200, [CHAIN.SOLANA]: 1636502400, [CHAIN.NEAR]: 1643673600, [CHAIN.HARMONY]: 1640995200, [CHAIN.TEZOS]: 1654387200, [CHAIN.KLAYTN]: 1660521600, [CHAIN.WAVES]: 1663200000, [CHAIN.STELLAR]: 1672358400, [CHAIN.STACKS]: 1690416000, } as IJSON; const adapter: SimpleAdapter = { adapter: Object.keys(chainCodeMap).reduce((acc, chain) => { acc[chain] = { fetch: getVolumeFunction(chain), start: startTimes[chain], }; return acc; }, {} as BaseAdapter) } export default adapter; ================================================ FILE: dexs/alpha-arcade/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const fetch = async (options: FetchOptions) => { let dailyVolume = 0; const { startTimestamp, endTimestamp } = options; const TARGET_APP_CALL_NAMES = [ 'uh3u9Q==', // MATCH 'gyGzvQ==', // SPLIT 'jF2wVg==', // MERGE 'MgBiOw==' // CLAIM ]; const toRFC3339 = (timestamp: number) => new Date(timestamp * 1000).toISOString(); const startRFC3339 = toRFC3339(startTimestamp); const endRFC3339 = toRFC3339(endTimestamp); const baseURL = `https://mainnet-idx.4160.nodely.dev/v2/transactions`; let nextToken: string | undefined = undefined; do { let url = `${baseURL}?min-round=1&max-round=999999999&after-time=${startRFC3339}&before-time=${endRFC3339}`; if (nextToken) { url += `&next=${nextToken}`; } const response = await fetchURL(url); const txns = response.transactions || []; const alphaArcadeTxns = txns.filter((txn) => hasAnyTargetAppArg(txn, TARGET_APP_CALL_NAMES)); for (const txn of alphaArcadeTxns) { if (hasAnyTargetAppArg(txn, ["uh3u9Q=="])) { // MATCH const amount = getInnerTxnAmountForAppCall(txn, 'uh3u9Q=='); dailyVolume += amount; } else if ( txn['application-transaction']?.['application-args']?.[0] === 'MgBiOw==' // CLAIM ) { const innerTxn = txn['inner-txns']?.[0]; const assetTransfer = innerTxn?.['asset-transfer-transaction']; if (assetTransfer && assetTransfer.amount) { dailyVolume += assetTransfer.amount; } } else if ( txn['application-transaction']?.['application-args']?.[0] === 'gyGzvQ==' || // SPLIT txn['application-transaction']?.['application-args']?.[0] === 'jF2wVg==' // MERGE ) { for (const innerTxn of txn['inner-txns'] || []) { const assetTransfer = innerTxn['asset-transfer-transaction']; const amount = assetTransfer?.amount || 0; dailyVolume += amount; } } } nextToken = response['next-token']; } while (nextToken); return { dailyVolume: dailyVolume / 1e6, // Convert from microUSDC }; }; function hasAnyTargetAppArg(txn: any, targetArgs: string[]): boolean { const appArgs = txn['application-transaction']?.['application-args']; if (Array.isArray(appArgs) && targetArgs.some(arg => appArgs.includes(arg))) { return true; } if (Array.isArray(txn['inner-txns'])) { return txn['inner-txns'].some((inner) => hasAnyTargetAppArg(inner, targetArgs)); } return false; }; function getInnerTxnAmountForAppCall(txn: any, targetArgBase64: string): number { let totalAmount = 0; if (txn["tx-type"] !== "appl" || !Array.isArray(txn["inner-txns"])) { return totalAmount; } for (const innerTxn of txn["inner-txns"]) { const appTxn = innerTxn["application-transaction"]; if ( appTxn && Array.isArray(appTxn["application-args"]) && appTxn["application-args"][0] === targetArgBase64 ) { if (!Array.isArray(innerTxn["inner-txns"])) { continue; } for (const nestedTxn of innerTxn["inner-txns"]) { if ( nestedTxn["tx-type"] === "axfer" && nestedTxn["asset-transfer-transaction"]?.amount ) { totalAmount += nestedTxn["asset-transfer-transaction"].amount; } } } } return totalAmount; } const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.ALGORAND]: { fetch: fetch, start: '2025-03-30', } } }; export default adapter; ================================================ FILE: dexs/alphaq/index.ts ================================================ import { Dependencies, FetchOptions, SimpleAdapter } from "../../adapters/types" import { CHAIN } from "../../helpers/chains" import { queryDuneSql } from "../../helpers/dune" // https://www.alphaq.xyz/docs const FEE_RATE = 0.00001; // 0.001% const fetch = async (_a:any, _b:any, options: FetchOptions) => { const query = ` with swaps as ( select tx_id , outer_instruction_index , inner_instruction_index from solana.instruction_calls where executing_account = 'ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA' and TIME_RANGE and tx_success = true ) select SUM(amount_usd) as daily_volume from tokens_solana.transfers t inner join swaps s on t.tx_id = s.tx_id and t.outer_instruction_index = s.outer_instruction_index and t.inner_instruction_index = s.inner_instruction_index + 1 where t.block_time >= from_unixtime(${options.startTimestamp}) and t.block_time <= from_unixtime(${options.endTimestamp}) ` const data = await queryDuneSql(options, query) const dailyVolume = data[0]?.daily_volume ?? 0 const dailyFees = Number(dailyVolume) * FEE_RATE return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, } } const adapter: SimpleAdapter = { fetch, dependencies: [Dependencies.DUNE], chains: [CHAIN.SOLANA], start: '2025-07-10', methodology: { Fees: 'Flat 0.001% fee per swap on major pairs.', Revenue: 'All fees are revenue collected by AlphaQ.', ProtocolRevenue: 'All fees are revenue collected by AlphaQ.', } } export default adapter ================================================ FILE: dexs/alphasec-spot.ts ================================================ import { SimpleAdapter, FetchOptions, ChainBlocks } from "../adapters/types"; import { httpGet } from "../utils/fetchURL"; import { CHAIN } from "../helpers/chains"; import { METRIC } from "../helpers/metrics"; const API_URL = "https://api.alphasec.trade/api/v1/defillama/stats"; const metrics = { TradingRebatesAndCommissions: "Trading Rebates and Commissions", }; const fetch = async (_ts: number, _: ChainBlocks, options: FetchOptions) => { const url = `${API_URL}?startOfDay=${options.startOfDay}`; const data = await httpGet(url); const stats = data.result; const dailyFees = options.createBalances(); const dailyRevenue = options.createBalances(); const dailySupplySideRevenue = options.createBalances(); dailyFees.addUSDValue(stats.dailyFees, METRIC.TRADING_FEES); dailyRevenue.addUSDValue(stats.dailyRevenue, METRIC.PROTOCOL_FEES); dailySupplySideRevenue.addUSDValue(stats.dailySupplySideRevenue, metrics.TradingRebatesAndCommissions); return { dailyVolume: stats.dailyVolume, dailyFees, dailyRevenue, dailySupplySideRevenue, }; }; const adapter: SimpleAdapter = { version: 1, fetch, chains: [CHAIN.ALPHASEC], start: '2025-12-02', methodology: { Volume: 'Total notional value of all trades executed on the AlphaSec DEX.', Fees: 'Total trading fees paid by users before any rebates or commissions are deducted.', SupplySideRevenue: 'Rebates and commissions paid to ecosystem participants.', Revenue: 'Total fees minus supply side revenue (rebates and commissions).', }, breakdownMethodology: { Fees: { [METRIC.TRADING_FEES]: 'Trading fees charged on all trades executed on the AlphaSec DEX, calculated as a percentage of trade notional value and paid by users before any rebates or incentives are applied.', }, Revenue: { [METRIC.PROTOCOL_FEES]: 'Protocol revenue retained by AlphaSec after paying out trading rebates and commissions to market makers, referrers, and other ecosystem participants.', }, SupplySideRevenue: { [metrics.TradingRebatesAndCommissions]: 'Trading rebates and commissions paid to ecosystem participants including market makers, referrers, and other liquidity providers to incentivize trading activity and liquidity provision.', }, }, }; export default adapter; ================================================ FILE: dexs/alphix.ts ================================================ import * as sdk from "@defillama/sdk"; import { FetchOptions, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; const SWAP_TOPIC = "0x40e9cecb9f5f1f1c5b9c97dec2917b7ee92e57ba5563708daca94dd84ad7112f"; type ChainConfig = { poolManager: string; pools: { id: string; token: string }[]; }; const config: Record = { [CHAIN.BASE]: { poolManager: "0x498581ff718922c3f8e6a244956af099b2652b2b", pools: [ { id: "0xebb666a5c6449b83536950b975d74deb32aca1537a501b58161a896816b04da6", token: "0x4200000000000000000000000000000000000006", // ETH/USDC (AlphixLVRFee) }, { id: "0x3860784278e9e481ffd0888430ab2af8f2bb1180069f31cde9e1066728bbe73b", token: "0x4200000000000000000000000000000000000006", // ETH/cbBTC (AlphixLVRFee) }, { id: "0x2d926f31a3b94ae9e0d22a0606f7684c9dbee8fcf46fae2ea68557ac1c48cb2d", token: "0x4200000000000000000000000000000000000006", // ETH/ZFI (AlphixPro) }, { id: "0xaf9168a5026bd5e398863dc1d0a0513fe21417792f9df4889571fd68d2d8cd71", token: "0x820c137fa70c8691f0e44dc420a5e53c168921dc", // USDS/USDC }, ], }, [CHAIN.ARBITRUM]: { poolManager: "0x360e68faccca8ca495c1b759fd9eee466db9fb32", pools: [ { id: "0xe2c28a234aadc40f115dcc56b70a759d02a372db90dfeed19048392d942ee286", token: "0xaf88d065e77c8cc2239327c5edb3a432268e5831", // USDC }, ], }, }; function decodeInt128(hex: string): bigint { const val = BigInt(hex); return val >= 1n << 127n ? val - (1n << 128n) : val; } async function fetch(options: FetchOptions) { const chainCfg = config[options.chain]; const dailyVolume = options.createBalances(); for (const pool of chainCfg.pools) { const logs = await sdk.getEventLogs({ chain: options.chain, target: chainCfg.poolManager, fromBlock: Number(options.fromApi.block), toBlock: Number(options.toApi.block), topics: [SWAP_TOPIC, pool.id], entireLog: true, }); for (const log of logs) { const data = log.data.slice(2); const amount0 = decodeInt128("0x" + data.slice(32, 64)); const absAmount0 = amount0 > 0n ? amount0 : -amount0; dailyVolume.add(pool.token, absAmount0); } } return { dailyVolume }; } const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.BASE]: { fetch, start: "2026-02-10", }, [CHAIN.ARBITRUM]: { fetch, start: "2026-03-07", }, }, doublecounted: true, }; export default adapter; ================================================ FILE: dexs/althea-dex.ts ================================================ import { FetchOptions, FetchV2, } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { addOneToken } from "../helpers/prices"; const DEX_ADDRESS = "0xd263DC98dEc57828e26F69bA8687281BA5D052E0"; const QUERY_HELPER_ADDRESS = "0xf7b59E4f71E467C0e409609A4a0688b073C56142"; const abi = { swap: 'event Swap(address indexed user, address indexed base, address indexed quote, uint256 poolIdx, bool isBuy, bool inBaseQty, uint128 qty, uint128 minOutput, int128 baseFlow, int128 quoteFlow)', queryPoolTemplate: 'function queryPoolTemplate (uint256 poolIdx) public view returns (uint8 schema_, uint16 feeRate_, uint8 protocolTake_, uint16 tickSize_, uint8 jitThresh_, uint8 knockoutBits_, uint8 oracleFlags_)', } const fetch: FetchV2 = async (options: FetchOptions) => { const dailyVolume = options.createBalances() const dailyFees = options.createBalances() const logs: any[] = await options.getLogs({ target: DEX_ADDRESS, eventAbi: abi.swap, }); const uniquePoolIdxs = new Set(); logs.forEach((log: any) => uniquePoolIdxs.add(Number(log.poolIdx))) const uniquePools = Array.from(uniquePoolIdxs) const uniqpuePoolInfoMap: { [key: number]: any } = {}; const feeRatesByIndex: { [key: number]: number } = {}; const poolInfos = await options.api.multiCall({ abi: abi.queryPoolTemplate, calls: uniquePools, target: QUERY_HELPER_ADDRESS }) poolInfos.forEach((info: any, idx: number) => { uniqpuePoolInfoMap[uniquePools[idx]] = info // The fee rate is in hundredths of a basis point, so to convert to the fee rate as a decimal divide by 10,000,000 feeRatesByIndex[uniquePools[idx]] = Number(info.feeRate_)/ 1e8; // Pre-fetch fee rates }) logs.forEach((log: any) => { const token0 = log.base const token1 = log.quote const amount0 = +log.baseFlow.toString() const amount1 = +log.quoteFlow.toString() const fee = feeRatesByIndex[Number(log.poolIdx)] if (fee === undefined) throw new Error(`Fee rate not found for poolIdx ${log.poolIdx}`) addOneToken({ balances: dailyVolume, token0, amount0, token1, amount1 }) addOneToken({ balances: dailyFees, token0, amount0: token0 * fee, token1, amount1: amount1 * fee }) }) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue: 0, dailySupplySideRevenue: dailyFees, dailyProtocolRevenue: 0 } } const methodology = { Volume: "iFi (Infrastructure Finance) DEX trade volume", Fees: "Trading fees are paid by users", UserFees: "All fees on iFi DEX are paid by users", Revenue: "iFi DEX doesnt take any fee share", ProtocolRevenue: "iFi DEX doesnt take any fee share", SupplySideRevenue: "All the trading fees go to liquidity providers", } export default { version: 2, pullHourly: true, fetch, chains: [CHAIN.ALTHEA_L1], start: '2025-10-07', methodology } ================================================ FILE: dexs/ambient/index.ts ================================================ import PromisePool from "@supercharge/promise-pool"; import { FetchV2 } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; const config: any = { [CHAIN.SCROLL]: { endpoint: 'https://ambindexer.net/scroll-gcgo/', chainId: '0x82750', poolIdx: '420', start: '2023-11-12', }, [CHAIN.BLAST]: { endpoint: 'https://ambindexer.net/blast-gcgo/', chainId: '0x13e31', poolIdx: '420', start: '2024-03-02', }, [CHAIN.ETHEREUM]: { endpoint: 'https://ambindexer.net/gcgo/', chainId: '0x1', poolIdx: '420' }, // canto: { endpoint: 'https://ambient-graphcache.fly.dev/gcgo/', chainId: '0x1e14', poolIdx: '420' }, // plume_mainnet: { endpoint: 'https://ambindexer.net/plume-gcgo/', chainId: '0x18232', poolIdx: '420', start: '2025-05-14', }, // wrong data reported from api [CHAIN.SWELLCHAIN]: { endpoint: 'https://ambindexer.net/swell-gcgo/', chainId: '0x783', poolIdx: '420', start: '2024-12-24', }, // plume: { endpoint: 'https://ambindexer.net/plume-gcgo/', chainId: '0x18231', poolIdx: '420', start: '2025-05-14', }, } const fetch: FetchV2 = async ({ startTimestamp, endTimestamp, createBalances, chain }) => { const dailyVolume = createBalances() const dailyFees = createBalances() const { poolIdx, chainId, endpoint, } = config[chain] const { data } = await httpGet(endpoint + 'pool_list', { params: { poolIdx, chainId } }) const { errors } = await PromisePool .withConcurrency(10) .for(data) .process(async ({ base, quote }: any) => { const { data, } = await httpGet(endpoint + 'pool_stats', { params: { poolIdx, chainId, base, quote, histTime: endTimestamp, } }) const { data: dataOld } = await httpGet(endpoint + 'pool_stats', { params: { poolIdx, chainId, base, quote, histTime: startTimestamp, } }) // dailyVolume.add(base, data.baseVolume) dailyVolume.add(quote, data.quoteVolume) // dailyVolume.subtractToken(base, dataOld.baseVolume) dailyVolume.subtractToken(quote, dataOld.quoteVolume) // dailyFees.add(base, data.baseVolume * data.feeRate) dailyFees.add(quote, data.quoteVolume * data.feeRate) // dailyFees.subtractToken(base, dataOld.baseVolume * data.feeRate) dailyFees.subtractToken(quote, dataOld.quoteVolume * data.feeRate) }) if (errors?.length) { const timeNow = Date.now() / 1e3 const isCloseToCurrentTime = endTimestamp >= (timeNow - 86400 * 3) // 3 days if (!isCloseToCurrentTime) return {} // ignore errors for historical dates throw errors[0]; } return { dailyVolume, dailyFees, dailyRevenue: 0, dailySupplySideRevenue: dailyFees, dailyProtocolRevenue: 0 } } const methodology = { Volume: "Ambient finance trade volume", Fees: "Trading fees paid by users", Revenue: "Ambient doesnt take any fee share", ProtocolRevenue: "Ambient doesnt take any fee share", SupplySideRevenue: "All the trading fee goes to liquidity providers", } const adapter: any = {} Object.keys(config).forEach(chain => { adapter[chain] = { start: config[chain].start ?? '2023-05-28', } }) export default { fetch, adapter, version: 2, methodology }; ================================================ FILE: dexs/amigo.ts ================================================ import { Adapter, FetchOptions } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { METRIC } from "../helpers/metrics"; const ROUTER = "0x4B48F3D1Ddc9e5793D4817517255e6beF6d72A7C"; const DEPLOY_BLOCK = 41117113; const PoolCreatedEvent = "event PoolCreated(address indexed pool, address indexed creator, address indexed referrer, uint256 curveId)"; const SwapEvent = "event Swap(address indexed buyer, uint256 tokenAmount, uint256 price, uint256 fees, bool isBuy)"; const GetTradeFeeParametersFunction = "function getTradeFeeParameters(address) view returns (address, uint96, address, uint96, address, uint96, address, uint96)"; const fetch = async ({ createBalances, getLogs, api }: FetchOptions) => { const dailyVolume = createBalances(); const dailyFees = createBalances(); const dailyRevenue = createBalances(); const dailySupplySideRevenue = createBalances(); const poolLogs = await getLogs({ target: ROUTER, eventAbi: PoolCreatedEvent, fromBlock: DEPLOY_BLOCK, cacheInCloud: true, }); const pools = poolLogs.map((log: any) => log.pool); if (!pools.length) return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, dailySupplySideRevenue }; // Fee params are currently uniform across all pools; fetching from pools[0] is sufficient const swapLogs = await getLogs({ targets: pools, eventAbi: SwapEvent }); const feeParams = await api.call({ target: ROUTER, abi: GetTradeFeeParametersFunction, params: pools[0] }); const creatorShareBPS = Number(feeParams[1]); const referrerShareBPS = Number(feeParams[3]); const protocolFeeBPS = Number(feeParams[5]); const rewardsPoolBPS = Number(feeParams[7]); const totalBPS = protocolFeeBPS + creatorShareBPS + referrerShareBPS + rewardsPoolBPS; for (const log of swapLogs) { const fees = log.fees; const volume = log.isBuy ? log.price - fees : log.price + fees; const rewardsAmount = fees * BigInt(rewardsPoolBPS) / BigInt(totalBPS); const creatorAmount = fees * BigInt(creatorShareBPS) / BigInt(totalBPS); const referrerAmount = fees * BigInt(referrerShareBPS) / BigInt(totalBPS); const protocolAmount = fees - rewardsAmount - creatorAmount - referrerAmount; dailyVolume.addGasToken(volume); dailyFees.addGasToken(protocolAmount, METRIC.TRADING_FEES); dailyFees.addGasToken(rewardsAmount, 'Rewards Pool Fees'); dailyFees.addGasToken(creatorAmount, METRIC.CREATOR_FEES); dailyFees.addGasToken(referrerAmount, 'Referral Fees'); dailyRevenue.addGasToken(protocolAmount, METRIC.TRADING_FEES); dailySupplySideRevenue.addGasToken(creatorAmount, METRIC.CREATOR_FEES); dailySupplySideRevenue.addGasToken(rewardsAmount, 'Rewards Pool Fees'); dailySupplySideRevenue.addGasToken(referrerAmount, 'Referral Fees'); } return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, dailySupplySideRevenue }; }; const methodology = { Fees: "All fees from key buy/sell trades (protocol + creator + referrer + rewards pool)", Revenue: "Protocol treasury's share of trading fees", ProtocolRevenue: "Protocol treasury's share of trading fees", SupplySideRevenue: "Fees distributed to creators, referrers, and the rewards pool", } const breakdownMethodology = { Fees: { [METRIC.TRADING_FEES]: "Protocol treasury's share of trading fees", 'Rewards Pool Fees': "Fees allocated to the rewards pool", [METRIC.CREATOR_FEES]: "Fees paid to the key creator", 'Referral Fees': "Fees paid to referrers", }, Revenue: { [METRIC.TRADING_FEES]: "Protocol treasury's share of trading fees", }, ProtocolRevenue: { [METRIC.TRADING_FEES]: "Protocol treasury's share of trading fees", }, SupplySideRevenue: { [METRIC.CREATOR_FEES]: "Fees paid to the key creator", 'Rewards Pool Fees': "Fees allocated to the rewards pool", 'Referral Fees': "Fees paid to referrers", }, } const adapter: Adapter = { version: 2, fetch, pullHourly: true, chains: [CHAIN.ABSTRACT], start: "2026-02-18", methodology, breakdownMethodology, }; export default adapter; ================================================ FILE: dexs/amped-derivatives.ts ================================================ import request, { gql, GraphQLClient } from "graphql-request"; import { Fetch, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const endpoints: { [key: string]: string } = { [CHAIN.LIGHTLINK_PHOENIX]: "https://graph.phoenix.lightlink.io/query/subgraphs/name/amped-finance/trades", [CHAIN.SONIC]: "https://gateway.thegraph.com/api/subgraphs/id/6hzdSJf3xaPxsRHCEqCfe9evk3xmmwB291ZJ9RoqgHfH", // [CHAIN.BSC]: "https://api.studio.thegraph.com/query/91379/amped-trades-bsc/version/latest", [CHAIN.BERACHAIN]: "https://api.studio.thegraph.com/query/91379/amped-trades-bera/version/latest", [CHAIN.BASE]: "https://api.studio.thegraph.com/query/91379/trades-base/version/latest", // [CHAIN.SSEED]: "https://api.goldsky.com/api/public/project_cm9j641qy0e0w01tzh6s6c8ek/subgraphs/superseed-trades/1.0.2/gn", }; // Hardcoded bearer token for The Graph decentralized network const GRAPH_BEARER_TOKEN = "e8cbd58884ab58d21be68ac2c1e15a24"; // Create GraphQL client with bearer token authentication const createGraphQLClient = (endpoint: string) => { return new GraphQLClient(endpoint, { headers: { Authorization: `Bearer ${GRAPH_BEARER_TOKEN}`, }, }); }; const historicalDataDerivatives = gql` query get_volume($period: String!, $id: String!) { volumeStats(where: { period: $period, id: $id }) { liquidation margin } } `; interface IGraphResponse { volumeStats: Array<{ burn: string; liquidation: string; margin: string; mint: string; swap: string; }>; } const getFetch = (chain: string): Fetch => async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp( new Date(timestamp * 1000) ); let dailyData: IGraphResponse; // Use bearer token authentication only for Sonic network if (chain === CHAIN.SONIC) { const client = createGraphQLClient(endpoints[chain]); dailyData = await client.request(historicalDataDerivatives, { id: String(dayTimestamp) + ":daily" , period: "daily", }); } else { // Use regular request for other networks dailyData = await request(endpoints[chain], historicalDataDerivatives, { id: String(dayTimestamp) + ":daily" , period: "daily", }); } const dailyVolume = dailyData.volumeStats.length == 1 ? Number( Object.values(dailyData.volumeStats[0]).reduce((sum, element) => String(Number(sum) + Number(element)) ) ) * 10 ** -30 : undefined; return { dailyVolume: dailyVolume !== undefined ? String(dailyVolume) : undefined, }; }; const startTimestamps: { [chain: string]: number } = { [CHAIN.LIGHTLINK_PHOENIX]: 1717199544, [CHAIN.SONIC]: 1735685544, // [CHAIN.BSC]: 1727740344, [CHAIN.BERACHAIN]: 1738882079, [CHAIN.BASE]: 1740056400, [CHAIN.SSEED]: 1745330400, }; const methodology = { Fees: "Trading fees vary based on liquidity and market conditions", UserFees: "Users pay variable trading fees", Revenue: "No revenue is taken by the protocol", HoldersRevenue: "No revenue is distributed to token holders", ProtocolRevenue: "Protocol does not take any revenue", SupplySideRevenue: "100% of trading fees are distributed to liquidity providers", }; const adapter: SimpleAdapter = { methodology, adapter: Object.keys(endpoints).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: getFetch(chain), start: startTimestamps[chain], }, }; }, {}), }; export default adapter; ================================================ FILE: dexs/amped-swap.ts ================================================ import request, { gql, GraphQLClient } from "graphql-request"; import { Fetch, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const endpoints: { [key: string]: string } = { [CHAIN.LIGHTLINK_PHOENIX]: "https://graph.phoenix.lightlink.io/query/subgraphs/name/amped-finance/trades", [CHAIN.SONIC]: "https://gateway.thegraph.com/api/subgraphs/id/6hzdSJf3xaPxsRHCEqCfe9evk3xmmwB291ZJ9RoqgHfH", // [CHAIN.BSC]: "https://api.studio.thegraph.com/query/91379/amped-trades-bsc/version/latest", [CHAIN.BERACHAIN]: "https://api.studio.thegraph.com/query/91379/amped-trades-bera/version/latest", [CHAIN.BASE]: "https://api.studio.thegraph.com/query/91379/trades-base/version/latest", // [CHAIN.SSEED]: "https://api.goldsky.com/api/public/project_cm9j641qy0e0w01tzh6s6c8ek/subgraphs/superseed-trades/1.0.2/gn", }; // Hardcoded bearer token for The Graph decentralized network const GRAPH_BEARER_TOKEN = "e8cbd58884ab58d21be68ac2c1e15a24"; // Create GraphQL client with bearer token authentication const createGraphQLClient = (endpoint: string) => { return new GraphQLClient(endpoint, { headers: { Authorization: `Bearer ${GRAPH_BEARER_TOKEN}`, }, }); }; const historicalDataSwap = gql` query get_volume($period: String!, $id: String!) { volumeStats(where: { period: $period, id: $id }) { swap } } `; interface IGraphResponse { volumeStats: Array<{ burn: string; liquidation: string; margin: string; mint: string; swap: string; }>; } const getFetch = (chain: string): Fetch => async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp( new Date(timestamp * 1000) ); let dailyData: IGraphResponse; // Use bearer token authentication only for Sonic network if (chain === CHAIN.SONIC) { const client = createGraphQLClient(endpoints[chain]); dailyData = await client.request(historicalDataSwap, { id: String(dayTimestamp) + ":daily" , period: "daily", }); } else { // Use regular request for other networks dailyData = await request(endpoints[chain], historicalDataSwap, { id: String(dayTimestamp) + ":daily" , period: "daily", }); } const dailyVolume = dailyData.volumeStats.length == 1 ? Number( Object.values(dailyData.volumeStats[0]).reduce((sum, element) => String(Number(sum) + Number(element)) ) ) * 10 ** -30 : undefined; return { dailyVolume: dailyVolume !== undefined ? String(dailyVolume) : undefined, }; }; const startTimestamps: { [chain: string]: number } = { [CHAIN.LIGHTLINK_PHOENIX]: 1717199544, [CHAIN.SONIC]: 1735685544, // [CHAIN.BSC]: 1727740344, [CHAIN.BERACHAIN]: 1738882079, [CHAIN.BASE]: 1740056400, [CHAIN.SSEED]: 1745330400, }; const methodology = { Fees: "Trading fees vary based on liquidity and market conditions", UserFees: "Users pay variable trading fees", Revenue: "No revenue is taken by the protocol", HoldersRevenue: "No revenue is distributed to token holders", ProtocolRevenue: "Protocol does not take any revenue", SupplySideRevenue: "100% of trading fees are distributed to liquidity providers", }; const adapter: SimpleAdapter = { methodology, adapter: Object.keys(endpoints).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: getFetch(chain), start: startTimestamps[chain], }, }; }, {}), }; export default adapter; ================================================ FILE: dexs/angstrom/helper/asset.ts ================================================ import { BinaryDecoder } from './binaryDecoder' import { i32 } from './type/type' const size = 68 export class Asset { addr: string save: string take: string settle: string constructor(addr: string, save: string, take: string, settle: string) { this.addr = addr this.save = save this.take = take this.settle = settle } } function readAsset(decoder: BinaryDecoder): Asset { const addr = decoder.readAddress() const save = decoder.readU128().toString() const take = decoder.readU128().toString() const settle = decoder.readU128().toString() return new Asset(addr, save, take, settle) } export function padAssets(decoder: BinaryDecoder): Map { const assetsLength = decoder.readU24() const assetCount = (assetsLength / size) as i32 const assetsMap: Map = new Map() for (let i = 0; i < assetCount; i++) { assetsMap.set(i, readAsset(decoder)) } return assetsMap } ================================================ FILE: dexs/angstrom/helper/binaryDecoder.ts ================================================ import { i32, u16, u32, u64, u8, bool } from './type/type' import { bytesToHex } from './utils' /** * Binary decoder for parsing Angstrom bundle format * Handles reading various data types from byte arrays */ export class BinaryDecoder { data: Uint8Array pos: i32 constructor(data: Uint8Array) { this.data = data this.pos = 0 } readU8(): u8 { if (this.pos >= this.data.length) return 0 return this.data[this.pos++] } readU16(): u16 { const b0 = this.readU8() const b1 = this.readU8() return ((b0 as u16) << 8) | (b1 as u16) } readU24(): u32 { const b0 = this.readU8() const b1 = this.readU8() const b2 = this.readU8() return ((b0 as u32) << 16) | ((b1 as u32) << 8) | (b2 as u32) } readU32(): u32 { const b0 = this.readU8() const b1 = this.readU8() const b2 = this.readU8() const b3 = this.readU8() return ((b0 as u32) << 24) | ((b1 as u32) << 16) | ((b2 as u32) << 8) | (b3 as u32) } readU40(): string { const high = this.readU32() const low = this.readU8() const result = ((high as u64) << 8) | (low as u64) return result.toString() } readU64(): string { const high = this.readU32() const low = this.readU32() const result = ((high as u64) << 32) | (low as u64) return result.toString() } readU128(): string { return this.readBytes(16) } readU256(): string { return this.readBytes(32) } readAddress(): string { const bytes = new Uint8Array(20) for (let i = 0; i < 20; i++) { bytes[i] = this.readU8() } return '0x' + bytesToHex(bytes) } readBytes(len: i32): string { const bytes = new Uint8Array(len) for (let i = 0; i < len; i++) { bytes[i] = this.readU8() } return '0x' + bytesToHex(bytes) } readBool(): bool { return this.readU8() != 0 } skip(count: i32): void { this.pos += count } } ================================================ FILE: dexs/angstrom/helper/index.ts ================================================ import { padPairs, Pair } from './pair' import { padAssets, Asset } from './asset' import { BinaryDecoder } from './binaryDecoder' import { hexDecode } from './utils' import { padPoolUpdates, PoolUpdate } from './pool' import { i32 } from './type/type' export class AngstromBundle { assets: Map pairs: Map pool_updates: PoolUpdate[] constructor( assets: Map, pairs: Map, pool_updates: PoolUpdate[], ) { this.assets = assets this.pairs = pairs this.pool_updates = pool_updates } } function decode_bundle(s: string): AngstromBundle { let hex_str = s if (s.length >= 2 && s.charAt(0) == '0' && s.charAt(1) == 'x') hex_str = s.slice(2) const bundle_bytes_ext = hexDecode(hex_str) if (!bundle_bytes_ext) return new AngstromBundle(new Map(), new Map(), []) let skip = 0 if (hex_str.length > 8 && hex_str.slice(0, 8) == '09c5eabe') skip = 68 const bundle_bytes = bundle_bytes_ext.slice(skip) const decoder = new BinaryDecoder(bundle_bytes) const assets = padAssets(decoder) const pairs = padPairs(decoder) const pool_updates = padPoolUpdates(decoder) // skip top_of_block_orders and user_orders sections (not needed) return new AngstromBundle(assets, pairs, pool_updates) } export { decode_bundle, } ================================================ FILE: dexs/angstrom/helper/pair.ts ================================================ import { BinaryDecoder } from './binaryDecoder' import { i32 } from './type/type' const size = 38 export class Pair { index0: i32 index1: i32 store_index: i32 price_1over0: string constructor(index0: i32, index1: i32, store_index: i32, price_1over0: string) { this.index0 = index0 this.index1 = index1 this.store_index = store_index this.price_1over0 = price_1over0 } } function readPair(decoder: BinaryDecoder): Pair { const index0 = decoder.readU16() as i32 const index1 = decoder.readU16() as i32 const store_index = decoder.readU16() as i32 const price_1over0 = decoder.readU256() return new Pair(index0, index1, store_index, price_1over0) } export function padPairs(decoder: BinaryDecoder): Map { const length = decoder.readU24() const count = (length / size) as i32 const pairsMap: Map = new Map() for (let i = 0; i < count; i++) { const pair = readPair(decoder) pairsMap.set(i, pair) } return pairsMap } ================================================ FILE: dexs/angstrom/helper/pool.ts ================================================ import { BinaryDecoder } from './binaryDecoder' import { i32, u16, u32, u8 } from './type/type' export class RewardsUpdate { isMultiTick: boolean // MultiTick fields start_tick: u32 start_liquidity: string quantities: string[] checksum: string // CurrentOnly fields amount: string expected_liquidity: string constructor( isMultiTick: boolean, start_tick: u32, start_liquidity: string, quantities: string[], checksum: string, amount: string, expected_liquidity: string ) { this.isMultiTick = isMultiTick this.start_tick = start_tick this.start_liquidity = start_liquidity this.quantities = quantities this.checksum = checksum this.amount = amount this.expected_liquidity = expected_liquidity } static createMultiTick(start_tick: u32, start_liquidity: string, quantities: string[], checksum: string): RewardsUpdate { return new RewardsUpdate(true, start_tick, start_liquidity, quantities, checksum, "", "") } static createCurrentOnly(amount: string, expected_liquidity: string): RewardsUpdate { return new RewardsUpdate(false, 0, "", [], "", amount, expected_liquidity) } } export class PoolUpdate { bitmap: i32[] zero_for_one: boolean pair_index: u16 swap_in_quantity: string rewards_update: RewardsUpdate constructor( bitmap: i32[], zero_for_one: boolean, pair_index: u16, swap_in_quantity: string, rewards_update: RewardsUpdate ) { this.bitmap = bitmap this.zero_for_one = zero_for_one this.pair_index = pair_index this.swap_in_quantity = swap_in_quantity this.rewards_update = rewards_update } } class PoolUpdateDecoder { decoder: BinaryDecoder bitmap: i32[] constructor(decoder: BinaryDecoder) { this.decoder = decoder const bitmapByte = decoder.readU8() const binaryArray: i32[] = new Array(8) for (let i: i32 = 0; i < 8; i++) binaryArray[i] = (bitmapByte >> ((7 - i) as u8)) & 1 this.bitmap = binaryArray } readZeroForOne(): boolean { return this.bitmap[7] == 1 } readPairIndex(): u16 { return this.decoder.readU16() } readSwapInQuantity(): string { return this.decoder.readU128() } readRewardsUpdateStartTick(): u32 { return this.decoder.readU24() } readRewardsUpdateStartLiquidity(): string { return this.decoder.readU128() } readRewardsUpdateAmount(): string { return this.decoder.readU128() } readRewardsUpdateExpectedLiquidity(): string { return this.decoder.readU128() } readRewardsUpdateQuantities(): string[] { const rewards_update_quantities = this.decoder.readU24() const length = (rewards_update_quantities / 16) as i32 const rewardsUpdateQuantitiesArray: string[] = [] for (let i = 0; i < length; i++) { rewardsUpdateQuantitiesArray.push(this.decoder.readU128()) } return rewardsUpdateQuantitiesArray } readRewardsUpdateChecksum(): string { return this.decoder.readAddress() } } function readPoolUpdate(decoder: BinaryDecoder): PoolUpdate { const poolUpdateDecoder = new PoolUpdateDecoder(decoder) const zero_for_one = poolUpdateDecoder.readZeroForOne() const pair_index = poolUpdateDecoder.readPairIndex() const swap_in_quantity = poolUpdateDecoder.readSwapInQuantity() let rewards_update: RewardsUpdate if (poolUpdateDecoder.bitmap[6] == 0) { // MultiTick const start_tick = poolUpdateDecoder.readRewardsUpdateStartTick() const start_liquidity = poolUpdateDecoder.readRewardsUpdateStartLiquidity() const quantities = poolUpdateDecoder.readRewardsUpdateQuantities() const checksum = poolUpdateDecoder.readRewardsUpdateChecksum() rewards_update = RewardsUpdate.createMultiTick(start_tick, start_liquidity, quantities, checksum) } else { // CurrentOnly const amount = poolUpdateDecoder.readRewardsUpdateAmount() const expected_liquidity = poolUpdateDecoder.readRewardsUpdateExpectedLiquidity() rewards_update = RewardsUpdate.createCurrentOnly(amount, expected_liquidity) } return new PoolUpdate( poolUpdateDecoder.bitmap, zero_for_one, pair_index, swap_in_quantity, rewards_update ) } export function padPoolUpdates(decoder: BinaryDecoder): PoolUpdate[] { const size = decoder.readU24() as i32 const poolUpdatesArray: PoolUpdate[] = [] let bytesRead = 3 // Already read 3 bytes for size (U24) while (bytesRead < size) { const startPosition = decoder.pos poolUpdatesArray.push(readPoolUpdate(decoder)) bytesRead += decoder.pos - startPosition } return poolUpdatesArray } ================================================ FILE: dexs/angstrom/helper/type/type.ts ================================================ export type i32 = number export type u8 = number export type u16 = number export type u32 = number export type u64 = number export type bool = boolean ================================================ FILE: dexs/angstrom/helper/utils.ts ================================================ import { i32 } from "./type/type" // Helper function to convert hex character to number export function hexCharToNum(c: string): i32 { const code = c.charCodeAt(0) if (code >= 48 && code <= 57) return code - 48 // 0-9 if (code >= 97 && code <= 102) return code - 87 // a-f if (code >= 65 && code <= 70) return code - 55 // A-F return -1 } // Simple hex decode function export function hexDecode(hex: string): Uint8Array | null { if (hex.length % 2 != 0) return null const bytes = new Uint8Array(hex.length / 2) for (let i = 0; i < hex.length; i += 2) { const high = hexCharToNum(hex.charAt(i)) const low = hexCharToNum(hex.charAt(i + 1)) if (high == -1 || low == -1) return null bytes[i / 2] = (high << 4) | low } return bytes } // Convert bytes to hex string export function bytesToHex(bytes: Uint8Array): string { let hex = '' for (let i = 0; i < bytes.length; i++) { const byte = bytes[i] const hi = (byte >> 4) & 0xf const lo = byte & 0xf hex += hi < 10 ? String.fromCharCode(48 + hi) : String.fromCharCode(87 + hi) hex += lo < 10 ? String.fromCharCode(48 + lo) : String.fromCharCode(87 + lo) } return hex } ================================================ FILE: dexs/angstrom/index.ts ================================================ import * as sdk from "@defillama/sdk"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import ADDRESSES from '../../helpers/coreAssets.json'; import { decode_bundle } from './helper/index'; // taken from https://github.com/SorellaLabs/angstrom-assembly-helper/tree/main interface IUniswapConfig { poolManager: string; positionManager: string; hook: string; source: 'LOGS'; start: string; poolIds: Array; } interface IPool { poolId: string; poolKey: string; currency0: string; currency1: string; } const SwapEvent = 'event Swap(bytes32 indexed id, address indexed sender, int128 amount0, int128 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick, uint24 fee)'; const FunctionPoolKeys = 'function poolKeys(bytes25) view returns(address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks)'; const Configs: Record = { [CHAIN.ETHEREUM]: { poolManager: '0x000000000004444c5dc75cB358380D2e3dE08A90', positionManager: '0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e', hook: '0x0000000aa232009084Bd71A5797d089AA4Edfad4', source: 'LOGS', start: '2025-07-23', poolIds: [ '0xe500210c7ea6bfd9f69dce044b09ef384ec2b34832f132baec3b418208e3a657', '0x90078845bceb849b171873cfbc92db8540e9c803ff57d9d21b1215ec158e79b3', ], }, } function getPoolKey(poolId: string): string { return poolId.slice(0, 52); } async function fetch(options: FetchOptions) { const dailyFees = options.createBalances() const dailyUserFees = options.createBalances() const dailyVolume = options.createBalances() const config = Configs[options.chain]; if (!config) { throw Error(`config not found for chain ${options.chain}`); } // --- Block auction fees from Angstrom bundles --- const transactions = await sdk.indexer.getTransactions({ chain: options.chain, transactionType: 'to', addresses: [config.hook], from_block: Number(options.fromApi.block), to_block: Number(options.toApi.block), }) if (transactions) { const bundleTxns = transactions.filter((tx: any) => tx.input.startsWith('0x09c5eabe')) for (const tx of bundleTxns) { const bundle = decode_bundle(tx.input) for (const poolUpdate of bundle.pool_updates) { const pair = bundle.pairs.get(poolUpdate.pair_index) if (!pair) continue const asset = bundle.assets.get(pair.index0) if (!asset) continue const token0 = asset.addr let feeAmount: bigint if (poolUpdate.rewards_update.isMultiTick) { feeAmount = poolUpdate.rewards_update.quantities.reduce((sum: bigint, q: string) => sum + BigInt(q), 0n) } else { feeAmount = BigInt(poolUpdate.rewards_update.amount || '0') } if (feeAmount > 0n) { dailyFees.add(token0, feeAmount, 'Auction Fees') } } } } // --- User swap fees from Uniswap v4 pool manager logs --- if (config.source === 'LOGS') { const events = await options.getLogs({ target: config.poolManager, eventAbi: SwapEvent, }); // query pools info const poolKeys = await options.api.multiCall({ abi: FunctionPoolKeys, target: config.positionManager, calls: config.poolIds.map(poolId => { return { params: [getPoolKey(poolId)], } }), permitFailure: true, }) const pools: { [key: string]: IPool | null } = {} for (let i = 0; i < config.poolIds.length; i++) { if (poolKeys[i] && (poolKeys[i].currency0 !== ADDRESSES.null || poolKeys[i].currency1 !== ADDRESSES.null)) { pools[config.poolIds[i]] = { poolId: config.poolIds[i], poolKey: getPoolKey(config.poolIds[i]), currency0: String(poolKeys[i].currency0), currency1: String(poolKeys[i].currency1), } } } for (const event of events) { const poolId = String(event.id) if (pools[poolId] as IPool) { const token = (pools[poolId] as IPool).currency0 dailyUserFees.add(token, Math.abs(Number(event.amount0)) * (Number(event.fee) / 1e6)) dailyVolume.add(token, Math.abs(Number(event.amount0))) } } } dailyFees.add(dailyUserFees, 'Swap Fees') return { dailyVolume, dailyFees, dailyUserFees, dailySupplySideRevenue: dailyFees, dailyRevenue: 0, // all fees to LPs } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, // doublecounted: true, // most of the fee come from the block auction methodology: { Fees: 'Includes user swap fees from Uniswap v4 pool swaps and block auction fees from Angstrom bundles distributed to LPs.', UserFees: 'Swap fees paid by users on each trade.', SupplySideRevenue: 'All fees (swap fees + block auction rewards) are distributed to LPs.', Revenue: 'No revenue collected by Angstrom', }, breakdownMethodology: { Fees: { 'Swap Fees': 'Fee paid by the users on each swap', 'Auction Fees': 'Fees paid by the arbitrageurs who win the right to extract MEV from Angstrom bundles. These fees are distributed to LPs.', }, SupplySideRevenue: { 'Swap Fees': 'Fee paid by the users on each swap', 'Auction Fees': 'Fees paid by the arbitrageurs who win the right to extract MEV from Angstrom bundles. These fees are distributed to LPs.', }, }, chains: Object.keys(Configs), start: '2025-07-23', fetch, }; export default adapter; ================================================ FILE: dexs/anome/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const MARKET_CONTRACT = "0x210d75B7C94aDf9FC1a2bCd047D76890479234e3"; const BSC_USDT = "0x55d398326f99059fF775485246999027B3197955"; const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; const TRANSFER_EVENT = "event Transfer(address indexed from, address indexed to, uint256 value)"; const topic0_address = (address: string) => "0x000000000000000000000000" + address.toLowerCase().replace('0x', ''); const fetch = async (options: FetchOptions) => { const { createBalances, getLogs } = options; const dailyVolume = createBalances(); // 1. Buy: User transfers USDT to Market (Inflow) const logsIn = await getLogs({ target: BSC_USDT, topics: [TRANSFER_TOPIC, null as any, topic0_address(MARKET_CONTRACT)], eventAbi: TRANSFER_EVENT, onlyArgs: true, }); // 2. Sell: Market transfers USDT to User (Outflow) const logsOut = await getLogs({ target: BSC_USDT, topics: [TRANSFER_TOPIC, topic0_address(MARKET_CONTRACT), null as any], eventAbi: TRANSFER_EVENT, onlyArgs: true, }); // 3. Aggregate total volume logsIn.forEach((log: any) => dailyVolume.add(BSC_USDT, log.value)); logsOut.forEach((log: any) => dailyVolume.add(BSC_USDT, log.value)); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, chains: [CHAIN.BSC], start: '2025-10-25', }; export default adapter; ================================================ FILE: dexs/antarctic/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; import { FetchOptions } from "../../adapters/types"; import { METRIC } from "../../helpers/metrics"; type V1TickerItem = { symbol: string; baseAsset: string; quoteAsset: string; open: number; close: number; low: number; high: number; amount: number; volume: number; }; const volumeAPI = "https://prod-openapi.antarctic.exchange/futures/common/v1/perpetual/contracts"; const feesAPI = "https://prod-openapi.antarctic.exchange/futures/common/v1/perpetual/fee" const fetch = async (_a: any, _b: any, options: FetchOptions) => { const volumeURL = volumeAPI + "?timestamp=" + (options.startOfDay * 1000); const feesURL = feesAPI + "?timestamp=" + (options.startOfDay * 1000); const volumeData = (await httpGet(volumeURL)) as { data: V1TickerItem[] }; const dailyVolume = volumeData.data.reduce((p, c) => p + +c.volume, 0); const feesData = (await httpGet(feesURL)) as { data: any }; const dailyFees = options.createBalances(); dailyFees.addUSDValue(feesData.data.totalFee || 0, METRIC.TRADING_FEES); const dailyRevenue = dailyFees.clone(0.4, METRIC.TRADING_FEES); const dailySupplySideRevenue = dailyFees.clone(0.6, METRIC.TRADING_FEES); return { dailyVolume, dailyFees, dailyRevenue, dailySupplySideRevenue, dailyProtocolRevenue: dailyRevenue, }; }; export default { fetch, start: "2025-05-10", chains: [CHAIN.OFF_CHAIN], methodology: { Fees: "Total trading fees collected from perpetual futures trading on Antarctic Exchange", Revenue: "Share of 40% total trading fees", ProtocolRevenue: "Share of 40% total trading fees", SupplySideRevenue: "LPs get 60% trading fees", }, breakdownMethodology: { Fees: { [METRIC.TRADING_FEES]: "All trading fees paid by traders when opening, closing, or modifying perpetual futures positions on Antarctic Exchange", }, Revenue: { [METRIC.TRADING_FEES]: "Share of 40% total trading fees", }, ProtocolRevenue: { [METRIC.TRADING_FEES]: "Share of 40% total trading fees", }, SupplySideRevenue: { [METRIC.TRADING_FEES]: "LPs get 60% trading fees", }, }, }; ================================================ FILE: dexs/anyhedge/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import fetchURL from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; const methodology = { Volume: "Scan the blockchain for AnyHedge input pattern, add up all such inputs BCH value. The daily volume is the volume of all settled contracts for the day. Indexer: https://gitlab.com/0353F40E/anyhedge-stats", } interface IAnyhedgeVolumeResponse { daily_volume: number; total_volume: number; } // day formatted as 2011-12-13 export const anyhedgeVolumeEndpoint = (day: string) => { // Data & calculation method is fully reproducible, see: // https://gitlab.com/0353F40E/anyhedge-stats/-/blob/master/readme.md return "https://gitlab.com/0353F40E/anyhedge-stats/-/raw/master/stats_daily/" + day + ".csv"; } const fetchAnyhedgeVolumeData: any = async (timestamp: number, _: any, options: FetchOptions) => { const dayString = new Date(timestamp * 1000).toISOString().slice(0,10); const anyhedgeVolumeData = await getAnyhedgeVolumeData(anyhedgeVolumeEndpoint(dayString)); const dailyVolume = options.createBalances(); dailyVolume.addCGToken('bitcoin-cash', Number(anyhedgeVolumeData?.daily_volume)); return { timestamp, dailyVolume, }; } async function getAnyhedgeVolumeData(endpoint: string): Promise { try { let data = await fetchURL(endpoint); data = parseCSV(data); const retval: IAnyhedgeVolumeResponse = {} as IAnyhedgeVolumeResponse; retval.daily_volume = data[0].volume_closed; retval.total_volume = data[0].volume_closed_cumulative; return retval; } catch { return null; } } function parseCSV(csvData) { csvData = csvData.replaceAll('\r', '').split('\n').map(i => i.split(',')) const headers = csvData.shift() const retval = csvData.map(row => toObject(headers, row)); return retval; } function toObject(keys, values) { const res = {} keys.forEach((key, i) => { res[key] = values[i] }) return res } const adapter: SimpleAdapter = { adapter: { [CHAIN.BITCOIN_CASH]: { fetch: fetchAnyhedgeVolumeData, start: '2022-06-09', }, }, methodology, }; export default adapter; ================================================ FILE: dexs/ape-church/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; type TokenMinted = { sender: string; recipient: string; value: string; // Token }; const USER_CONTRACT = "0x6EA76F01Aa615112AB7de1409EFBD80a13BfCC84"; const BASE_FEE = BigInt(20); const FEE_DENOM = BigInt(1000); const BASE_REV_RATE = BigInt(250); async function fetch(options: FetchOptions) { let dailyVolume = options.createBalances(); let dailyFees = options.createBalances(); let dailyRevenue = options.createBalances(); const wagerLogs = await options.getLogs({ target: USER_CONTRACT, eventAbi: "event Transfer(address indexed from, address indexed to, uint256 value)", }); wagerLogs.map((log: TokenMinted) => { const nativeAmount = BigInt(log.value); const feeAmount = (nativeAmount * BASE_FEE) / FEE_DENOM; const protocolRev = (feeAmount * BASE_REV_RATE) / FEE_DENOM; dailyVolume.addGasToken(nativeAmount); dailyFees.addGasToken(feeAmount); dailyRevenue.addGasToken(protocolRev); }); const dailySupplySideRevenue = dailyFees.clone(1) dailySupplySideRevenue.subtract(dailyRevenue) return { dailyVolume, dailyFees, dailyRevenue, dailySupplySideRevenue, dailyProtocolRevenue: dailyRevenue, }; } const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch: fetch, chains: [CHAIN.APECHAIN], start: "2025-09-11", // "YYYY-MM-DD" format methodology: { Volume: 'Total wager amount from all user bets.', Fees: 'Charge 2% of wager amount.', Revenue: 'Share of 25% fees to protocol.', ProtocolRevenue: 'Share of 25% fees to protocol.', SupplySideRevenue: 'Share of 75% fees to house suppliers.', } }; export default adapter; ================================================ FILE: dexs/apestore/index.ts ================================================ import { httpPost } from "../../utils/fetchURL" import { FetchOptions, FetchResultV2, Adapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; interface VolumeInfo { dailyVolume: string; timeStamp: number; } const adapter: Adapter = { version: 2, adapter: { [CHAIN.BASE]: { fetch: async (options: FetchOptions): Promise => { const volumeData: VolumeInfo = await httpPost('https://api.ape.store/base/volume', { date: options.startOfDay }, { headers: { "Authorization": "92ff54fa-80b7-4f2c-bae1-f862ea7525ae" }, }); return { dailyVolume: volumeData.dailyVolume, }; }, start: '2024-04-04', }, [CHAIN.ETHEREUM]: { fetch: async (options: FetchOptions): Promise => { const volumeData: VolumeInfo = await httpPost('https://api.ape.store/eth/volume', { date: options.startOfDay }, { headers: { "Authorization": "92ff54fa-80b7-4f2c-bae1-f862ea7525ae" }, }); return { dailyVolume: volumeData.dailyVolume, }; }, start: '2024-04-04', } }, }; export default adapter; ================================================ FILE: dexs/apex-omni/index.ts ================================================ import fetchURL, { httpGet } from "../../utils/fetchURL"; import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; const plimit = require('p-limit'); const limits = plimit(1); const historicalVolumeEndpoint = (symbol: string, endTime: number) => `https://omni.apex.exchange/api/v3/klines?end=${endTime}&interval=D&start=1718380800&symbol=${symbol}&limit=10` const allTiker = (symbol: string) => `https://omni.apex.exchange/api/v3/ticker?symbol=${symbol}` const getSumbols = async () => { const res = await fetchURL('https://omni.apex.exchange/api/v3/all-open-tickers') const symbol = res?.data?.map((i: any) => i?.ticker_id) return symbol || [] } interface IVolumeall { id: string; volume: string; timestamp: number; price: string; volumeUSD: number; } interface IOpenInterest { id: string; openInterest: string; lastPrice: string; } const fetch = async (timestamp: number) => { const symbol = (await getSumbols()); const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const historical: any[] = (await Promise.all(symbol.map((coins: string) => limits(() => httpGet(historicalVolumeEndpoint(coins, dayTimestamp + 60 * 60 * 24), { timeout: 10000 }))))) .map((e: any) => Object.values(e.data)).flat().flat() .map((e: any) => { return { timestamp: e.t / 1000, volume: e.v, price: e.c } }); const openInterestHistorical: IOpenInterest[] = (await Promise.all(symbol.map((coins: string) => limits(() => httpGet(allTiker(coins), { timeout: 10000 }))))) .map((e: any) => e.data).flat().map((e: any) => { return { id: e.symbol, openInterest: e.openInterest, lastPrice: e.lastPrice } }); const openInterestAtEnd = openInterestHistorical.reduce((a: number, { openInterest, lastPrice }) => a + Number(openInterest) * Number(lastPrice), 0); const historicalUSD = historical.map((e: IVolumeall) => { return { ...e, volumeUSD: Number(e.volume) * Number(e.price) } }); const dailyVolume = historicalUSD.filter((e: IVolumeall) => e.timestamp === dayTimestamp) .reduce((a: number, { volumeUSD }) => a + volumeUSD, 0); return { dailyVolume: dailyVolume, openInterestAtEnd, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.ETHEREUM]: { fetch, start: '2024-06-14', } }, }; export default adapter; ================================================ FILE: dexs/apollox/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; type ResponseItem = { symbol: string; baseAsset: string; qouteAsset: string; productType: string; lastPrice: number; low: number; high: number; baseVol: number; qutoVol: number; openInterest: number; }; type V1TickerItem = { symbol: string; baseAsset: string; quoteAsset: string; lastPrice: number; highPrice: number; lowPrice: number; baseVolume: number; quoteVolume: number; openInterest: number; }; const v2VolumeAPI = "https://www.apollox.finance/bapi/future/v1/public/future/apx/pair"; const v1VolumeAPI = "https://www.apollox.finance/bapi/future/v1/public/future/aster/ticker/pair"; async function sleep(time: number) { return new Promise((resolve) => setTimeout(() => resolve(), time)); } let sleepCount = 0; const fetchV2Volume = async (retry = 0) => { if (retry >= 3) { throw new Error("Failed to fetch v2 volume after 3 retries"); } // This is very important!!! because our API will throw error when send >=2 requests at the same time. await sleep(sleepCount++ * 2 * 1e3); const res = (await httpGet(v2VolumeAPI, { params: { excludeCake: true }, })) as { data: ResponseItem[]; success: boolean }; if (res.data === null && res.success === false) { return fetchV2Volume(retry + 1); } const dailyVolume = (res.data || []).reduce((p, c) => p + +c.qutoVol, 0); return { dailyVolume, }; }; const fetchV1Volume = async () => { const data = (await httpGet(v1VolumeAPI)) as { data: V1TickerItem[] }; const dailyVolume = data.data.reduce((p, c) => p + +c.quoteVolume, 0); return { dailyVolume }; }; const fetch = async () => { const v1DailyVolume = await fetchV1Volume(); const v2DailyVolume = await fetchV2Volume(); let dailyVolume = v2DailyVolume.dailyVolume + v1DailyVolume.dailyVolume; if (dailyVolume >= 35_000_000_000) { console.log("Daily volume is greater than 35 billion", dailyVolume); throw new Error("Daily volume is too high, something went wrong"); } return { dailyVolume, }; }; export default { fetch, start: "2023-04-21", runAtCurrTime: true, chains: [CHAIN.OFF_CHAIN], }; ================================================ FILE: dexs/aptos-caliber-prop-amm/index.ts ================================================ /* * Aptos Caliber Prop AMM – daily volume (USDC) * * Volume = sum of USDC amounts from SwapEventV2: * - When token_in is USDC: amount_in / 1e6 * - When token_out is USDC: amount_out / 1e6 * * Event: 0x9f848aa20dc3829b23079d595ed719f55eec932a6805acf4909be88c88dd4d66::pools::SwapEventV2 * USDC: 0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b */ import { Dependencies, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { queryDuneSql } from "../../helpers/dune"; const SWAP_EVENT_TYPE = "0x9f848aa20dc3829b23079d595ed719f55eec932a6805acf4909be88c88dd4d66::pools::SwapEventV2"; const USDC_TOKEN = "0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const query = ` WITH raw AS ( SELECT block_time, json_parse(data) AS event_json FROM aptos.events WHERE event_type = '${SWAP_EVENT_TYPE}' AND TIME_RANGE ), swaps AS ( SELECT block_time, TRY_CAST(json_extract_scalar(event_json, '$.amount_in') AS DECIMAL(38,0)) AS amount_in, TRY_CAST(json_extract_scalar(event_json, '$.amount_out') AS DECIMAL(38,0)) AS amount_out, json_extract_scalar(event_json, '$.token_in.inner') AS token_in, json_extract_scalar(event_json, '$.token_out.inner') AS token_out FROM raw ) SELECT COALESCE(SUM( CASE WHEN token_in = '${USDC_TOKEN}' THEN amount_in / DECIMAL '1000000' WHEN token_out = '${USDC_TOKEN}' THEN amount_out / DECIMAL '1000000' END ), 0) AS daily_volume FROM swaps ` const data = await queryDuneSql(options, query) return { dailyVolume: data[0]?.daily_volume ?? 0 } } const adapter: SimpleAdapter = { version: 1, fetch, chains: [CHAIN.APTOS], dependencies: [Dependencies.DUNE], isExpensiveAdapter: true, start: '2026-03-02', } export default adapter; ================================================ FILE: dexs/aqua-network/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const AQUA_VOLUME_ENDPOINT = "https://amm-api.aqua.network/api/external/v1/statistics/totals/?size=all" interface IVolumeAll { volume: number; tvl: number; date: string; protocol_fees: number; lp_fees: number; external_rewards: number; timestamp_date_from: number; timestamp_date_to: number; } let historicalVolume: IVolumeAll[] | any const fetch = async (_: any, _1: any, { startOfDay, dateString, }: FetchOptions) => { if (!historicalVolume) historicalVolume = fetchURL(AQUA_VOLUME_ENDPOINT) historicalVolume = await historicalVolume // Seems like we have here gap about 3.5 hours in to-timestamps, can u maybe explain that diff? // Finding day period from our api, that matches llama toTimestamp (current time) const day = historicalVolume .find(i => startOfDay === i.timestamp_date_from); if (!day) throw new Error('No data for timestamp: ' + dateString); const ProtocolFees = day.protocol_fees / 1e7 const LPFees = day.lp_fees / 1e7 const ExternalRewards = day.external_rewards / 1e7 return { dailyVolume: day.volume / 1e7, dailyFees: ProtocolFees + LPFees, dailyUserFees: ProtocolFees + LPFees, dailySupplySideRevenue: LPFees, dailyRevenue: ProtocolFees, dailyHoldersRevenue: ProtocolFees, dailyBribesRevenue: ExternalRewards, dailyProtocolRevenue: 0, } }; const methodology = { Fees: "All fees including 100% of the swap fees and external rewards for AQUA holders.", UserFees: "100% of the swap fees", Revenue: "50% of the swap fees that are received by the protocol and then distributed between AQUA holders that voted for the markets where these fees have been collected", ProtocolRevenue: "Share of the fees kept by Aquarius. Currently equals 0.", HoldersRevenue: "50% of the swap fees that are received by the protocol and then distributed between AQUA holders that voted for the markets where these fees have been collected.", SupplySideRevenue: "50% of the swap fees that are shared with the Aquarius liquidity providers", BribesRevenue: "Amount of external incentives for AQUA holders voting for specific markets on Aquarius.", } const adapter: SimpleAdapter = { version: 1, methodology, adapter: { [CHAIN.STELLAR]: { fetch, start: '2024-07-01' }, }, }; export default adapter; ================================================ FILE: dexs/arctic/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { Chain, FetchOptions } from "../../adapters/types"; import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; const historicalVolumeEndpoint = (chain_id: number) => `https://izumi.finance/api/v1/izi_swap/summary_record/?chain_id=${chain_id}&type=4&page_size=100000` interface IVolumeall { volDay: number; chainId: number; timestamp: number; } type TChains = { [k: Chain | string]: number; }; const chains: TChains = { [CHAIN.AURORA]: 1313161554, }; const fetch = async (timestamp: number, _a: any, options: FetchOptions) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const historical: IVolumeall[] = (await fetchURL(historicalVolumeEndpoint(chains[options.chain])))?.data; const historicalVolume = historical.filter(e => e.chainId === chains[options.chain]); const dailyVolume = historicalVolume .find(dayItem => (new Date(dayItem.timestamp).getTime()) === dayTimestamp)?.volDay return { dailyVolume: dailyVolume, }; } const adapter: SimpleAdapter = { adapter: { [CHAIN.AURORA]: { fetch, }, }, }; export default adapter; ================================================ FILE: dexs/arena-launch.ts ================================================ import { FetchOptions } from '../adapters/types' import { CHAIN } from '../helpers/chains' const abi = { "Buy": "event Buy(address user, uint256 tokenId, uint256 tokenAmount, uint256 cost, uint256 tokenSupply, address referrerAddress, uint256 referralFee, uint256 creatorFee, uint256 protocolFee)", "Sell": "event Sell(address user, uint256 tokenId, uint256 tokenAmount, uint256 cost, uint256 tokenSupply, address referrerAddress, uint256 referralFee, uint256 creatorFee, uint256 protocolFee)", } async function fetch({ createBalances, getLogs }: FetchOptions) { const dailyVolume = createBalances() const dailyFees = createBalances() const dailyRevenue = createBalances() const buyLogs = await getLogs({ target: '0x8315f1eb449Dd4B779495C3A0b05e5d194446c6e', eventAbi: abi.Buy }) const sellLogs = await getLogs({ target: '0x8315f1eb449Dd4B779495C3A0b05e5d194446c6e', eventAbi: abi.Sell }) function addLogData(log: any) { dailyVolume.addGasToken(log.cost) dailyRevenue.addGasToken(log.protocolFee) dailyFees.addGasToken(log.protocolFee) dailyFees.addGasToken(log.creatorFee) dailyFees.addGasToken(log.referralFee) } buyLogs.forEach(addLogData) sellLogs.forEach(addLogData) return { dailyFees, dailyVolume, dailyRevenue, } } export default { version: 2, pullHourly: true, methodology: { Fees: 'All fees paid by users for trading tokens.', Revenue: 'All fees paid by users for trading tokens.', }, fetch, adapter: { [CHAIN.AVAX]: { start: '2025-05-04', }, } } ================================================ FILE: dexs/ash-perp/index.ts ================================================ import { request } from "graphql-request"; import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const API_URL = 'https://statistic-api.ashperp.trade/graphql'; const VolumeQuery = ` query getVolume { overview { getPrevious24h { volume_24h } } } ` const fetch = async () => { const dailyVolume: number = (await request(API_URL, VolumeQuery)).overview.getPrevious24h.volume_24h; return { dailyVolume, }; } const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.ELROND]: { fetch, runAtCurrTime: true, start: '2024-02-13', deadFrom: '2025-10-01' }, }, }; export default adapter; ================================================ FILE: dexs/ashswap/index.ts ================================================ import { request } from "graphql-request"; import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; const API_URL = 'https://api-v2.ashswap.io/graphql'; interface IVolume { totalVolumeUSD24h: number; } const VolumeQuery = ` { defillama { totalVolumeUSD24h } } ` const fetch = async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const results: IVolume = (await request(API_URL, VolumeQuery)).defillama; const dailyVolume = results?.totalVolumeUSD24h; return { dailyVolume: dailyVolume, timestamp: dayTimestamp, }; } const adapter: SimpleAdapter = { adapter: { [CHAIN.ELROND]: { fetch: fetch, runAtCurrTime: true, start: '2023-02-17' }, }, }; export default adapter; ================================================ FILE: dexs/aster-spot.ts ================================================ import { CHAIN } from "../helpers/chains"; import { httpGet } from "../utils/fetchURL"; type TickerItem = { symbol: string; priceChange: string; priceChangePercent: string; weightedAvgPrice: string; lastPrice: string; lastQty: string; openPrice: string; highPrice: string; lowPrice: string; volume: string; quoteVolume: string; openTime: number; closeTime: number; firstId: number; lastId: number; count: number; baseAsset: string; quoteAsset: string; bidPrice: string; bidQty: string; askPrice: string; askQty: string; }; const dayAPI = "https://sapi.asterdex.com/api/v1/ticker/24hr"; const fetch = async () => { const data = (await httpGet(dayAPI)) as TickerItem[]; const tickerPrices: { [symbol: string]: number } = {}; data.forEach((t) => { if (t.quoteAsset === "USDT") { tickerPrices[t.baseAsset] = Number(t.lastPrice); } tickerPrices[t.symbol] = Number(t.lastPrice); }); const dailyVolume = data .filter((d) => d.baseAsset !== "TEST") .reduce((p: any, c: any) => { let vol = Number(c.quoteVolume); let price = 1 if (c.quoteAsset !== "USDT") { price = tickerPrices[c.quoteAsset] if (!price) return p; } return p + (vol * price); }, 0); return { dailyVolume }; }; export default { fetch, version: 2, runAtCurrTime: true, start: "2025-09-02", chains: [CHAIN.OFF_CHAIN], }; ================================================ FILE: dexs/astro-perp.ts ================================================ import { FetchOptions, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { httpGet } from "../utils/fetchURL"; import { getEnv } from "../helpers/env"; import { METRIC } from "../helpers/metrics"; const BASE_URL = "https://llama.astros.ag/api/third/info"; const methodology = { Volume: "Volume of all perpetual contract trades executed.", Fees: "Trading fees paid by users.", Revenue: "Trading fees paid by users are revenue.", }; const getHeaders = () => ({ "api-key": getEnv("ASTROS_PERP_API_KEY"), }); const fetch = async (_a: any, _t: any, options: FetchOptions) => { let dailyVolume = 0 const dailyFees = options.createBalances() const pairs = await httpGet(`${BASE_URL}/pairs`, { headers: getHeaders() }) const tradablePairs = pairs.data.filter((pair: any) => pair.tradable); for (const pair of tradablePairs) { const ticker: any = await httpGet( `${BASE_URL}/ticker/24hr?pairName=${pair.symbol}`, { headers: getHeaders() } ); dailyVolume += Number(ticker.data.amount) const feeRate = (Number(pair.takerTradeFeeRate) + Number(pair.makerTradeFeeRate)) / 100; dailyFees.addUSDValue(feeRate * Number(ticker.data.amount), METRIC.TRADING_FEES) } return { dailyVolume, dailyFees, dailyRevenue: dailyFees, }; }; const adapter: SimpleAdapter = { methodology, breakdownMethodology: { Fees: { [METRIC.TRADING_FEES]: "Trading fees paid by users" }, Revenue: { [METRIC.TRADING_FEES]: "Trading fees paid by users are revenue" } }, adapter: { [CHAIN.SUI]: { fetch, runAtCurrTime: true, }, }, }; export default adapter; ================================================ FILE: dexs/astrolescent/index.ts ================================================ import { FetchResultVolume, SimpleAdapter } from "../../adapters/types" import { CHAIN } from "../../helpers/chains" import fetchURL from "../../utils/fetchURL" interface AstrolescentStats { volumeUSD: number; } const fetchVolume = async (timestamp: number): Promise => { const response: AstrolescentStats = (await fetchURL(`https://api.astrolescent.com/stats/history?timestamp=${timestamp}`)); const dailyVolume = Number(response?.volumeUSD); return { dailyVolume, timestamp } } const adapters: SimpleAdapter = { adapter: { [CHAIN.RADIXDLT]: { fetch: fetchVolume, start: '2023-10-30', } } } export default adapters; ================================================ FILE: dexs/astroport-v2/index.ts ================================================ import { FetchOptions, FetchResultV2, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; import { METRIC } from "../../helpers/metrics"; const chainIdMap: Record = { "terra2": "phoenix-1", "neutron": "neutron-1", }; let res: any; const url = "https://app.astroport.fi/api/trpc/protocol.stats?input=%7B%22json%22%3A%7B%22chains%22%3A%5B%22phoenix-1%22%2C%22neutron-1%22%5D%7D%7D"; const fetch = async (options: FetchOptions): Promise => { if (!res) res = fetchURL(url); const chainId = chainIdMap[options.chain]; const results = (await res).result.data.json.chains[chainId]; const dailyFees = options.createBalances(); const dailySupplySideRevenue = options.createBalances(); dailyFees.addCGToken("usd-coin", results.dayLpFeesUSD, METRIC.SWAP_FEES); dailySupplySideRevenue.addCGToken("usd-coin", results.dayLpFeesUSD, METRIC.LP_FEES); return { dailyVolume: results.dayVolumeUSD, dailyFees, dailyRevenue: 0, dailySupplySideRevenue, }; }; const methodology = { Fees: "Trading fees paid by users on each swap", Revenue: "Protocol doesn't keep any fees", SupplySideRevenue: "All swap fees are distributed to liquidity providers", }; const breakdownMethodology = { Fees: { [METRIC.SWAP_FEES]: "Fees collected on all swaps across Astroport's liquidity pools", }, SupplySideRevenue: { [METRIC.LP_FEES]: "100% of swap fees distributed to liquidity providers", }, }; const adapter: SimpleAdapter = { version: 2, runAtCurrTime: true, fetch, chains: [CHAIN.TERRA2, CHAIN.NEUTRON], // adapter: { // [CHAIN.TERRA2]: { // }, // // deprecated: https://github.com/DefiLlama/dimension-adapters/issues/5116#issuecomment-3660619459 // // [CHAIN.INJECTIVE]: { // // start: '2023-XX-XX', // // }, // [CHAIN.NEUTRON]: { // }, // // [CHAIN.SEI]: { // // start: '2023-XX-XX', // // }, // // [CHAIN.OSMOSIS]: { // // start: '2023-XX-XX', // // }, // }, methodology, breakdownMethodology, }; export default adapter; ================================================ FILE: dexs/atmos-dex/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; const API_ENDPOINT = "https://api.atmos.ag/stats/defillama/stats"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const response = await httpGet( `${API_ENDPOINT}?timestamp=${options.startOfDay}` ); return { dailyVolume: response.data.dex.volume, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.SUPRA]: { fetch, start: "2025-09-23", }, }, }; export default adapter; ================================================ FILE: dexs/atmos-studio.ts ================================================ import { FetchOptions, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { httpGet } from "../utils/fetchURL"; const API_ENDPOINT = "https://api.atmos.ag/stats/defillama/stats"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const response = await httpGet(`${API_ENDPOINT}?timestamp=${options.startOfDay}`); return { dailyVolume: response.data.pump.volume, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.SUPRA]: { fetch, start: '2025-09-23', }, }, }; export default adapter; ================================================ FILE: dexs/aux-exchange/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { GraphQLClient } from "graphql-request"; const graphURL = 'https://api.mainnet.aptoslabs.com/v1/graphql' const query = (txHeight?: number) => `query GetAccountTransactionsData { events( where: { ${txHeight ? `transaction_block_height: {_lt: ${txHeight}},` : ''} indexed_type: {_eq: "0xbd35135844473187163ca197ca93b2ab014370587bb0ed3befff9e902d6bb541::amm::SwapEvent"}, account_address: {_eq: "0xbd35135844473187163ca197ca93b2ab014370587bb0ed3befff9e902d6bb541"}} limit: 1000 order_by: {transaction_block_height: desc} ) { data, transaction_block_height } }` async function fetch({ createBalances, fromTimestamp, api, toTimestamp, }: FetchOptions) { const dailyVolume = createBalances() let hasMore = true let lastTxHeight const client = new GraphQLClient(graphURL) const aDayAgo = new Date().getTime() / 1e3 - 86400 // this way we make fewer queries let i = 0 do { const { events } = await client.request(query(lastTxHeight)) let lastTimestamp = 0 events.forEach(({ data: e, transaction_block_height }: any) => { lastTimestamp = e.timestamp / 1e3 lastTxHeight = transaction_block_height // if (e.timestamp / 1e6 > toTimestamp) return; // if (hasMore && e.timestamp / 1e6 > fromTimestamp) { if (hasMore && e.timestamp / 1e6 > aDayAgo) { dailyVolume.add(e.out_coin_type, e.out_au) } else { hasMore = false } }) api.log(`${++i} ${lastTxHeight} [Aux fi] Fetched ${events.length} events, last timestamp: ${new Date(lastTimestamp).toString().split('(')[0]} fetching till ${new Date(fromTimestamp * 1000).toString().split('(')[0]}`) } while (hasMore) return { dailyVolume, } } const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.APTOS]: { fetch, start: '2023-11-09', runAtCurrTime: true, }, }, deadFrom: '2024-11-05', }; export default adapter; ================================================ FILE: dexs/avantis/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { SimpleAdapter } from "../../adapters/types"; import fetchURL from "../../utils/fetchURL"; import { FetchResultVolume } from "../../adapters/types"; import { getTimestampAtStartOfDayUTC } from "../../utils/date"; interface IData { success: boolean; cumulativeVolume: number; history: { date: string; volume: number; buyVolume: number; sellVolume: number; cumulativeVolume: number; }[]; } const API_URL = "https://api.avantisfi.com/v1"; const fetch = async (timestamp: number): Promise => { const todaysTimestamp = getTimestampAtStartOfDayUTC(timestamp); const date = new Date(todaysTimestamp * 1000); const dateStr = date.toISOString().split("T")[0]; const url = `${API_URL}/cached/history/analytics/daily-volumes/60`; const value: IData = await fetchURL(url); if (!value.success) throw new Error("Failed to fetch data"); const data = await fetchURL(`${API_URL}/cached/history/analytics/open-interest-snapshot/60`); const openInterest = data.history.find((d: any) => d.date === dateStr)?.openInterestSnapshot; const openInterestAtEnd = openInterest ? openInterest.totalRatio : 0; const dailyVolume = value.history.find((d) => d.date === dateStr)?.volume; return { dailyVolume, openInterestAtEnd }; }; const adapter: SimpleAdapter = { version: 1, adapter: { [CHAIN.BASE]: { fetch, start: '2024-01-27', }, }, }; export default adapter; ================================================ FILE: dexs/axial/index.ts ================================================ import type { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getSaddleVolume } from "../../helpers/saddle"; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.AVAX]: { fetch, start: '2023-01-03', }, } }; export default adapter; const abi = { "poolLength": "uint256:poolLength", "poolInfo": "function poolInfo(uint256) view returns (address lpToken, uint256 accAxialPerShare, uint256 lastRewardTimestamp, uint256 allocPoint, address rewarder)", "owner": "address:owner" } async function fetch(options: FetchOptions) { const { api } = options const AXIAL_MASTERCHEF_V3 = "0x958C0d0baA8F220846d3966742D4Fb5edc5493D3"; const pools = (await api.fetchList({ lengthAbi: abi.poolLength, itemAbi: abi.poolInfo, target: AXIAL_MASTERCHEF_V3})).map((i: any) => i.lpToken) const vaults = (await api.multiCall({ abi: abi.owner, calls: pools, permitFailure: true,})).filter(i => i) return getSaddleVolume(options, vaults) } ================================================ FILE: dexs/b402/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const RAILGUN_PROXY = "0x26111e2379E5fC0A7Cd8728fe52c7b84CA4fbE85"; const topic0_shield = '0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b'; const shieldEventAbi = "event Shield(uint256 treeNumber, uint256 startPosition, (bytes32 npk, (uint8 tokenType, address tokenAddress, uint256 tokenSubID) token, uint120 value)[] commitments, (bytes32[3] encryptedBundle, bytes32 shieldKey)[] shieldCiphertext, uint256[] fees)"; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const logs = await options.getLogs({ target: RAILGUN_PROXY, topics: [topic0_shield], eventAbi: shieldEventAbi, }); logs.forEach((log) => { log.commitments.forEach((commitment: any) => { dailyVolume.add(commitment.token.tokenAddress, commitment.value); }); }); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.BASE]: { fetch, start: "2026-02-20", }, }, methodology: { Volume: "Sum of all assets shielded into B402's Railgun privacy pool on Base. Tracks Shield events emitted by the Railgun proxy contract to measure private transaction volume.", }, }; export default adapter; ================================================ FILE: dexs/babydoge-algebra.ts ================================================ import { CHAIN } from "../helpers/chains"; import request from "graphql-request"; import { FetchOptions, } from "../adapters/types"; export const BABYDOGE_GRAPHQL_ENDPOINT = "https://gateway.thegraph.com/api/9ce7bb24f9764358478f6a82c68e7ad3/subgraphs/id/9a8QustfXaMcrBcdB3rZidfLHjGa2eW1AVbUzHUQD3qb"; export const fetch = async (_: number, _ctx: any, options: FetchOptions,) => { const q = ` query { poolDayDatas(first: 1000 where: { date: ${options.startOfDay}}) { id date volumeUSD feesUSD } } `; const { poolDayDatas } = await request(BABYDOGE_GRAPHQL_ENDPOINT, q); if (!poolDayDatas.length) throw new Error("No data for " + options.dateString); const dailyVolume = poolDayDatas.reduce((acc: string, d: any) => acc + +d.volumeUSD, 0) const dailyFees = poolDayDatas.reduce((acc: string, d: any) => acc + +d.feesUSD, 0) return { dailyVolume, dailyFees, dailySupplySideRevenue: dailyFees * 0.97, dailyProtocolRevenue: dailyFees * 0.03, dailyHoldersRevenue: 0, dailyRevenue: dailyFees * 0.03, } } export default { fetch, start: '2025-07-15', chains: [CHAIN.BSC], methodology: { Fees: "All swap fees paid by users.", Revenue: "Protocol keeps 3% of swap fees as revenue.", ProtocolRevenue: "3% of swap fees.", SupplySideRevenue: "Remaining 97% of fees.", } } ================================================ FILE: dexs/balanced/index.ts ================================================ import { CHAIN } from '../../helpers/chains' import { FetchOptions } from '../../adapters/types' import { httpGet } from '../../utils/fetchURL' import { METRIC } from '../../helpers/metrics' const breakdownMethodology = { Fees: { [METRIC.LP_FEES]: 'Fees paid by traders on token swaps, distributed to liquidity providers', }, SupplySideRevenue: { [METRIC.LP_FEES]: 'Fees paid by traders on token swaps, distributed to liquidity providers', } } export default { version: 2, methodology: { Fees: 'Fees collected from borrowers and traders.', SupplySideRevenue: 'All the fees collected from borrowers and traders are distributed to liquidity providers.', }, breakdownMethodology, runAtCurrTime: true, start: '2023-11-14', adapter: { [CHAIN.ICON]: { fetch: async ({ createBalances }: FetchOptions) => { const dailyVolume = createBalances() const dailyFees = createBalances() const data = await httpGet('https://balanced.icon.community/api/v1/pools') data.forEach((pool: any) => { dailyVolume.add(pool.base_address, pool.base_volume_24h * (10 ** pool.base_decimals)) dailyVolume.add(pool.quote_address, pool.quote_volume_24h * (10 ** pool.quote_decimals)) dailyFees.add(pool.base_address, pool.base_lp_fees_24h * (10 ** pool.base_decimals), METRIC.LP_FEES) dailyFees.add(pool.quote_address, pool.quote_lp_fees_24h * (10 ** pool.quote_decimals), METRIC.LP_FEES) }) return { dailyVolume, dailyFees, dailyRevenue: 0, dailySupplySideRevenue: dailyFees } }, }, } } ================================================ FILE: dexs/balancer-v1.ts ================================================ import * as sdk from "@defillama/sdk"; import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getChainVolume2 } from "../helpers/getUniSubgraphVolume"; const graphParams = { totalVolume: { factory: "balancers", field: "totalSwapVolume", }, hasDailyVolume: false, }; const v1graphs = getChainVolume2({ graphUrls: { [CHAIN.ETHEREUM]: sdk.graph.modifyEndpoint("93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB"), }, ...graphParams, }); const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.ETHEREUM]: { fetch: v1graphs(CHAIN.ETHEREUM), start: '2020-02-27', }, }, }; export default adapter; ================================================ FILE: dexs/balancer-v2.ts ================================================ import { FetchOptions } from '../adapters/types' import { getFeesExport } from '../helpers/balancer' import { CHAIN } from '../helpers/chains' const ESTIMATED_NON_CORE_SHARE = 0.7; const ESTIMATED_CORE_SHARE = 0.3; const HOLDERS_SHARE_NON_CORE = 0.825; // 82.5% for non-core pools const HOLDERS_SHARE_CORE = 0.125; // 12.5% for core pools const weightedHoldersShare = ESTIMATED_NON_CORE_SHARE * HOLDERS_SHARE_NON_CORE + ESTIMATED_CORE_SHARE * HOLDERS_SHARE_CORE; const revenueRatio = 0.5; const TOKENOMICS_REVAMP_DATE = "2026-04-23"; async function fetch(options: FetchOptions) { // https://x.com/Balancer/status/1988685056982835470 const WhitehatActivitiesChains: Array = [ CHAIN.ETHEREUM, CHAIN.OPTIMISM, CHAIN.ARBITRUM, ] if ((options.startOfDay === 1762992000 || options.startOfDay === 1762905600) && WhitehatActivitiesChains.includes(options.chain)) { return { dailyVolume: 0, dailyFees: 0, dailyRevenue: 0, dailyProtocolRevenue: 0, dailySupplySideRevenue: 0, dailyHoldersRevenue: 0, } } else { const holderRevenueRatio = options.dateString >= TOKENOMICS_REVAMP_DATE ? 0 : revenueRatio * weightedHoldersShare; const protocolRevenueRatio = revenueRatio - holderRevenueRatio; const fetchFunction = getFeesExport('0xBA12222222228d8Ba445958a75a0704d566BF2C8', { revenueRatio, protocolRevenueRatio, holderRevenueRatio, }); return await fetchFunction(options); } } export default { version: 2, fetch: fetch, methodology: { Fees: "All trading fees collected (includes swap and yield fee)", UserFees: "Trading fees paid by users, ranging from 0.0001% to 10%", Revenue: "Balancer V2 protocol collects 50% swap fees as revenue.", ProtocolRevenue: "Share of revenue to Balancer DAO.", HoldersRevenue: "Share of revenue to veBAL holders (None after 2026-04-23)", SupplySideRevenue: "50% from swap fees paid by traders are shared to pool LPs", }, adapter: { [CHAIN.ETHEREUM]: { start: '2021-04-23', }, [CHAIN.POLYGON]: { start: '2021-06-24', }, [CHAIN.ARBITRUM]: { start: '2021-08-31', }, [CHAIN.AVAX]: { start: '2023-02-25', }, [CHAIN.XDAI]: { start: '2023-01-10', }, [CHAIN.BASE]: { start: '2023-07-26', }, [CHAIN.MODE]: { start: '2024-05-22', }, [CHAIN.FRAXTAL]: { start: '2024-05-20', }, [CHAIN.OPTIMISM]: { start: '2022-05-04', }, }, } ================================================ FILE: dexs/balancer-v3/index.ts ================================================ import request from "graphql-request"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { METRIC } from "../../helpers/metrics"; const v3ChainMapping: any = { [CHAIN.ETHEREUM]: "MAINNET", [CHAIN.XDAI]: "GNOSIS", [CHAIN.ARBITRUM]: "ARBITRUM", [CHAIN.OPTIMISM]: "OPTIMISM", [CHAIN.AVAX]: "AVALANCHE", [CHAIN.BASE]: "BASE", [CHAIN.HYPERLIQUID]: "HYPEREVM", [CHAIN.PLASMA]: "PLASMA", [CHAIN.MONAD]: "MONAD", }; const TOKENOMICS_REVAMP_DATE = "2026-04-23"; const n = (x: any) => (Number.isFinite(Number(x)) ? Number(x) : 0); async function fetch(options: FetchOptions) { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const dailyUserFees = options.createBalances(); const dailyProtocolRevenueGross = options.createBalances(); const dailySupplySideRevenue = options.createBalances(); const dailyHoldersRevenue = options.createBalances(); const dailyProtocolRevenueNet = options.createBalances(); const dailyRevenue = options.createBalances(); const HOLDERS_SHARE_OF_PROTOCOL = options.dateString >= TOKENOMICS_REVAMP_DATE ? 0 : 0.825; const LP_SHARE_OF_SWAP_FEES = options.dateString >= TOKENOMICS_REVAMP_DATE ? 0.75 : 0.5; const query = `query { pools: poolGetPools( orderBy: volume24h orderDirection: desc where: { chainIn: [${v3ChainMapping[options.chain]}] protocolVersionIn: [3]} ) { address chain createTime decimals protocolVersion tags dynamicData { totalLiquidity lifetimeVolume lifetimeSwapFees volume24h fees24h yieldCapture24h } } }`; const { pools } = await request("https://api-v3.balancer.fi/graphql", query); let protocolGrossSum = 0; let supplySideSum = 0; pools.forEach((pool: any) => { const fees24h = n(pool?.dynamicData?.fees24h); const vol24h = n(pool?.dynamicData?.volume24h); const yield24h = n(pool?.dynamicData?.yieldCapture24h); dailyVolume.addUSDValue(vol24h); dailyFees.addUSDValue(fees24h, METRIC.SWAP_FEES); dailyUserFees.addUSDValue(fees24h, METRIC.SWAP_FEES); dailyProtocolRevenueGross.addUSDValue(fees24h * (1 - LP_SHARE_OF_SWAP_FEES), METRIC.SWAP_FEES); dailySupplySideRevenue.addUSDValue(fees24h * LP_SHARE_OF_SWAP_FEES, METRIC.SWAP_FEES); protocolGrossSum += fees24h * (1-LP_SHARE_OF_SWAP_FEES); supplySideSum += fees24h * LP_SHARE_OF_SWAP_FEES; // subgraph error on hyperlqiuid yields if (options.chain !== CHAIN.HYPERLIQUID) { dailyFees.addUSDValue(yield24h, METRIC.ASSETS_YIELDS); dailyProtocolRevenueGross.addUSDValue( +(yield24h * 0.1), METRIC.ASSETS_YIELDS ); // 10% of yield capture goes to the protocol dailySupplySideRevenue.addUSDValue(yield24h * 0.9, METRIC.ASSETS_YIELDS); // 90% of yield capture goes to the supply side protocolGrossSum += yield24h * 0.1; supplySideSum += yield24h * 0.9; } }); const holdersUSD = protocolGrossSum * HOLDERS_SHARE_OF_PROTOCOL; const protocolNetUSD = protocolGrossSum - holdersUSD; if (holdersUSD > 0) dailyHoldersRevenue.addUSDValue(holdersUSD); if (protocolNetUSD > 0) dailyProtocolRevenueNet.addUSDValue(protocolNetUSD); dailyRevenue.addBalances(dailyHoldersRevenue); dailyRevenue.addBalances(dailyProtocolRevenueNet); return { dailyFees, dailyUserFees, dailyVolume, dailyRevenue, dailyProtocolRevenue: dailyProtocolRevenueNet, dailyHoldersRevenue, dailySupplySideRevenue, }; } const adapter: SimpleAdapter = { version: 2, fetch, runAtCurrTime: true, chains: Object.keys(v3ChainMapping), methodology: { Fees: "Fees earned from all the trades and yields.", UserFees: "Fees earned from all the trades.", Revenue: "Revenue earned by the protocol and holders, which is 25% ( 50 % before 2026-04-23 ) of the trade fees and 10% of the yield capture.", ProtocolRevenue: "Revenue earned by the protocol, which is 25% ( 8.75% before 2026-04-23 ) of the trade fees and 10% of the yield capture.", HoldersRevenue: "Portion of protocol revenue distributed to token holders (e.g., veBAL/BAL) (82.5 % of revenue before 2026-04-23, 0 % of revenue after )", SupplySideRevenue: "Revenue earned by the supply side, which is 90% of the yield capture and 75% ( 50 % before 2026-04-23 ) of the fees.", }, breakdownMethodology: { Fees: { [METRIC.SWAP_FEES]: "Swap fees paid by users from all trades.", [METRIC.ASSETS_YIELDS]: "Yields captured from all assets in liquity pools.", }, UserFees: { [METRIC.SWAP_FEES]: "Swap fees paid by users from all trades.", }, Revenue: { [METRIC.SWAP_FEES]: "50% of swap fees paid by users from all trades.", [METRIC.ASSETS_YIELDS]: "10% of yields captured from all assets in liquity pools.", }, ProtocolRevenue: { [METRIC.SWAP_FEES]: "50% of swap fees paid by users from all trades.", [METRIC.ASSETS_YIELDS]: "10% of yields captured from all assets in liquity pools.", }, HoldersRevenue: { [METRIC.SWAP_FEES]: "Share of protocol revenue sent to token holders.", [METRIC.ASSETS_YIELDS]: "Share of protocol revenue from yield capture sent to token holders.", }, SupplySideRevenue: { [METRIC.SWAP_FEES]: "50% of swap fees paid by users from all trades.", [METRIC.ASSETS_YIELDS]: "90% of yields captured from all assets in liquity pools.", }, }, }; export default adapter; ================================================ FILE: dexs/bancor-v2_1.ts ================================================ import { SimpleAdapter, FetchOptions } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { filterPools2 } from "../helpers/uniswap"; async function fetchV2(fetchOptions: FetchOptions) { const { api, getLogs, createBalances } = fetchOptions const converterRegistry = '0xC0205e203F423Bcd8B2a4d6f8C8A154b0Aa60F19' const smartTokens = await api.call({ abi: 'address[]:getLiquidityPools', target: converterRegistry }) const pools = await api.call({ abi: "function getConvertersBySmartTokens(address[] _smartTokens) view returns (address[])", target: converterRegistry, params: [smartTokens] }); const token1s = await api.multiCall({ abi: 'function connectorTokens(uint256) view returns (address)', calls: pools.map((i: any) => ({ target: i, params: [1] })) }) const token0s = await api.multiCall({ abi: 'function connectorTokens(uint256) view returns (address)', calls: pools.map((i: any) => ({ target: i, params: [0] })) }) const { pairs } = await filterPools2({ fetchOptions, pairs: pools, token0s, token1s, minUSDValue: 1e4, maxPairSize: 31 }) const logs = await getLogs({ targets: pairs, eventAbi: 'event Conversion (address indexed sourceToken, address indexed targetToken, address indexed trader, uint256 sourceAmount, uint256 targetAmount, int256 conversionFee)' }) const dailyVolume = createBalances() logs.forEach((log: any) => dailyVolume.add(log.targetToken, log.targetAmount)) return { dailyVolume } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.ETHEREUM]: { fetch: fetchV2, start: '2019-10-10', } } } export default adapter; ================================================ FILE: dexs/bancor-v3.ts ================================================ import { FetchOptions, SimpleAdapter } from "../adapters/types" import { CHAIN } from "../helpers/chains" import { METRIC } from "../helpers/metrics" // https://etherscan.io/tx/0x49aad1741e1c7bee650befb18d9c37266237e0021722d74cc00fc4dfa5d8c38c const REVENUE_RATIO = 0.2; // 20% fees to revenue buy back and burn BNT tokens async function fetch(fetchOptions: FetchOptions) { const { getLogs, createBalances, } = fetchOptions const contract = '0xeEF417e1D5CC832e619ae18D2F140De2999dD4fB' const dailyVolume = createBalances() const dailyFees = createBalances() const logs = await getLogs({ targets: [contract], eventAbi: 'event TokensTraded(bytes32 indexed contextId, address indexed sourceToken, address indexed targetToken, uint256 sourceAmount, uint256 targetAmount, uint256 bntAmount, uint256 targetFeeAmount, uint256 bntFeeAmount, address trader)' }) logs.forEach((log: any) => { dailyVolume.add(log.targetToken, log.targetAmount); dailyFees.add(log.targetToken, log.targetFeeAmount, METRIC.SWAP_FEES); }) const dailyRevenue = dailyFees.clone(REVENUE_RATIO); const dailySupplySideRevenue = dailyFees.clone(1 - REVENUE_RATIO); const dailyHoldersRevenue = createBalances(); dailyHoldersRevenue.add(dailyRevenue, METRIC.TOKEN_BUY_BACK); return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue: 0, dailySupplySideRevenue, dailyHoldersRevenue, } } const methodology = { Fees: 'Swap fees charged on trades in the target token.', SupplySideRevenue: 'There are 80% fees are distributed to LPs.', Revenue: 'There are 20% fees are collected as revenue.', ProtocolRevenue: 'No reveneu share to Bancor protocol.', HoldersRevenue: 'All revenue are used to buy back and burn vBNT tokens.', } const breakdownMethodology = { Fees: { [METRIC.SWAP_FEES]: 'Fee charged on each swap, denominated in the target token of the trade.', }, Revenue: { [METRIC.SWAP_FEES]: 'There are 20% fees are collected as revenue.', }, SupplySideRevenue: { [METRIC.SWAP_FEES]: 'There are 80% fees are distributed to LPs', }, HoldersRevenue: { [METRIC.TOKEN_BUY_BACK]: 'All revenue are used to buy back and burn vBNT tokens.', } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, chains: [CHAIN.ETHEREUM], fetch, start: '2022-04-20', methodology, breakdownMethodology, } export default adapter; ================================================ FILE: dexs/barterswap/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addTokensReceived } from "../../helpers/token"; const superpositionRouter = "0x0b7250866f0b014E6983cACc5b854EeA7a3d9188" async function fetch(options: FetchOptions) { const dailyVolume = options.createBalances() await addTokensReceived({ options: options, target: superpositionRouter, balances: dailyVolume}) return { dailyVolume, } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, chains: [CHAIN.ETHEREUM], start: "2025-11-04" } export default adapter ================================================ FILE: dexs/baryon/index.ts ================================================ import { Fetch, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { getUniV2LogAdapter } from "../../helpers/uniswap"; import {CHAIN} from "../../helpers/chains"; const POOL_CREATE = 'event PairCreated(address indexed token0, address indexed token1, address pair, uint256)'; const SWAP_EVENT = 'event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to)'; const factory: {[chain: string]: string} = { [CHAIN.BSC]: '0x03879e2a3944fd601e7638dfcbc9253fb793b599', [CHAIN.ANCIENT8]: '0xAE12C5930881c53715B369ceC7606B70d8EB229f', [CHAIN.BITKUB]: '0xf7eEe3A8363731C611A24CdDfCBcaDE9C153Cfe8', } const graphs: Fetch = async (_timestamp: number, _t: any, options: FetchOptions) => { const adapter = getUniV2LogAdapter({ factory: factory[options.chain as string], eventAbi: SWAP_EVENT, pairCreatedAbi: POOL_CREATE }); const v2stats = await adapter(options); return { timestamp: options.startOfDay, dailyVolume: v2stats?.dailyVolume, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.BSC]: { fetch: graphs, start: '2023-08-12', }, [CHAIN.ANCIENT8]: { fetch: graphs, start: '2023-08-12', }, [CHAIN.BITKUB]: { fetch: graphs, start: '2023-08-12', }, }, }; export default adapter; ================================================ FILE: dexs/baseswap-v2.ts ================================================ import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniV2LogAdapter } from "../helpers/uniswap"; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.BASE]: { fetch: getUniV2LogAdapter({ factory: '0xFDa619b6d20975be80A10332cD39b9a4b0FAa8BB', revenueRatio: 0 }), start: '2023-07-28', }, }, }; export default adapter; ================================================ FILE: dexs/baseswap-v3.ts ================================================ import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniV3LogAdapter } from "../helpers/uniswap"; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.BASE]: { fetch: getUniV3LogAdapter({ factory: '0x38015d05f4fec8afe15d7cc0386a126574e8077b', revenueRatio: 0.64 }), start: '2023-07-28', }, }, }; export default adapter; ================================================ FILE: dexs/basin/helper.ts ================================================ import { BaseAdapterChainConfig, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { addOneToken } from "../../helpers/prices"; export interface BasinExchangeConfig { wells: string[]; start: string; // YYYY-MM-DD } export interface BasinExchangeExportConfig { [chain: string]: BasinExchangeConfig; } async function getBasinVolume(options: FetchOptions, configs: BasinExchangeExportConfig) { const config = configs[options.chain]; const dailyVolume = options.createBalances(); const wellsSwapEvents = await options.getLogs({ eventAbi: 'event Swap(address fromToken, address toToken, uint256 amountIn, uint256 amountOut, address recipient)', targets: config.wells, flatten: true, }); for (const event of wellsSwapEvents) { addOneToken({ chain: options.chain, balances: dailyVolume, token0: event.fromToken, token1: event.toToken, amount0: event.amountIn, amount1: event.amountOut, }); } return { dailyVolume }; } export function getBasinAdapter(configs: BasinExchangeExportConfig): SimpleAdapter { const adapter: SimpleAdapter = { version: 2, pullHourly: true, methodology: { Volume: 'Total swap volume from all Well pools on exchange.' }, adapter: {}, }; for (const [chain, config] of Object.entries(configs)) { (adapter.adapter as BaseAdapterChainConfig)[chain] = { fetch: (options: FetchOptions) => getBasinVolume(options, configs), start: config.start, }; } return adapter; } ================================================ FILE: dexs/basin/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { getBasinAdapter } from "./helper"; export default getBasinAdapter({ [CHAIN.ETHEREUM]: { start: '2023-08-24', wells: [ '0xBEA0e11282e2bB5893bEcE110cF199501e872bAd', '0xbea0000113b0d182f4064c86b71c315389e4715d', '0x1125eac5f713503e2b7cb2299027960ce1aa5d42', '0x54c04c9bf5af0bc3096cb0af24c4fa8379a2915e', '0x905eafe9434fabacaf10d1490fcd0d1eb9b85fc8', '0x8d97775623368f833f8fa82209e220f1c60508ea', '0xdf9c4a067279857b463817ef773fe189c77e1686', ], }, [CHAIN.ARBITRUM]: { start: '2024-10-07', wells: [ '0xBeA00Aa8130aCaD047E137ec68693C005f8736Ce', '0xBEa00BbE8b5da39a3F57824a1a13Ec2a8848D74F', '0xBeA00Cc9F93E9a8aC0DFdfF2D64Ba38eb9C2e48c', '0xBea00DDe4b34ACDcB1a30442bD2B39CA8Be1b09c', '0xBea00ee04D8289aEd04f92EA122a96dC76A91bd7', '0xbEA00fF437ca7E8354B174339643B4d1814bED33', ], }, }); ================================================ FILE: dexs/beamex-beamex-perps.ts ================================================ import { gql, request } from "graphql-request"; import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const endpointsBeamex = { [CHAIN.MOONBEAM]: 'https://graph.beamswap.io/subgraphs/name/beamswap/beamex-stats', }; const historicalDataDerivatives = gql` query get_volume($period: String!, $id: String!) { volumeStats(where: { period: $period, id: $id }) { liquidation margin } } `; interface IGraphResponse { volumeStats: Array<{ burn: string; liquidation: string; margin: string; mint: string; swap: string; }>; } const fetch = async (timestamp: number) => { const chain = CHAIN.MOONBEAM; const dayTimestamp = getUniqStartOfTodayTimestamp( new Date(timestamp * 1000) ); const dailyData: IGraphResponse = await request( endpointsBeamex[chain], historicalDataDerivatives, { id: String(dayTimestamp), period: "daily", } ); return { dailyVolume: dailyData.volumeStats.length == 1 ? String( Number( Object.values(dailyData.volumeStats[0]).reduce((sum, element) => String(Number(sum) + Number(element)) ) ) * 10 ** -30 ) : undefined, }; }; const methodologyBeamex = { Fees: "Fees from open/close position (0.2%), liquidations, swap (0.2% to 0.4%), mint and burn (based on tokens balance in the pool) and borrow fee ((assets borrowed)/(total assets in pool)*0.02%)", UserFees: "Fees from open/close position (0.2%), swap (0.2% to 0.4%) and borrow fee ((assets borrowed)/(total assets in pool)*0.04%)", HoldersRevenue: "30% of all collected fees are distributed to $stGLINT stakers", SupplySideRevenue: "70% of all collected fees will be distributed to BLP stakers. Currently they are distributed to treasury", Revenue: "70% of all collected fees are distributed to the treasury", ProtocolRevenue: "70% of all collected fees are distributed to the treasury", }; const adapter: SimpleAdapter = { adapter: { [CHAIN.MOONBEAM]: { fetch, start: '2023-06-22', }, }, methodology: methodologyBeamex, deadFrom: "2025-08-12", }; export default adapter; ================================================ FILE: dexs/beamex-beamex-swap.ts ================================================ import { gql, request } from "graphql-request"; import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const endpointsBeamex = { [CHAIN.MOONBEAM]: 'https://graph.beamswap.io/subgraphs/name/beamswap/beamex-stats', }; const historicalDataSwap = gql` query get_volume($period: String!, $id: String!) { volumeStats(where: { period: $period, id: $id }) { swap } } `; interface IGraphResponse { volumeStats: Array<{ burn: string; liquidation: string; margin: string; mint: string; swap: string; }>; } const fetch = async (timestamp: number) => { const chain = CHAIN.MOONBEAM; const dayTimestamp = getUniqStartOfTodayTimestamp( new Date(timestamp * 1000) ); const dailyData: IGraphResponse = await request( endpointsBeamex[chain], historicalDataSwap, { id: String(dayTimestamp), period: "daily", } ); return { dailyVolume: dailyData.volumeStats.length == 1 ? String( Number( Object.values(dailyData.volumeStats[0]).reduce((sum, element) => String(Number(sum) + Number(element)) ) ) * 10 ** -30 ) : undefined, }; }; const methodologyBeamex = { Fees: "Fees from open/close position (0.2%), liquidations, swap (0.2% to 0.4%), mint and burn (based on tokens balance in the pool) and borrow fee ((assets borrowed)/(total assets in pool)*0.02%)", UserFees: "Fees from open/close position (0.2%), swap (0.2% to 0.4%) and borrow fee ((assets borrowed)/(total assets in pool)*0.04%)", HoldersRevenue: "30% of all collected fees are distributed to $stGLINT stakers", SupplySideRevenue: "70% of all collected fees will be distributed to BLP stakers. Currently they are distributed to treasury", Revenue: "70% of all collected fees are distributed to the treasury", ProtocolRevenue: "70% of all collected fees are distributed to the treasury", }; const adapter: SimpleAdapter = { adapter: { [CHAIN.MOONBEAM]: { fetch, start: '2023-06-22', }, }, methodology: methodologyBeamex, deadFrom: "2025-08-12", }; export default adapter; ================================================ FILE: dexs/beamswap-classic.ts ================================================ import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniV2LogAdapter } from "../helpers/uniswap"; const adapter: SimpleAdapter = { version: 2, methodology: { UserFees: "User pays 0.30% fees on each swap.", Fees: "A 0.30% of each swap is collected as trading fees", Revenue: "Protocol receives 0.13% on each swap.", ProtocolRevenue: "Protocol receives 0.13% on each swap.", SupplySideRevenue: "All user fees are distributed among LPs.", HoldersRevenue: "Stakers received $GLINT in staking rewards.", }, adapter: { [CHAIN.MOONBEAM]: { fetch: getUniV2LogAdapter({ factory: '0x985BcA32293A7A496300a48081947321177a86FD', revenueRatio: 0.13/0.30, protocolRevenueRatio: 0.13/0.30 }), }, }, }; export default adapter; ================================================ FILE: dexs/beamswap-stable-amm.ts ================================================ import { FetchOptions, FetchResultV2, SimpleAdapter } from '../adapters/types' import { CHAIN } from '../helpers/chains' const pools = { '0xe3f59ab3c37c33b6368cdf4f8ac79644011e402c': { tokens: ['0x931715FEE2d06333043d11F658C8CE934aC61D0c', '0xCa01a1D0993565291051daFF390892518ACfAD3A', '0xFFFFFFfFea09FB06d082fd1275CD48b191cbCD1d'], }, '0x09a793cca9d98b14350f2a767eb5736aa6b6f921': { tokens: ['0x8f552a71EFE5eeFc207Bf75485b356A0b3f01eC9', '0x8e70cD5B4Ff3f62659049e74b6649c6603A0E594', '0xc234A67a4F840E61adE794be47de455361b52413'], }, } const fetch = async (options: FetchOptions): Promise => { const dailyVolume = options.createBalances() for (const [poolAddress, poolConfig] of Object.entries(pools)) { const events = await options.getLogs({ eventAbi: 'event TokenSwap(address indexed buyer, uint256 tokensSold, uint256 tokensBought, uint128 soldId, uint128 boughtId)', target: poolAddress, }); for (const event of events) { dailyVolume.add(poolConfig.tokens[Number(event.soldId)], event.tokensSold) } } return { dailyVolume } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, chains: [CHAIN.MOONBEAM], fetch, methodology: { UserFees: "User pays a 0.04% fee on each swap.", Fees: "A 0.04% of each swap is collected as trading fees", Revenue: "Protocol receives 0.02% of the swap fee", ProtocolRevenue: "Protocol receives 0.02% of the swap fee", SupplySideRevenue: "0.02% of the swap fee is distributed to LPs", HoldersRevenue: "Stakers received $GLINT in staking rewards.", }, deadFrom: "2025-08-12", } export default adapter; ================================================ FILE: dexs/bean-exchange/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "./../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from "../../helpers/prices"; const dlmmFactory = "0x8Bb9727Ca742C146563DccBAFb9308A234e1d242"; type TABI = { [k: string]: object; }; const ABIs: TABI = { getNumberOfLBPairs: { inputs: [], name: "getNumberOfLBPairs", outputs: [{ internalType: "uint256", name: "lbPairNumber", type: "uint256" }], stateMutability: "view", type: "function", }, getLBPairAtIndex: { inputs: [{ internalType: "uint256", name: "index", type: "uint256" }], name: "getLBPairAtIndex", outputs: [{ internalType: "contract ILBPair", name: "lbPair", type: "address" }], stateMutability: "view", type: "function", }, getTokenX: { inputs: [], name: "getTokenX", outputs: [{ internalType: "address", name: "tokenX", type: "address" }], stateMutability: "view", type: "function", }, getTokenY: { inputs: [], name: "getTokenY", outputs: [{ internalType: "address", name: "tokenY", type: "address" }], stateMutability: "view", type: "function", }, }; const swapEvent = "event Swap(address indexed sender, address indexed to, uint24 id, bytes32 amountsIn, bytes32 amountsOut, uint24 volatilityAccumulator, bytes32 totalFees, bytes32 protocolFees, (uint256 nativePriceUSD, uint256 tokenXPriceNative, uint256 tokenYPriceNative) priceData)"; type Pool = { address: string; tokenX: string; tokenY: string; }; function getAmountsFromBytesString(bytes: string): { amountX: number; amountY: number } { return { amountX: parseInt(`0x${bytes.replace("0x", "").slice(32, 64)}`, 16), amountY: parseInt(`0x${bytes.replace("0x", "").slice(0, 32)}`, 16), }; } const fetch = async ({ createBalances, getLogs, api, chain }: FetchOptions) => { const poolsAddresses = await api.fetchList({ lengthAbi: ABIs.getNumberOfLBPairs, itemAbi: ABIs.getLBPairAtIndex, target: dlmmFactory, }); const tokens0 = await api.multiCall({ abi: "function getTokenX() view returns (address)", calls: poolsAddresses.map((pool: any) => ({ target: pool })), }); const tokens1 = await api.multiCall({ abi: "function getTokenY() view returns (address)", calls: poolsAddresses.map((pool: any) => ({ target: pool })), }); const pools: Pool[] = poolsAddresses.map((address: any, index: number) => ({ address: address, tokenX: tokens0[index], tokenY: tokens1[index], })); const dailyVolume = createBalances(); const dailyFees = createBalances(); const dailyRevenue = createBalances(); await Promise.all( pools.map(async (pool: any, index: number) => { const logsResult = await getLogs({ target: pool.address, eventAbi: swapEvent, }); logsResult.forEach((log: any) => { const amountInd = getAmountsFromBytesString(log.amountsIn); const amountOut = getAmountsFromBytesString(log.amountsOut); addOneToken({ chain, balances: dailyVolume, token0: pool.tokenX, token1: pool.tokenY, amount0: amountInd.amountX + amountOut.amountX, amount1: amountInd.amountY + amountOut.amountY, }); const totalFees = getAmountsFromBytesString(log.totalFees); dailyFees.add(pool.tokenX, totalFees.amountX); dailyFees.add(pool.tokenY, totalFees.amountY); const protocolFees = getAmountsFromBytesString(log.protocolFees); dailyRevenue.add(pool.tokenY, protocolFees.amountY); dailyRevenue.add(pool.tokenX, protocolFees.amountX); }); }) ); const dailySupplySideRevenue = dailyFees.clone(1); dailySupplySideRevenue.subtract(dailyRevenue); return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, dailySupplySideRevenue, }; }; const methodology = { Fees: "LP fees generated by the swap transactions on Bean Exchange.", Revenue: "20% percent of fees to Bean Exchange.", ProtocolRevenue: "20% percent of fees to Bean Exchange.", SupplySideRevenue: "80% percent of the fees to LPs.", }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.MONAD]: { fetch, start: "2025-11-23", }, }, methodology, }; export default adapter; ================================================ FILE: dexs/beethoven-x/index.ts ================================================ import * as sdk from "@defillama/sdk"; import { ChainEndpoints, FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { Chain } from "../../adapters/types"; import { getTimestampAtStartOfDayUTC } from "../../utils/date"; import request, { gql } from "graphql-request"; const endpoints: ChainEndpoints = { [CHAIN.FANTOM]: sdk.graph.modifyEndpoint('CcWtE5UMUaoKTRu8LWjzambKJtgUVjcN31pD5BdffVzK'), [CHAIN.OPTIMISM]: sdk.graph.modifyEndpoint('FsmdxmvBJLGjUQPxKMRtcWKzuCNpomKuMTbSbtRtggZ7'), [CHAIN.SONIC]: sdk.graph.modifyEndpoint("wwazpiPPt5oJMiTNnQ2VjVxKnKakGDuE2FfEZPD4TKj"), }; interface IPool { id: string; swapVolume: string; } interface IPoolSnapshot { today: IPool[]; yesterday: IPool[]; } const v2Graphs = (chain: Chain) => { return async (timestamp: number): Promise => { const startTimestamp = getTimestampAtStartOfDayUTC(timestamp) const fromTimestamp = startTimestamp - 60 * 60 * 24 const toTimestamp = startTimestamp const graphQuery = gql `query fees { today:poolSnapshots(where: {timestamp:${toTimestamp}}) { id swapVolume } yesterday:poolSnapshots(where: {timestamp:${fromTimestamp}}) { id swapVolume } }`; const graphRes: IPoolSnapshot = (await request(endpoints[chain], graphQuery)); const dailyVolume = graphRes["today"].map((p: IPool) => { const yesterdayValue = Number(graphRes.yesterday.find((e: IPool) => e.id.split('-')[0] === p.id.split('-')[0])?.swapVolume || '0') if (yesterdayValue === 0) return 0; return Number(p.swapVolume) - yesterdayValue; }).filter(e => e < 100_000_000).reduce((a: number, b: number) => a + b, 0) return { dailyVolume: dailyVolume, timestamp, }; }; }; const adapter: SimpleAdapter = { adapter: Object.keys(endpoints).reduce((acc, chain: any) => { return { ...acc, [chain]: { fetch: v2Graphs(chain), start: '2021-10-05', } } }, {}) }; export default adapter; ================================================ FILE: dexs/beets-v3/index.ts ================================================ import request from "graphql-request"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { METRIC } from "../../helpers/metrics"; const v3ChainMapping: any = { [CHAIN.SONIC]: 'SONIC', } const breakdownMethodology = { Fees: { [METRIC.SWAP_FEES]: 'Fees collected from token swaps in liquidity pools', 'Yield capture': 'Revenue generated from yield-bearing tokens held in pools (e.g., stETH, wstETH)', }, Revenue: { [METRIC.PROTOCOL_FEES]: 'Protocol share of swap fees (25% of total swap fees)', 'Protocol yield capture': 'Protocol share of yield capture (25% of total yield capture)', }, SupplySideRevenue: { [METRIC.LP_FEES]: 'Liquidity provider share of swap fees and yield capture (75% of total)', }, }; const adapter: SimpleAdapter = { version: 2, runAtCurrTime: true, methodology: { Volume: 'Total volume is the sum of all trades in the last 24 hours.', Fees: 'Total fees earned from all the trades and yield in the last 24 hours.', Revenue: 'Total revenue earned by the protocol in the last 24 hours, which is 25% of the fees and yield capture.', }, breakdownMethodology, fetch, chains: Object.keys(v3ChainMapping), }; async function fetch({ createBalances, chain }: FetchOptions) { const dailyVolume = createBalances() const dailyFees = createBalances() const dailyRevenue = createBalances() const dailySupplySideRevenue = createBalances() const query = `query { pools: poolGetPools( orderBy: volume24h orderDirection: desc where: { chainIn: [${v3ChainMapping[chain]}] protocolVersionIn: [3]} ) { address chain createTime decimals protocolVersion tags dynamicData { totalLiquidity lifetimeVolume lifetimeSwapFees volume24h fees24h yieldCapture24h } } }` const { pools } = await request('https://api-v3.balancer.fi/graphql', query); pools.forEach((pool: any) => { dailyFees.addUSDValue(+pool.dynamicData.fees24h, METRIC.SWAP_FEES) dailyFees.addUSDValue(+pool.dynamicData.yieldCapture24h, 'Yield capture') dailyVolume.addUSDValue(+pool.dynamicData.volume24h) dailyRevenue.addUSDValue(+(pool.dynamicData.fees24h * 0.25), METRIC.PROTOCOL_FEES) // 25% of fees go to the protocol dailyRevenue.addUSDValue(+(pool.dynamicData.yieldCapture24h * 0.25), 'Protocol yield capture') // 25% of yield capture goes to the protocol dailySupplySideRevenue.addUSDValue(+(pool.dynamicData.fees24h * 0.75), METRIC.LP_FEES) // 75% of fees go to LPs dailySupplySideRevenue.addUSDValue(+(pool.dynamicData.yieldCapture24h * 0.75), METRIC.LP_FEES) // 75% of yield capture goes to LPs }) return { dailyFees, dailyVolume, dailyRevenue, dailySupplySideRevenue } } export default adapter; ================================================ FILE: dexs/beezie.ts ================================================ import request from "graphql-request"; import type { FetchOptions, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import ADDRESSES from "../helpers/coreAssets.json"; import { addTokensReceived } from "../helpers/token"; const graphUrl = "https://indexer.beezie.io/"; type FetchItemResult = { clawMachine: string; user: string; tokenId: string; currency: string; swapValue: string; price: string; timestamp: string; }; const getQuery = (fromTimestamp: number, toTimestamp: number, endCursor: any) => `{ clawMachineWins( where: { timestamp_gte: "${fromTimestamp}", timestamp_lt: "${toTimestamp}" }, orderBy: "timestamp", orderDirection: "desc", after: ${endCursor ? `"${endCursor}"` : null}, limit: 1000 ) { items { clawMachine, user, tokenId, currency, swapValue, price, timestamp }, pageInfo { endCursor, hasNextPage }, totalCount } }` const fetchFlow: any = async ({ createBalances, fromTimestamp, toTimestamp }: FetchOptions) => { const dailyVolume = createBalances(); let hasNextPage = true; let endCursor = null; while (hasNextPage) { const query: string = getQuery(fromTimestamp, toTimestamp, endCursor); const res = await request(graphUrl, query); if (res?.clawMachineWins?.items?.length > 0) { res.clawMachineWins.items.forEach((item: FetchItemResult) => dailyVolume.add(item.currency, item.swapValue)); } hasNextPage = res?.clawMachineWins?.pageInfo?.hasNextPage ?? false; endCursor = res?.clawMachineWins?.pageInfo?.endCursor ?? null; } return { dailyVolume, }; }; const abi = { clawMachineCreated: "event ClawMachineCreated(address indexed clawMachine)", played: "event Played(address indexed user, uint256 indexed amount)", playToken: "function playToken() view returns (address)", } const clawMachineFactory = "0x8B50BAB7464764f6d102a9819B7db967256Db14c"; const bidRouter = "0x80d7C04B738eF379971a6b73f25B1A71ea1c820D"; const paymentToken = ADDRESSES.base.USDC; const CLAW_MANAGERS = new Set( [ "0x2129836a9ee21cD92129B05453F4Bdbd879566D7", "0x46e2Af76235d2fb959cf725f73443042a9aF7080", "0x279Dd5eE509783D04F002FDFc3d688a911557305", "0x61aA186Be094041F5C8C41c6AadF210532111fDc", "0xBa2b26Dd25C57838B7E500c539e0d85293d96FD4", "0xa69D72428AfFcCEcAc7C2fa91492480273E41200", "0x48C27EF6218Bc4f0714dd00df6941868B1afa54a", "0x69daaBeD9750a96F0eE7340b800930366D9dC976", "0x3BD1141C1dc3E74197411452DcAd9B1b2b6329F2", ].map((a) => a.toLowerCase()), ); const fetchBase = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const clawMachineCreatedLogs = await options.getLogs({ target: clawMachineFactory, eventAbi: abi.clawMachineCreated, fromBlock: 40451500, cacheInCloud: true, }); const clawMachines = clawMachineCreatedLogs.map((log: any) => log.clawMachine); const playTokens = await options.api.multiCall({ abi: abi.playToken, calls: clawMachines, permitFailure: true, }); const machineToToken = new Map(); const validMachines: string[] = []; clawMachines.forEach((machine, i) => { if (playTokens[i]) { machineToToken.set(machine.toLowerCase(), playTokens[i]); validMachines.push(machine); } }); const playedLogs = await options.getLogs({ targets: validMachines, eventAbi: abi.played, }); for (const log of playedLogs) { const machine = log.address?.toLowerCase() ?? ""; const token = machineToToken.get(machine); if (!token) continue; dailyVolume.add(token, log.amount); } const swapVolume = options.createBalances(); await addTokensReceived({ options, target: bidRouter, balances: swapVolume, token: paymentToken, fromAdddesses: [...CLAW_MANAGERS], }); const marketplaceVolume = options.createBalances(); await addTokensReceived({ options, target: bidRouter, balances: marketplaceVolume, token: paymentToken, logFilter: (log: any) => !CLAW_MANAGERS.has((log.from ?? "").toLowerCase()), }); dailyVolume.add(swapVolume) dailyVolume.add(marketplaceVolume) return { dailyVolume, }; } const adapter: SimpleAdapter = { version: 2, adapter: { // [CHAIN.FLOW]: { // start: '2025-01-04', // fetch: fetchFlow, // }, [CHAIN.BASE]: { start: '2026-01-06', fetch: fetchBase, }, }, }; export default adapter; ================================================ FILE: dexs/believe/index.ts ================================================ import ADDRESSES from '../../helpers/coreAssets.json' import { Dependencies, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { queryDuneSql } from "../../helpers/dune"; import { FetchOptions } from "../../adapters/types"; interface IData { total_volume: number; } const fetch = async (_a: any, _b: any, options: FetchOptions) => { const data: IData[] = await queryDuneSql(options, ` WITH launch_coin_tokens AS ( SELECT DISTINCT account_arguments[4] AS token FROM solana.instruction_calls WHERE executing_account = 'dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN' AND tx_signer = '5qWya6UjwWnGVhdSBL3hyZ7B45jbk6Byt1hwd7ohEGXE' AND account_arguments[4] <> '${ADDRESSES.solana.SOL}' AND tx_success = TRUE AND NOT is_inner ), launch_coin_swap_txs_for_event_join AS ( SELECT tx_id FROM solana.instruction_calls WHERE tx_success = TRUE AND executing_account = 'dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN' AND VARBINARY_STARTS_WITH (data, 0xf8c69e91e17587c8) AND account_arguments[8] IN (SELECT token FROM launch_coin_tokens) AND TIME_RANGE ), swap_events AS ( SELECT LEAST( TRY_CAST(BYTEARRAY_TO_UINT256(BYTEARRAY_REVERSE(BYTEARRAY_SUBSTRING(data, 9+90, 8))) AS DECIMAL(38,0)), TRY_CAST(BYTEARRAY_TO_UINT256(BYTEARRAY_REVERSE(BYTEARRAY_SUBSTRING(data, 9+98, 8))) AS DECIMAL(38,0)) ) AS event_sol_amount FROM solana.instruction_calls WHERE tx_id IN (SELECT tx_id FROM launch_coin_swap_txs_for_event_join) AND tx_success = TRUE AND executing_account = 'dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN' AND VARBINARY_STARTS_WITH (data, 0xe445a52e51cb9a1d) AND TIME_RANGE ) SELECT SUM(COALESCE(event_sol_amount, 0)) / 1e9 AS total_volume FROM swap_events `) const dailyVolume = options.createBalances(); dailyVolume.addCGToken('solana', data[0].total_volume); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 1, dependencies: [Dependencies.DUNE], adapter: { [CHAIN.SOLANA]: { fetch, start: '2025-04-27' } }, isExpensiveAdapter: true } export default adapter ================================================ FILE: dexs/betterswap/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; interface BetterSwapResponse { volumeUSD: string; } // BetterSwap factoryAddress const factoryAddress = "0x5970dcbebac33e75eff315c675f1d2654f7bf1f5"; const fetch = async (_a:any, _b:any, options: FetchOptions) => { const startDate = new Date(options.startOfDay * 1000).toISOString().split("T")[0]; const url = `https://www.betterswap.io/api/volume?startDate=${startDate}&factoryAddress=${factoryAddress}`; const response: BetterSwapResponse = await fetchURL(url); return { dailyVolume: parseFloat(response.volumeUSD), }; }; const adapter: SimpleAdapter = { version: 1, fetch, chains: [CHAIN.VECHAIN], start: '2025-04-30', }; export default adapter; ================================================ FILE: dexs/bifrost-dex.ts ================================================ import { CHAIN } from "../helpers/chains"; import { FetchOptions } from "../adapters/types"; import fetchURL from "../utils/fetchURL"; let res: any; const fetch = async (_: any, _1: any, options: FetchOptions) => { const startTime = new Date(options.startTimestamp * 1000).toISOString().split("T")[0] if (!res) res = fetchURL('https://dapi.bifrost.io/api/dapp/stats/swap') const v = (await res).volume.find((v: { date: string }) => v.date === startTime) return { dailyVolume: v.amount }; }; const adapter: any = { adapter: { [CHAIN.BIFROST]: { fetch, start: '2024-11-08', }, }, }; export default adapter; ================================================ FILE: dexs/bigpump/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { CHAIN } from "../../helpers/chains"; import { FetchOptions } from "../../adapters/types"; import { getPrices } from "../../utils/prices"; const endpoint = "https://tonfunstats-eqnd7.ondigitalocean.app/api/v1/getVolume" const fetch = async (options: FetchOptions) => { const res = await fetchURL(`${endpoint}?from=${options.startTimestamp}&to=${options.endTimestamp}&service=bigpump`) const TON = "coingecko:the-open-network" const ton_price = await getPrices([TON], options.startTimestamp); return { dailyVolume: Number(BigInt(res.volume) / 1000000000n) * ton_price[TON].price, timestamp: options.startTimestamp, }; }; const adapter: any = { version: 2, adapter: { [CHAIN.TON]: { fetch, start: '2024-10-24', }, }, }; export default adapter; ================================================ FILE: dexs/bisonfi/index.ts ================================================ // Program: BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi import { Dependencies, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { queryDuneSql } from "../../helpers/dune"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const query = ` with swaps as ( select tx_id , outer_instruction_index , inner_instruction_index from solana.instruction_calls where executing_account = 'BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi' and TIME_RANGE and tx_success = true ) select SUM(amount_usd) as daily_volume from tokens_solana.transfers t inner join swaps s on t.tx_id = s.tx_id and t.outer_instruction_index = s.outer_instruction_index and t.inner_instruction_index = s.inner_instruction_index + 1 where t.block_time >= from_unixtime(${options.startTimestamp}) and t.block_time <= from_unixtime(${options.endTimestamp}) `; const data = await queryDuneSql(options, query); return { dailyVolume: data[0]?.daily_volume ?? 0 }; }; const adapter: SimpleAdapter = { fetch, dependencies: [Dependencies.DUNE], chains: [CHAIN.SOLANA], start: '2025-12-05', isExpensiveAdapter: true, }; export default adapter; ================================================ FILE: dexs/bisq/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { ChainBlocks, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const historicalVolumeEndpoint = "https://markets.bisq.network/api/volumes?interval=day" interface IVolumeall { volume: string; period_start: number; } const fetch = async (__: number, _: ChainBlocks, {startOfDay, createBalances, }: FetchOptions) => { const totalVolume = createBalances() const dailyVolume = createBalances() const historicalVolume: IVolumeall[] = (await fetchURL(historicalVolumeEndpoint)); historicalVolume .filter(volItem => volItem.period_start <= startOfDay) .map(({ volume }) => totalVolume.addCGToken('bitcoin', +volume)) const dailyVol = historicalVolume .find(dayItem => dayItem.period_start === startOfDay)?.volume dailyVolume.addCGToken('bitcoin', +(dailyVol as any)) return { dailyVolume, timestamp: startOfDay }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.BITCOIN]: { fetch, start: '2018-05-07', }, }, }; export default adapter; ================================================ FILE: dexs/bitcoin-bridge/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types" import { CHAIN } from "../../helpers/chains" import fetchURL from "../../utils/fetchURL"; import { getTimestampAtStartOfDayUTC } from "../../utils/date"; const permuteEndpoint = "https://api.permute.finance/bridge" const chainConfig = { [CHAIN.BITCOIN]: { start: '2025-05-28', key: 'BTC'}, [CHAIN.ETHEREUM]: { start: '2025-05-28', key: 'ETH'}, [CHAIN.AVAX]: { start: '2025-05-28', key: 'AVXC'}, [CHAIN.ARBITRUM]: { start: '2025-05-28', key: 'ARBITRUM'}, [CHAIN.BSC]: { start: '2025-05-28', key: 'BSC'}, [CHAIN.TRON]: { start: '2025-05-28', key: 'TRON'}, [CHAIN.LITECOIN]: { start: '2025-05-28', key: 'LTC'}, [CHAIN.BITCOIN_CASH]: { start: '2025-05-28', key: 'BCH'}, [CHAIN.DOGE]: { start: '2025-05-28', key: 'DOGE'}, [CHAIN.SOLANA]: { start: '2025-05-28', key: 'SOL'}, [CHAIN.BERACHAIN]: { start: '2025-05-28', key: 'BERA'}, } const fetch = async (_a: any, _b: any, options: FetchOptions) => { const startOfDay = getTimestampAtStartOfDayUTC(options.startOfDay); const url = permuteEndpoint.concat(`/dashboard/vol/chain/day?chain=${chainConfig[options.chain].key}×tamp=${startOfDay}`) const volumeForDay = await fetchURL(url) const dailyVolume = volumeForDay.day_vol return { dailyVolume }; }; const adapter: SimpleAdapter = { fetch, adapter: chainConfig, }; export default adapter; ================================================ FILE: dexs/bitflow-fi.ts ================================================ import fetchURL from "../utils/fetchURL"; import { FetchResult, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const tickersURL = "https://api.bitflowapis.finance/ticker"; const dlmmTickersURL = "https://bff.bitflowapis.finance/api/app/v1/tickers"; const tokensURL = "https://api.bitflowapis.finance/getAllTokensAndPools"; interface Ticker { base_currency: string; base_volume: number; } interface Token { tokenContract: string; priceData: { last_price: number; }; } const isStacksToken = (tokenContract: string) => { return ( tokenContract === "Stacks" || tokenContract === "SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.token-stx-v-1-2" ); }; const getTokenPricesMap = async () => { const { tokens, }: { tokens: Token[]; } = await fetchURL(tokensURL); const tokenPricesMap: { [tokenContract: string]: number } = {}; for (const token of tokens) { if (!token.priceData) tokenPricesMap[token.tokenContract] = 0; else tokenPricesMap[token.tokenContract] = token.priceData.last_price; } return tokenPricesMap; }; const getTokenDailyVolume = ({ map, tokenContract, baseVolume, }: { map: { [tokenContract: string]: number }; tokenContract: string; baseVolume: number; }) => { const tokenPrice = map[tokenContract]; if (!tokenPrice) return 0; return baseVolume * tokenPrice; }; const fetch = async (): Promise => { const [tickers, dlmmTickers, tokensPriceMap] = await Promise.all([ fetchURL(tickersURL), fetchURL(dlmmTickersURL), getTokenPricesMap(), ]); let dailyVolume = 0; for (const ticker of [...tickers, ...dlmmTickers]) { const baseVolume = Number(ticker.base_volume); if (!Number.isFinite(baseVolume)) continue; const tokenContract = isStacksToken(ticker.base_currency) ? "null" : ticker.base_currency; dailyVolume += getTokenDailyVolume({ map: tokensPriceMap, tokenContract, baseVolume, }); } return { dailyVolume, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.STACKS]: { fetch, runAtCurrTime: true, }, }, }; export default adapter; ================================================ FILE: dexs/bitflux/index.ts ================================================ import { FetchOptions, FetchResultV2, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; interface IPool { address: string; tokens: Array; swapFeeRate: number; adminFeeRate: number; // how many percentage of swap fee } const Pools: Array = [ { address: '0x4bcb9ea3dacb8ffe623317e0b102393a3976053c', tokens: ['0x5B1Fb849f1F76217246B8AAAC053b5C7b15b7dc3', '0x9410e8052Bc661041e5cB27fDf7d9e9e842af2aa', '0x5832f53d147b3d6Cd4578B9CBD62425C7ea9d0Bd'], swapFeeRate: 0.0005, // 0.05% per swap adminFeeRate: 0.5, // 50% swap fees }, { address: '0x6a63cbf00D15137756189c29496B14998b259254', tokens: ['0x8BB97A618211695f5a6a889faC3546D1a573ea77', '0x7A6888c85eDBA8E38F6C7E0485212da602761C08', '0x5a2aa871954eBdf89b1547e75d032598356caad5'], swapFeeRate: 0.0005, // 0.05% per swap adminFeeRate: 0.5, // 50% swap fees }, { address: '0xE7E1b1F216d81a4b2c018657f26Eda8FE2F91e26', tokens: ['0xe04d21d999FaEDf1e72AdE6629e20A11a1ed14FA', '0xe85411C030fB32A9D8b14Bbbc6CB19417391F711', '0x7A6888c85eDBA8E38F6C7E0485212da602761C08'], swapFeeRate: 0.0005, // 0.05% per swap adminFeeRate: 0.5, // 50% swap fees }, { address: '0x7C59fd4348261348de72be3e40fA87252E778CA3', tokens: ['0x5832f53d147b3d6Cd4578B9CBD62425C7ea9d0Bd', '0x7A6888c85eDBA8E38F6C7E0485212da602761C08'], swapFeeRate: 0.0005, // 0.05% per swap adminFeeRate: 0.5, // 50% swap fees }, ] const SwapEvent = 'event TokenSwap(address indexed buyer, uint256 tokensSold, uint256 tokensBought, uint128 soldId, uint128 boughtId)'; async function fetch(options: FetchOptions): Promise { const dailyVolume = options.createBalances() const dailyFees = options.createBalances() const dailyRevenue = options.createBalances() for (const pool of Pools) { const swapEvents = await options.getLogs({ target: pool.address, eventAbi: SwapEvent, }); for (const event of swapEvents) { dailyVolume.add(pool.tokens[event.soldId], event.tokensSold); const feeAmount = Number(event.tokensSold) * pool.swapFeeRate; dailyFees.add(pool.tokens[event.soldId], feeAmount); dailyRevenue.add(pool.tokens[event.soldId], feeAmount * pool.adminFeeRate); } } const dailySupplySideRevenue = dailyFees.clone() dailySupplySideRevenue.subtract(dailyRevenue) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue, dailyProtocolRevenue: dailyRevenue, dailySupplySideRevenue, // no holders revenue dailyHoldersRevenue: 0, } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.CORE]: { fetch: fetch, start: '2024-11-06', } }, methodology: { UserFees: "User pays a 0.05% fee on each swap.", Fees: "A 0.05% of each swap is collected as trading fees", Revenue: "Protocol receives 0.025% of the swap fee (50% of total fees)", ProtocolRevenue: "Protocol receives 0.025% of the swap fee (50% of total fees)", SupplySideRevenue: "0.025% of the swap fee is distributed to LPs (50% of total fees)", HoldersRevenue: "No direct revenue to token holders", } }; export default adapter; ================================================ FILE: dexs/bitget-wallet-card.ts ================================================ import { FetchOptions, SimpleAdapter } from "../adapters/types" import { CHAIN } from "../helpers/chains" const NFT_CONTRACT = '0x133CAEecA096cA54889db71956c7f75862Ead7A0' const SPEND_CONTRACT = '0xe2e3B88B9893e18D0867c08f9cA93f8aB5935b14' const SPEND_EVENT= 'event Authorized (string authorizationToken, uint256 indexed tokenId, address indexed sender, string cardId, address cardCurrency, uint256 paidAmount)' const TRANSFER_EVENT= 'event Transfer (address indexed from, address indexed to, uint256 indexed tokenId)' const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' const ZERO_TOPIC = '0x0000000000000000000000000000000000000000000000000000000000000000' const MINT_START_BLOCK = 298189162 const CURRENCY_RATES: Record = { '0x2c5d06f591d0d8cd43ac232c2b654475a142c7da': 1.1722, // EUR '0xbe00f3db78688d9704bcb4e0a827aea3a9cc0d62': 1, // USD '0xd41f1f0cf89fd239ca4c1f8e8ada46345c86b0a4': 1.25, // CHF '0x7288ac74d211735374a23707d1518dcbbc0144fd': 0.14, // CNY } const fetch = async (_a: any, _b: any, options: FetchOptions) => { const spendLogs = await options.getLogs({ target: SPEND_CONTRACT, eventAbi: SPEND_EVENT, }) if (spendLogs.length === 0) return { dailyVolume: 0 } // Fetch all mint events and filter wallets const mintLogs = await options.getLogs({ target: NFT_CONTRACT, eventAbi: TRANSFER_EVENT, topics: [TRANSFER_TOPIC, ZERO_TOPIC], fromBlock: MINT_START_BLOCK, cacheInCloud: true, }) const mintWallets = new Set( mintLogs.map((log: any) => log.to.toLowerCase()) ) let totalVolume = 0 for (const log of spendLogs) { const walletAddress = log.sender.toLowerCase() if (!mintWallets.has(walletAddress)) continue const currencyContract = log.cardCurrency.toLowerCase() const spendAmount = Number(log.paidAmount) / 1e2 const rate = CURRENCY_RATES[currencyContract] if (rate) { totalVolume += spendAmount * rate } } return { dailyVolume: totalVolume }; }; const adapter: SimpleAdapter = { fetch, start: '2025-01-21', chains: [CHAIN.ARBITRUM], }; export default adapter; ================================================ FILE: dexs/bitkeep/index.ts ================================================ import { FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { Chain } from "../../adapters/types"; import {getUniqStartOfTodayTimestamp} from "../../helpers/getUniSubgraphVolume"; import fetchURL from "../../utils/fetchURL"; const historicalVolumeEndpoint = "https://new-swapopen.bitapi.vip/st/getOrderDayList" interface IVolumeall { volume: string; date: string; } const graph = (chain: Chain) => { return async (timestamp: number): Promise => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const historicalVolume: IVolumeall[] = (await fetchURL(historicalVolumeEndpoint + `?chain=${chain}`))?.data.list; const dailyVolume = historicalVolume .find(dayItem => (new Date(dayItem.date).getTime() / 1000) === dayTimestamp)?.volume return { dailyVolume: dailyVolume, }; } } const adapter: SimpleAdapter = { adapter: { [CHAIN.ETHEREUM]: { fetch: graph(CHAIN.ETHEREUM), start: '2022-10-31', }, [CHAIN.BSC]: { fetch: graph(CHAIN.BSC), start: '2022-10-31', }, [CHAIN.ARBITRUM]: { fetch: graph(CHAIN.ARBITRUM), start: '2022-10-31', }, [CHAIN.OPTIMISM]: { fetch: graph(CHAIN.OPTIMISM), start: '2022-10-31', }, } }; export default adapter; ================================================ FILE: dexs/blackhole-CL.ts ================================================ import { CHAIN } from "../helpers/chains"; import { FetchOptions, IJSON, SimpleAdapter } from "../adapters/types"; import { filterPools } from "../helpers/uniswap"; import { ethers } from "ethers"; import { addOneToken } from "../helpers/prices"; const poolEvent = 'event CustomPool(address indexed token0, address indexed token1, address pool)' const customPoolEvent = 'event CustomPool(address indexed deployer, address indexed token0, address indexed token1, address pool)' const poolSwapEvent = 'event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)' const factory = '0x512eb749541B7cf294be882D636218c84a5e9E5F' const fromBlock = 65218551 const fetch = async (options: FetchOptions) => { const { createBalances, getLogs, chain, api } = options let logs = await options.getLogs({ target: factory, eventAbi: poolEvent, fromBlock: fromBlock, entireLog: true, cacheInCloud: true, }) logs = logs.concat(await options.getLogs({ target: factory, eventAbi: customPoolEvent, fromBlock: fromBlock, entireLog: true, cacheInCloud: true, })) const iface = new ethers.Interface([poolEvent, customPoolEvent]) logs = logs.map((log: any) => iface.parseLog(log)?.args) const pairObject: IJSON = {} const fees: any = {} logs.forEach((log: any) => { pairObject[log.pool] = [log.token0, log.token1] }) let _fees = await api.multiCall({ abi: 'function fee() view returns (uint24)', calls: logs.map((log: any) => log.pool) }) _fees.forEach((fee: any, i: number) => fees[logs[i].pool] = fee / 1e6) const filteredPairs = await filterPools({ api, pairs: pairObject, createBalances }) const dailyVolume = createBalances() const dailyFees = createBalances() const dailyRevenue = createBalances() const dailySupplySideRevenue = createBalances() if (!Object.keys(filteredPairs).length) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue, dailySupplySideRevenue } const allLogs = await getLogs({ targets: Object.keys(filteredPairs), eventAbi: poolSwapEvent, flatten: false }) allLogs.map((logs: any, index) => { if (!logs.length) return; const pair = Object.keys(filteredPairs)[index] const [token0, token1] = pairObject[pair] const fee = fees[pair] logs.forEach((log: any) => { addOneToken({ chain, balances: dailyVolume, token0, token1, amount0: log.amount0, amount1: log.amount1 }) addOneToken({ chain, balances: dailyFees, token0, token1, amount0: log.amount0.toString() * fee, amount1: log.amount1.toString() * fee }) addOneToken({ chain, balances: dailyRevenue, token0, token1, amount0: log.amount0.toString() * fee, amount1: log.amount1.toString() * fee }) }) }) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue, dailySupplySideRevenue: dailySupplySideRevenue, dailyProtocolRevenue: 0, dailyHoldersRevenue: dailyRevenue, } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, methodology: { Fees: "All swap fees paid by users.", UserFees: "All swap fees paid by users.", SupplySideRevenue: "No fees distributed to LPs.", Revenue: "All swap fees are revenue.", ProtocolRevenue: "Protocol makes no revenue.", HoldersRevenue: "All revenue is distributed to veBlack holders.", }, chains: [CHAIN.AVAX], fetch, }; export default adapter; ================================================ FILE: dexs/blackhole.ts ================================================ import { CHAIN } from "../helpers/chains" import { FetchV2, IJSON, SimpleAdapter } from "../adapters/types" import { cache } from "@defillama/sdk" import { filterPools } from "../helpers/uniswap" import { addOneToken } from "../helpers/prices" const GaugeManager = '0x59aa177312Ff6Bdf39C8Af6F46dAe217bf76CBf6' const Factory = '0xfe926062fb99ca5653080d6c14fe945ad68c265c' const SwapEvent = 'event Swap(address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to)' // FeesEvent emits the real fee amounts deducted during each swap. // Since fees for Blackhole pairs can change over time, these events are the most accurate method to track fees/revenue. const FeesEvent = `event Fees(address indexed sender, uint amount0, uint amount1)` const fetch: FetchV2 = async (fetchOptions) => { const { createBalances, getLogs, chain, api } = fetchOptions const cacheKey = `tvl-adapter-cache/cache/uniswap-forks/${Factory}-${chain}.json` const { pairs, token0s, token1s } = await cache.readCache(cacheKey, { readFromR2Cache: true }) if (!pairs?.length) throw new Error('No pairs found, is there TVL adapter for this already?') const pairObject: IJSON = {} pairs.forEach((pair: string, i: number) => { pairObject[pair] = [token0s[i], token1s[i]] }) const filteredPairs = await filterPools({ api, pairs: pairObject, createBalances }) const pairIds = Object.keys(filteredPairs) api.log(`uniV2RunLog: Filtered to ${pairIds.length}/${pairs.length} pairs Factory: ${Factory} Chain: ${chain}`) if (!pairIds.length) return { dailyVolume: 0, dailyFees: 0, dailyUserFees: 0, dailyRevenue: 0, dailySupplySideRevenue: 0, dailyProtocolRevenue: 0, dailyHoldersRevenue: 0, } const lpSupplies = await api.multiCall({ abi: 'uint256:totalSupply', calls: pairIds, permitFailure: false, }) const gauges = await api.multiCall({ abi: 'function gauges(address) view returns (address)', target: GaugeManager, calls: pairIds.map(pairid => ({ params: [pairid] })), permitFailure: true, }) const gaugeSupplies = await api.multiCall({ abi: 'uint256:totalSupply', calls: gauges, permitFailure: true, }) const allSwapLogs = await getLogs({ targets: pairIds, eventAbi: SwapEvent, flatten: false }) const allFeesLogs = await getLogs({ targets: pairIds, eventAbi: FeesEvent, flatten: false }) const dailyVolume = createBalances() const dailyFees = createBalances() const dailyRevenue = createBalances() const dailySupplySideRevenue = createBalances() // Get daily volume from Swap events. allSwapLogs.forEach((logs, index) => { if (!logs.length) return const pair = pairIds[index] const [token0, token1] = pairObject[pair] logs.forEach((log: any) => { addOneToken({ chain, balances: dailyVolume, token0, token1, amount0: log.amount0In, amount1: log.amount1In }) addOneToken({ chain, balances: dailyVolume, token0, token1, amount0: log.amount0Out, amount1: log.amount1Out }) }) }) // Fee / revenue metrics from Fees events. // // Blackhole basic pools distribute swap fees as follows: // - Unstaked LPs receive all fees proportional to their LP token balance. // - Staked LPs deposit LP tokens into a Gauge, and their fee share is routed to veBLACK voters as bribes. // // Each Fees event already includes the exact fee collected for that swap (including any referral/staking-NFT cuts). // To split these fees between supply-side LPs and veBLACK holders, we estimate the share of LP tokens // held by the gauge at the time of execution using the current ratio: // // revenueShare = gaugeSupply / totalLpSupply // // This ratio is an approximation because LP balances can change throughout the day. // Computing precise ratios per swap is far too expensive. allFeesLogs.forEach((logs: any, index) => { if (!logs.length) return const pair = pairIds[index] const [token0, token1] = pairObject[pair] const gaugeSupply = Number(gaugeSupplies[index] ?? 0) const lpSupply = Number(lpSupplies[index] ?? 0) // revenueShare determines the portion of fees attributed to staked LPs (=> veBLACK holders). // supplySideRevenueShare determines the portion attributed to unstaked LPs. const revenueShare = lpSupply > 0 ? gaugeSupply / lpSupply : 0 const supplySideRevenueShare = 1 - revenueShare logs.forEach((log: any) => { const amount0 = Number(log.amount0) const amount1 = Number(log.amount1) // Exactly one of amount0 / amount1 is non-zero for a FeesEvent. if (amount0 > 0) { dailyFees.add(token0, amount0) dailyRevenue.add(token0, amount0 * revenueShare) dailySupplySideRevenue.add(token0, amount0 * supplySideRevenueShare) } else { dailyFees.add(token1, amount1) dailyRevenue.add(token1, amount1 * revenueShare) dailySupplySideRevenue.add(token1, amount1 * supplySideRevenueShare) } }) }) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue, dailySupplySideRevenue: dailySupplySideRevenue, dailyProtocolRevenue: 0, dailyHoldersRevenue: dailyRevenue, } } const adapter: SimpleAdapter = { version: 2, pullHourly: true, methodology: { Fees: "All swap fees paid by traders.", UserFees: "All swap fees paid by traders.", SupplySideRevenue: "Portion of swap fees paid out to unstaked LPs.", Revenue: "Portion of swap fees attributed to staked LPs, which are routed through the Gauge and distributed to veBLACK voters as bribes.", ProtocolRevenue: "No protocol revenue.", HoldersRevenue: "Portion of swap fees attributed to staked LPs, which are routed through the Gauge and distributed to veBLACK voters as bribes.", }, chains: [CHAIN.AVAX], fetch, } export default adapter ================================================ FILE: dexs/bladeswap-v2.ts ================================================ import { SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { FetchOptions } from "../adapters/types"; const fetch: any = async ({ getLogs, createBalances, }: FetchOptions) => { const dailyVolume = createBalances() let eventAbi = "event Swap(address indexed pool, address indexed user, bytes32[] tokenRef, int128[] delta)" const logs = await getLogs({ target: "0x10F6b147D51f7578F760065DF7f174c3bc95382c", eventAbi, }) logs.forEach((log: any) => { const pool = log.pool.toLowerCase() const hasPool = log.tokenRef.some((val: string) => '0x' + val.slice(2 + 24).toLowerCase() === pool) // this is lp deposit/withdrawal, not swap if (hasPool) return; log.tokenRef.forEach((val: string, i: number) => { const token = '0x' + val.slice(2 + 24).toLowerCase() const volume = Number(log.delta[i]) if (volume < 0) return; dailyVolume.add(token, volume) }) }) return { dailyVolume }; } const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.BLAST]: { fetch, start: '2024-02-29', } } } export default adapter; ================================================ FILE: dexs/blastfutures/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import {FetchResultVolume, SimpleAdapter} from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import {getUniqStartOfTodayTimestamp} from "../../helpers/getUniSubgraphVolume"; const historicalVolumeEndpoint = "https://api.prod.rabbitx.io/bfx/volume" const volumeByTime = (timestampFrom: number, timestampTo: number) => { const url = `${historicalVolumeEndpoint}?start_date=${timestampFrom}&end_date=${timestampTo}`; return url; } interface IVolumeall { volume: string; } const fetchVolume = async (timestamp: number): Promise => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const fromMS = dayTimestamp * 1000 * 1000; const toMS = (dayTimestamp + 60 * 60 * 24) * 1000 * 1000; const response = await fetchURL(volumeByTime(fromMS, toMS)); const marketsData: IVolumeall[] = response.result; const dailyVolume = marketsData.reduce((acc, {volume}) => acc + Number(volume), 0); return { dailyVolume: dailyVolume, timestamp: timestamp, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.BLAST]: { fetch: fetchVolume, start: '2023-11-17', // Replace with actual start timestamp }, }, }; export default adapter; ================================================ FILE: dexs/blex-derivatives.ts ================================================ import * as sdk from "@defillama/sdk"; import request, { gql } from "graphql-request"; import { SimpleAdapter, Fetch } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const endpoints: { [key: string]: string } = { [CHAIN.ARBITRUM]: sdk.graph.modifyEndpoint('FZz1rRe9kEd3FG6ZiX2tdoryxYiSFH4RnzKjMwny3mFH'), } const derivativesData = gql` query get_summary($period: String!, $id: String!){ summaries(where: {period: $period, id: $id}){ tradingVolume } } ` interface IGraphResponse { summaries: Array<{ tradingVolume: string tradingLPVolume: string trades: string openInterest: string uniqueUsers: string fees: string lpVolume: string }> } const getFetch = (chain: string): Fetch => async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date((timestamp * 1000))) const dailyData: IGraphResponse = await request(endpoints[chain], derivativesData, { id: "daily:" + String(dayTimestamp), period: 'daily', }) return { dailyVolume: dailyData.summaries.length == 1 ? String(Number(Object.values(dailyData.summaries[0]).reduce((sum, element) => String(Number(sum) + Number(element)))) * 10 ** -18) : undefined, } } const startTimestamps: { [chain: string]: number } = { [CHAIN.ARBITRUM]: 1691211277, } const adapter: SimpleAdapter = { adapter: Object.keys(endpoints).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: getFetch(chain), start: startTimestamps[chain], deadFrom: "2025-03-15", } } }, {}), } export default adapter; ================================================ FILE: dexs/blex-volume.ts ================================================ import * as sdk from "@defillama/sdk"; import request, { gql } from "graphql-request"; import { SimpleAdapter, Fetch } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const endpoints: { [key: string]: string } = { [CHAIN.ARBITRUM]: sdk.graph.modifyEndpoint('FZz1rRe9kEd3FG6ZiX2tdoryxYiSFH4RnzKjMwny3mFH'), } const allData = gql` query get_summary($period: String!, $id: String!){ summaries(where: {period: $period, id: $id}){ tradingLPVolume } } ` interface IGraphResponse { summaries: Array<{ tradingVolume: string tradingLPVolume: string trades: string openInterest: string uniqueUsers: string fees: string lpVolume: string }> } const getFetch = (chain: string): Fetch => async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date((timestamp * 1000))) const dailyData: IGraphResponse = await request(endpoints[chain], allData, { id: "daily:" + String(dayTimestamp), period: 'daily', }) return { dailyVolume: dailyData.summaries.length == 1 ? String(Number(Object.values(dailyData.summaries[0]).reduce((sum, element) => String(Number(sum) + Number(element)))) * 10 ** -18) : undefined, } } const startTimestamps: { [chain: string]: number } = { [CHAIN.ARBITRUM]: 1691211277, } const adapter: SimpleAdapter = { adapter: Object.keys(endpoints).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: getFetch(chain), start: startTimestamps[chain], deadFrom: "2025-03-15", } } }, {}), } export default adapter; ================================================ FILE: dexs/bluefin/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; const fetch = async ({ startTimestamp, endTimestamp }: FetchOptions) => { const { volume, } = (await httpGet(`https://dapi.api.sui-prod.bluefin.io/marketData/volume?startTime=${startTimestamp * 1000}&&endTime=${endTimestamp * 1000}`)) return { dailyVolume: volume, }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.SUI]: { fetch, start: '2023-09-25', deadFrom: "2025-08-01", }, }, }; export default adapter; ================================================ FILE: dexs/bluefin-amm/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const fetch = async (_a: any, _b: any, _c: FetchOptions) => { const allPools: any[] = []; let page = 1; let hasMore = true; const maxPoolsPerPage = 100; while (hasMore) { const response = await fetchURL(`https://swap.api.sui-prod.bluefin.io/api/v1/pools/info?page=${page}&limit=${maxPoolsPerPage}`); const pools = Array.isArray(response) ? response : (response.data || response.pools || []); if (pools.length === 0) break; allPools.push(...pools); if (pools.length < maxPoolsPerPage) { hasMore = false; } else { const nextPage = response.nextPage || (response.data && response.data.nextPage); if (!nextPage) hasMore = false; } page++; } let dailyVolume = 0; for (const pool of allPools) { dailyVolume += Number(pool.day.volume); } return { dailyVolume }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.SUI]: { fetch, start: '2024-11-19', runAtCurrTime: true }, }, }; export default adapter; ================================================ FILE: dexs/bluefin-pro/index.ts ================================================ import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; const fetch = async () => { const exchangeInfo = (await httpGet(`https://api.sui-prod.bluefin.io/v1/exchange/info`)) let volume = 0; for(const market of exchangeInfo.markets){ if(market.status !== "ACTIVE") continue; const {quoteVolume24hrE9} = (await httpGet(`https://api.sui-prod.bluefin.io/v1/exchange/ticker?symbol=${market.symbol}`)) volume += Number(quoteVolume24hrE9) } return { dailyVolume: volume/1e9, }; }; const adapter: SimpleAdapter = { adapter:{ [CHAIN.SUI]:{ fetch: fetch, runAtCurrTime: true } } }; export default adapter; ================================================ FILE: dexs/bluemove.ts ================================================ import fetchURL from "../utils/fetchURL" import { FetchOptions, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; import { queryEvents } from "../helpers/sui"; const historicalVolumeEndpoint = "https://aptos-mainnet-api.bluemove.net/api/histogram"; const SUI_PACKAGE = "0xb24b6789e088b876afabca733bed2299fbc9e2d6369be4d1acfa17d8145454d9"; interface IVolumeall { num: string; date: string; } const fetchAptos = async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const historicalVolume: IVolumeall[] = (await fetchURL(historicalVolumeEndpoint))?.data.list; const dailyVolume = historicalVolume .find(dayItem => (new Date(dayItem.date.split('T')[0]).getTime() / 1000) === dayTimestamp)?.num return { dailyVolume: dailyVolume, }; }; const fetchSui = async (_timestamp: number, _: any, options: FetchOptions) => { const events = await queryEvents({ eventModule: { package: SUI_PACKAGE, module: "swap" }, options, }); const swapEvents = events.filter((e: any) => e.amount_x_in !== undefined); const dailyVolume = options.createBalances(); for (const e of swapEvents) { const amountXIn = BigInt(e.amount_x_in ?? 0); const amountYIn = BigInt(e.amount_y_in ?? 0); if (amountXIn > 0) { const token = e.token_x_in.startsWith("0x") ? e.token_x_in : "0x" + e.token_x_in; dailyVolume.add(token, amountXIn); } else if (amountYIn > 0) { const token = e.token_y_in.startsWith("0x") ? e.token_y_in : "0x" + e.token_y_in; dailyVolume.add(token, amountYIn); } } return { dailyVolume, timestamp: options.startOfDay, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.APTOS]: { fetch: fetchAptos, start: '2022-10-20', deadFrom: '2024-03-01', }, [CHAIN.SUI]: { fetch: fetchSui, start: '2024-03-01', }, }, version: 1 }; export default adapter; ================================================ FILE: dexs/blum/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { CHAIN } from "../../helpers/chains" import { FetchOptions } from "../../adapters/types" const endpoint = "https://tonfunstats-eqnd7.ondigitalocean.app/api/v1/getVolume" const fetch = async ({ startTimestamp, endTimestamp, createBalances, }: FetchOptions) => { const res = await fetchURL(`${endpoint}?from=${startTimestamp}&to=${endTimestamp}&service=blum`) const TON = "coingecko:the-open-network" const dailyVolume = createBalances() dailyVolume.addCGToken('the-open-network', res.volume / 1e9) return { dailyVolume, } } const adapter = { version: 2, adapter: { [CHAIN.TON]: { fetch, start: '2024-10-24', }, }, } export default adapter ================================================ FILE: dexs/blur.ts ================================================ import { SimpleAdapter, FetchOptions } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; const abis = { Execution: "event Execution((address trader, uint256 id, uint256 amount, address collection, uint8 assetType) transfer, bytes32 orderHash, uint256 listingIndex, uint256 price, (address recipient, uint16 rate) makerFee, ((address recipient, uint16 rate) protocolFee, (address recipient, uint16 rate) takerFee) fees, uint8 orderType)", Execution721MakerFeePacked: "event Execution721MakerFeePacked(bytes32 orderHash, uint256 tokenIdListingIndexTrader, uint256 collectionPriceSide, uint256 makerFeeRecipientRate)", Execution721Packed: "event Execution721Packed(bytes32 orderHash, uint256 tokenIdListingIndexTrader, uint256 collectionPriceSide)", Execution721TakerFeePacked: "event Execution721TakerFeePacked(bytes32 orderHash, uint256 tokenIdListingIndexTrader, uint256 collectionPriceSide, uint256 takerFeeRecipientRate)", }; const unpackPrice = (packedValue: any): bigint => { packedValue = BigInt(packedValue); packedValue /= BigInt(2) ** BigInt(160); return packedValue % BigInt(2) ** BigInt(88); }; const marketplace = "0xb2ecfe4e4d61f8790bbb9de2d1259b9e2410cea5"; const fetch = async ({ getLogs, createBalances }: FetchOptions) => { const dailyVolume = createBalances(); const [executionLogs, execution721MakerFeeLogs, execution721PackedLogs, execution721TakerFeeLogs] = await Promise.all([ abis.Execution, abis.Execution721MakerFeePacked, abis.Execution721Packed, abis.Execution721TakerFeePacked, ].map(eventAbi => getLogs({ target: marketplace, eventAbi }))); executionLogs.forEach((log: any) => dailyVolume.addGasToken(log.price)); execution721PackedLogs.forEach((log: any) => dailyVolume.addGasToken(unpackPrice(log.collectionPriceSide))); execution721MakerFeeLogs.forEach((log: any) => dailyVolume.addGasToken(unpackPrice(log.collectionPriceSide))); execution721TakerFeeLogs.forEach((log: any) => dailyVolume.addGasToken(unpackPrice(log.collectionPriceSide))); return { dailyVolume }; }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.ETHEREUM]: { fetch, start: "2023-07-02" }, }, }; export default adapter; ================================================ FILE: dexs/bmx-derivatives.ts ================================================ import request, { gql } from "graphql-request"; import { Fetch, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const endpoints: { [key: string]: string } = { [CHAIN.BASE]: "https://api.goldsky.com/api/public/project_cm2x72f7p4cnq01x5fuy95ihm/subgraphs/bmx-base-stats/0.0.2/gn", [CHAIN.MODE]: "https://api.goldsky.com/api/public/project_cm2x72f7p4cnq01x5fuy95ihm/subgraphs/bmx-mode-stats/0.0.1/gn", }; const historicalDataDerivatives = gql` query get_volume($period: String!, $id: String!) { volumeStats(where: { period: $period, id: $id }) { liquidation margin } } `; const historicalOI = gql` query get_trade_stats($period: String!, $id: String!) { tradingStats(where: { period: $period, id: $id }) { id longOpenInterest shortOpenInterest } } `; interface IGraphResponse { volumeStats: Array<{ burn: string; liquidation: string; margin: string; mint: string; swap: string; }>; } interface IGraphResponseOI { tradingStats: Array<{ id: string; longOpenInterest: string; shortOpenInterest: string; }>; } const getFetch = (chain: string): Fetch => async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp( new Date(timestamp * 1000) ); const dailyData: IGraphResponse = await request(endpoints[chain], historicalDataDerivatives, { id: String(dayTimestamp) + ":daily", period: "daily", }); const tradingStats: IGraphResponseOI = await request( endpoints[chain], historicalOI, { id: String(dayTimestamp) + ":daily", period: "daily", } ); const openInterestAtEnd = Number(tradingStats.tradingStats[0]?.longOpenInterest || 0) + Number(tradingStats.tradingStats[0]?.shortOpenInterest || 0); const longOpenInterestAtEnd = Number( tradingStats.tradingStats[0]?.longOpenInterest || 0 ); const shortOpenInterestAtEnd = Number( tradingStats.tradingStats[0]?.shortOpenInterest || 0 ); return { longOpenInterestAtEnd: longOpenInterestAtEnd ? String(longOpenInterestAtEnd * 10 ** -30) : undefined, shortOpenInterestAtEnd: shortOpenInterestAtEnd ? String(shortOpenInterestAtEnd * 10 ** -30) : undefined, openInterestAtEnd: openInterestAtEnd ? String(openInterestAtEnd * 10 ** -30) : undefined, dailyVolume: dailyData.volumeStats.length == 1 ? String( Number( Object.values(dailyData.volumeStats[0]).reduce((sum, element) => String(Number(sum) + Number(element)) ) ) * 10 ** -30 ) : 0, }; }; const startTimestamps: { [chain: string]: number } = { [CHAIN.BASE]: 1694304000, [CHAIN.MODE]: 1720627435, }; const adapter: SimpleAdapter = { adapter: Object.keys(endpoints).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: getFetch(chain), start: startTimestamps[chain], }, }; }, {}), }; export default adapter; ================================================ FILE: dexs/bmx-freestyle/index.ts ================================================ import BigNumber from "bignumber.js"; import { FetchOptions, FetchResultVolume, SimpleAdapter, } from "../../adapters/types"; import request, { gql } from "graphql-request"; import { CHAIN } from "../../helpers/chains"; const freestyleEndpoints: { [key: string]: string } = { [CHAIN.BASE]: "https://api.goldsky.com/api/public/project_cm2x72f7p4cnq01x5fuy95ihm/subgraphs/bmx_analytics_base/0.8.2/gn", [CHAIN.MODE]: "https://api.goldsky.com/api/public/project_cm2x72f7p4cnq01x5fuy95ihm/subgraphs/bmx_analytics_mode/0.8.2/gn", }; const freestyleQueries: { [key: string]: string } = { [CHAIN.BASE]: gql` query stats($from: String!, $to: String!) { dailyHistories( where: { timestamp_gte: $from timestamp_lte: $to accountSource: "0x6D63921D8203044f6AbaD8F346d3AEa9A2719dDD" } ) { timestamp platformFee accountSource tradeVolume } totalHistories( where: { accountSource: "0x6D63921D8203044f6AbaD8F346d3AEa9A2719dDD" } ) { timestamp platformFee accountSource tradeVolume } } `, [CHAIN.MODE]: gql` query stats($from: String!, $to: String!) { dailyHistories( where: { timestamp_gte: $from timestamp_lte: $to accountSource: "0xC0ff4B56f62f20bA45f4229CC6BAaD986FA2a904" } ) { timestamp platformFee accountSource tradeVolume } totalHistories( where: { accountSource: "0xC0ff4B56f62f20bA45f4229CC6BAaD986FA2a904" } ) { timestamp platformFee accountSource tradeVolume } } `, }; interface IGraphResponseFreestyle { dailyHistories: Array<{ tiemstamp: string; platformFee: string; accountSource: string; tradeVolume: string; }>; totalHistories: Array<{ tiemstamp: string; platformFee: string; accountSource: string; tradeVolume: BigNumber; }>; } const ONE_DAY_IN_SECONDS = 60 * 60 * 24; const toString = (x: BigNumber) => { if (x.isEqualTo(0)) return undefined; return x.toString(); }; const fetch = async ( _a: any, _b: any, options: FetchOptions): Promise => { const startTime = options.startOfDay; const endTime = startTime + ONE_DAY_IN_SECONDS; const response: IGraphResponseFreestyle = await request( freestyleEndpoints[options.chain], freestyleQueries[options.chain], { from: String(startTime), to: String(endTime), } ); let dailyVolume = new BigNumber(0); response.dailyHistories.forEach((data) => { dailyVolume = dailyVolume.plus(new BigNumber(data.tradeVolume)); }); dailyVolume = dailyVolume.dividedBy(new BigNumber(1e18)); const _dailyVolume = toString(dailyVolume); return { dailyVolume: _dailyVolume || "0", }; }; const adapter: SimpleAdapter = { version: 1, adapter: { [CHAIN.BASE]: { fetch, start: "2024-05-01", }, [CHAIN.MODE]: { fetch, start: "2024-05-01", }, }, }; export default adapter; ================================================ FILE: dexs/bmx-swap.ts ================================================ import request, { gql } from "graphql-request"; import { Fetch, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; const endpoints: { [key: string]: string } = { [CHAIN.BASE]: "https://api.goldsky.com/api/public/project_cm2x72f7p4cnq01x5fuy95ihm/subgraphs/bmx-base-stats/0.0.2/gn", [CHAIN.MODE]: "https://api.goldsky.com/api/public/project_cm2x72f7p4cnq01x5fuy95ihm/subgraphs/bmx-mode-stats/0.0.1/gn", }; const historicalDataSwap = gql` query get_volume($period: String!, $id: String!) { volumeStats(where: { period: $period, id: $id }) { swap } } `; interface IGraphResponse { volumeStats: Array<{ burn: string; liquidation: string; margin: string; mint: string; swap: string; }>; } const getFetch = (chain: string): Fetch => async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp( new Date(timestamp * 1000) ); const dailyData: IGraphResponse = await request(endpoints[chain], historicalDataSwap, { id: String(dayTimestamp) + ":daily", period: "daily", }); return { dailyVolume: dailyData.volumeStats.length == 1 ? String( Number( Object.values(dailyData.volumeStats[0]).reduce((sum, element) => String(Number(sum) + Number(element)) ) ) * 10 ** -30 ) : 0, }; }; const startTimestamps: { [chain: string]: number } = { [CHAIN.BASE]: 1694304000, [CHAIN.MODE]: 1720627435, }; const adapter: SimpleAdapter = { adapter: Object.keys(endpoints).reduce((acc, chain) => { return { ...acc, [chain]: { fetch: getFetch(chain), start: startTimestamps[chain], }, }; }, {}), }; export default adapter; ================================================ FILE: dexs/bogged-finance/index.ts ================================================ import fetchURL from "../../utils/fetchURL" import { Chain, FetchOptions } from "../../adapters/types"; import { FetchResultVolume, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; const historicalVolumeEndpoint = (chain: string) => `https://analytics.bog-general-api.com/daily_volume?type=all&chain=${chain}` interface IVolumeall { dailyVolume: number; timestamp: number; } type TChains = { [k: Chain | string]: string; }; const chains: TChains = { [CHAIN.BSC]: 'bsc', [CHAIN.AVAX]: 'avax', [CHAIN.FANTOM]: 'ftm', [CHAIN.POLYGON]: 'matic', [CHAIN.CRONOS]: 'cro' }; const fetch = async (timestamp: any, _b: any, options: FetchOptions): Promise => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) const historicalVolume: IVolumeall[] = (await fetchURL(historicalVolumeEndpoint(chains[options.chain]))); const dailyVolume = historicalVolume .find(dayItem => Math.floor(Number(dayItem.timestamp)/1000) === dayTimestamp)?.dailyVolume return { dailyVolume: dailyVolume, }; } const adapter: SimpleAdapter = { adapter: Object.keys(chains).reduce((acc, chain: any) => { return { ...acc, [chain]: { fetch, } } }, {}) }; export default adapter; ================================================ FILE: dexs/boop-fun/index.ts ================================================ import { Dependencies, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { queryDuneSql } from "../../helpers/dune"; import { FetchOptions } from "../../adapters/types"; interface IData { total_volume: number; } const fetch = async (_a: any, _b: any, options: FetchOptions) => { const data: IData[] = await queryDuneSql(options, ` WITH buy_volume AS ( SELECT SUM(buy_amount) / 1e9 AS volume FROM boopdotfun_solana.boop_call_buy_token WHERE call_block_time >= from_unixtime(${options.startTimestamp}) and call_block_time <= from_unixtime(${options.endTimestamp}) ), sell_volume AS ( SELECT SUM(amount_out_min) / 1e9 AS volume FROM boopdotfun_solana.boop_call_sell_token WHERE call_block_time >= from_unixtime(${options.startTimestamp}) and call_block_time <= from_unixtime(${options.endTimestamp}) ) SELECT COALESCE((SELECT volume FROM buy_volume), 0) + COALESCE((SELECT volume FROM sell_volume), 0) AS total_volume `) const dailyVolume = options.createBalances(); dailyVolume.addCGToken('solana', data[0].total_volume); return { dailyVolume }; }; const adapter: SimpleAdapter = { fetch, dependencies: [Dependencies.DUNE], chains: [CHAIN.SOLANA], start: '2025-05-01', isExpensiveAdapter: true } export default adapter ================================================ FILE: dexs/boros/index.ts ================================================ import { SimpleAdapter, FetchOptions } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { METRIC } from "../../helpers/metrics"; const BOROS_ABIS = { MARKET_CREATION_EVENT: 'event MarketCreated(address market,tuple(string name,string symbol,bool k_isIsolatedOnly, uint32 k_maturity,uint16 k_tokenId,uint24 k_marketId,uint8 k_tickStep, uint16 k_iTickThresh) immData, tuple(uint16 maxOpenOrders, address markRateOracle, address fIndexOracle, uint128 hardOICap, uint64 takerFee, uint64 otcFee, tuple(uint64 base,uint64 slope,uint64 feeRate)liqSettings,uint64 kIM, uint64 kMM,uint32 tThresh, uint16 maxRateDeviationFactorBase1e4, uint16 closingOrderBoundBase1e4, int16 loUpperConstBase1e4, int16 loUpperSlopeBase1e4, int16 loLowerConstBase1e4, int16 loLowerSlopeBase1e4, uint8 status, bool useImpliedAsMarkRate) config)', MARKET_ORDERS_FILLED_EVENT: 'event MarketOrdersFilled (bytes26 user, uint256 totalTrade, uint256 totalFees)', OTC_SWAP_EVENT: 'event OtcSwap (bytes26 user, bytes26 counterParty, uint256 trade, int256 cashToCounter, uint256 otcFee)', PAYMENT_FROM_SETTLEMENT_EVENT: 'event PaymentFromSettlement (bytes26 user, uint256 lastFTime, uint256 latestFTime, int256 payment, uint256 fees)', LIQUIDATION_EVENT: 'event Liquidate (bytes26 liq, bytes26 vio, uint256 liqTrade, uint256 liqFee)', } const BOROS_FACTORY = '0x3080808080Ee6a795c1a6Ff388195Aa5F11ECeE0'; const BOROS_FACTORY_CREATION_BLOCK = 362039621; // 2025-07-27 const TWO_128 = 1n << 128n; const TWO_127 = 1n << 127n; interface BorosMarket { address: string; symbol: string; maturity: number; coinGeckoId: string; }; const TOKENID_TO_CGID: Record = { 1: 'bitcoin', 2: 'ethereum', 3: 'tether', 4: 'binancecoin', 5: 'hyperliquid', }; // AMMConfigUpdated transactions, ignore volume from these transactions const EXCLUDE_OTC_SWAPS: Array = [ '0x752eea9b38bb427e10a1ae0b8a55783cd700033c6967ae70590202645a1177ad', '0xf8e45548cbf08c48c71d054ce872f7e8cbef6633b45224a28d5c7c5128471856', ] const getCgId = (tokenId: number): string => { const cgId = TOKENID_TO_CGID[tokenId]; if (!cgId) { throw Error(`No CG mapping for tokenId: ${tokenId}`) } return cgId; } const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const dailyRevenue = options.createBalances(); const dailySupplySideRevenue = options.createBalances(); const marketCreationLogs = await options.getLogs({ target: BOROS_FACTORY, eventAbi: BOROS_ABIS.MARKET_CREATION_EVENT, cacheInCloud: true, fromBlock: BOROS_FACTORY_CREATION_BLOCK }); const markets: Array = marketCreationLogs .filter(marketLog => Number(marketLog.immData.k_maturity) >= options.fromTimestamp) .map(marketLog => ({ address: marketLog.market, symbol: marketLog.immData.symbol, maturity: Number(marketLog.immData.k_maturity), coinGeckoId: getCgId(marketLog.immData.k_tokenId), })) .filter(market => market.coinGeckoId); await Promise.all(markets.map(async (market) => { const marketOrderFilledLogs = await options.getLogs({ target: market.address, eventAbi: BOROS_ABIS.MARKET_ORDERS_FILLED_EVENT, onlyArgs: false, }); marketOrderFilledLogs.forEach((item: any) => { const trade = item.args; let tradeAmount = trade.totalTrade >> 128n; if (tradeAmount > TWO_127) tradeAmount = TWO_128 - tradeAmount; dailyVolume.addCGToken(market.coinGeckoId, Number(tradeAmount) / 1e18); // add open/close fees dailyFees.addCGToken(market.coinGeckoId, Number(trade.totalFees) / 1e18, METRIC.OPEN_CLOSE_FEES); dailyRevenue.addCGToken(market.coinGeckoId, Number(trade.totalFees) / 1e18, METRIC.OPEN_CLOSE_FEES); }); const otcSwapLogs = await options.getLogs({ target: market.address, eventAbi: BOROS_ABIS.OTC_SWAP_EVENT, onlyArgs: false, }); otcSwapLogs.forEach((item: any) => { if (EXCLUDE_OTC_SWAPS.includes(item.transaction_hash)) { return; } const swap = item.args; // let tradeAmountAfterFee = swap.trade >> 128n; // if (tradeAmountAfterFee > TWO_127) // tradeAmountAfterFee = TWO_128 - tradeAmountAfterFee; // don't add volume from otc swap // dailyVolume.addCGToken(market.coinGeckoId, (Number(tradeAmountAfterFee) + Number(swap.otcFee)) / 1e18); // add swap fees dailyFees.addCGToken(market.coinGeckoId, Number(swap.otcFee) / 1e18, METRIC.SWAP_FEES); dailySupplySideRevenue.addCGToken(market.coinGeckoId, Number(swap.otcFee) / 1e18, METRIC.SWAP_FEES) }) const paymentSettlementLogs = await options.getLogs({ target: market.address, eventAbi: BOROS_ABIS.PAYMENT_FROM_SETTLEMENT_EVENT, }); paymentSettlementLogs.forEach(settlement => { dailyFees.addCGToken(market.coinGeckoId, Number(settlement.fees) / 1e18, METRIC.TRADING_FEES); dailyRevenue.addCGToken(market.coinGeckoId, Number(settlement.fees) / 1e18, METRIC.TRADING_FEES); }); const liquidationLogs = await options.getLogs({ target:market.address, eventAbi:BOROS_ABIS.LIQUIDATION_EVENT }); liquidationLogs.forEach((liquidation:any)=>{ dailyFees.addCGToken(market.coinGeckoId, Number(liquidation.liqFee)/1e18,METRIC.LIQUIDATION_FEES); dailyRevenue.addCGToken(market.coinGeckoId, Number(liquidation.liqFee) / 1e18, METRIC.LIQUIDATION_FEES); }); })); return { dailyVolume, dailyFees, dailyRevenue, dailySupplySideRevenue, dailyProtocolRevenue: dailyRevenue, }; } const methodology = { Fees: "Includes open/close trades fees, swap fees, liquidation and settlement fees.", Revenue: "Include open/close fees and settlement fees going to the protocol.", SupplySideRevenue: "Swap fees paid to vault liquidity providers.", ProtocolRevenue: "Include open/close fees and settlement fees going to the protocol.", }; const breakdownMethodology = { Fees: { [METRIC.SWAP_FEES]: "Total fees from token swaps.", [METRIC.OPEN_CLOSE_FEES]: "Total fees from trading open/close fees.", [METRIC.TRADING_FEES]: "Total fees from settlements.", [METRIC.LIQUIDATION_FEES]: "Total fees from liquidation events", }, Revenue: { [METRIC.OPEN_CLOSE_FEES]: "All fees from trading open/close fees.", [METRIC.TRADING_FEES]: "All fees from settlements.", [METRIC.LIQUIDATION_FEES]: "Total fees from liquidation events", }, SupplySideRevenue: { [METRIC.SWAP_FEES]: "Total fees from token swaps distributed to liquidity providers.", }, ProtocolRevenue: { [METRIC.OPEN_CLOSE_FEES]: "All fees from trading open/close fees.", [METRIC.TRADING_FEES]: "All fees from settlements.", [METRIC.LIQUIDATION_FEES]: "Total fees from liquidation events", } }; const adapter: SimpleAdapter = { fetch, methodology, breakdownMethodology, version: 2, pullHourly: true, chains: [CHAIN.ARBITRUM], start: '2025-07-27', }; export default adapter; ================================================ FILE: dexs/bounce-tech.ts ================================================ // Bounce - Leveraged Tokens on HyperEVM // // Volume = notional base asset exposure based on mints and redemptions. // notional = baseAmount × targetLeverage // // Mint event: baseAmount = Base asset amount deposited by user // Redeem event: baseAmount = Base asset amount withdrawn by user (after fees, instant) // ExecuteRedeem event: baseAmount = Base asset amount withdrawn by user (after fees, async) // // Contract resolution chain: // GlobalStorage.factory() → Factory address // GlobalStorage.baseAsset() → Base asset address // Factory.lts() → All deployed LeveragedToken addresses // LeveragedToken.targetLeverage() → Leverage per token (1e18 scale) import { FetchOptions, SimpleAdapter } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; const GLOBAL_STORAGE = '0xa07d06383c1863c8A54d427aC890643d76cc03ff'; const MINT_ABI = 'event Mint(address indexed minter, address indexed to, uint256 baseAmount, uint256 ltAmount)'; const REDEEM_ABI = 'event Redeem(address indexed sender, address indexed to, uint256 ltAmount, uint256 baseAmount)'; const EXECUTE_REDEEM_ABI = 'event ExecuteRedeem(address indexed user, uint256 ltAmount, uint256 baseAmount)'; const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const factory: string = await options.api.call({ abi: 'address:factory', target: GLOBAL_STORAGE }); const [baseAsset, lts]: [string, string[]] = await Promise.all([ options.api.call({ abi: 'address:baseAsset', target: GLOBAL_STORAGE }), options.api.call({ abi: 'address[]:lts', target: factory }), ]); const [leverages, mintLogs, redeemLogs, executeRedeemLogs] = await Promise.all([ options.api.multiCall({ abi: 'uint256:targetLeverage', calls: lts }), options.getLogs({ targets: lts, eventAbi: MINT_ABI, entireLog: true, parseLog: true }), options.getLogs({ targets: lts, eventAbi: REDEEM_ABI, entireLog: true, parseLog: true }), options.getLogs({ targets: lts, eventAbi: EXECUTE_REDEEM_ABI, entireLog: true, parseLog: true }), ]); // Mapping LT address to leverage for subsequent log lookup const leverageByLt: Record = {}; lts.forEach((lt, i) => { leverageByLt[lt.toLowerCase()] = BigInt(leverages[i]); }); const addNotional = (log: any) => { const leverage = leverageByLt[log.address.toLowerCase()]; const notional = BigInt(log.args.baseAmount) * leverage / 10n ** 18n; dailyVolume.add(baseAsset, notional); }; mintLogs.forEach((log: any) => addNotional(log,)); redeemLogs.forEach((log: any) => addNotional(log,)); executeRedeemLogs.forEach((log: any) => addNotional(log)); return { dailyVolume }; }; const methodology = { Volume: 'Notional leveraged exposure created and destroyed via mints and redemptions. Calculated as base asset amount × target leverage per token.', }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, chains: [CHAIN.HYPERLIQUID], start: '2026-01-28', methodology, }; export default adapter; ================================================ FILE: dexs/brine/index.ts ================================================ import fetchURL from "../../utils/fetchURL"; import type { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const VOLUME_URL = `https://api.tanx.fi/external-aggregator/defillama/volume24/`; const fetch = async (timestamp: number) => { const dailyVolume = (await fetchURL(`${VOLUME_URL}?timestamp=${timestamp}`)).payload.volume; return { dailyVolume, timestamp, }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.ETHEREUM]: { fetch, start: '2023-04-06', }, }, }; export default adapter; ================================================ FILE: dexs/brownfi/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { filterPools } from "../../helpers/uniswap"; import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { addOneToken } from "../../helpers/prices"; import { cache } from "@defillama/sdk"; const chainConfig: Record = { [CHAIN.BERACHAIN]: { factory: "0x43AB776770cC5c739adDf318Af712DD40918C42d", start: '2025-07-04', }, [CHAIN.BASE]: { factory: "0x43AB776770cC5c739adDf318Af712DD40918C42d", start: '2025-07-01', }, [CHAIN.ARBITRUM]: { factory: "0xD05395a6b6542020FBD38D31fe1377130b35592E", start: '2025-07-01', }, [CHAIN.HYPERLIQUID]: { factory: "0x3240853b71c89209ea8764CDDfA3b81766553E55", start: '2025-07-19', }, [CHAIN.LINEA]: { factory: "0x43AB776770cC5c739adDf318Af712DD40918C42d", start: '2025-09-05', }, [CHAIN.BSC]: { factory: "0x43AB776770cC5c739adDf318Af712DD40918C42d", start: '2025-07-01', }, [CHAIN.MONAD]: { factory: "0x68bc42F886ddf6a4b0B90a9496493dA1f8304536", start: '2025-12-02', }, }; const brownfiV2SwapEvent = "event Swap(address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, uint price0, uint price1, address indexed to)" const abis = { fees: "function fee() external view returns (uint32)", protocolFee: "function protocolFee() external view returns (uint64)" }; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const factory = chainConfig[options.chain].factory; const { createBalances, getLogs, chain, api } = options const cacheKey = `tvl-adapter-cache/cache/uniswap-forks/${factory.toLowerCase()}-${chain}.json` const { pairs, token0s, token1s } = await cache.readCache(cacheKey, { readFromR2Cache: true }) if (!pairs?.length) throw new Error('No pairs found, is there TVL adapter for this already?') const pairObject: { [key: string]: string[] } = {} const fees: any = {} const protocolFees: any = {} pairs.forEach((pair: string, i: number) => { pairObject[pair] = [token0s[i], token1s[i]] fees[pair] = 0 protocolFees[pair] = 0 }) let _fees = await api.multiCall({ abi: abis.fees, calls: pairs.map((pair: any) => pair), permitFailure: true }) _fees.forEach((fee: any, i: number) => { if (fee !== null) fees[pairs[i]] = fee / 1e8 }) let _protocolFees = await api.multiCall({ abi: abis.protocolFee, calls: pairs.map((pair: any) => pair), permitFailure: true }) _protocolFees.forEach((fee: any, i: number) => { if (fee !== null) protocolFees[pairs[i]] = fee / 1e8 }) const dailyVolume = createBalances() const dailyFees = createBalances() const dailyRevenue = createBalances() const dailySupplySideRevenue = createBalances() const filteredPairs = await filterPools({ api, pairs: pairObject, createBalances, minUSDValue: 100 }) const pairIds = Object.keys(filteredPairs) if (!pairIds.length) return { dailyVolume, dailyFees, } const allLogs = await getLogs({ targets: pairIds, eventAbi: brownfiV2SwapEvent, flatten: false }) allLogs.map((logs: any, index) => { if (!logs.length) return; const pair = pairIds[index] const fee = fees[pair] const protocolFee = protocolFees[pair] const [token0, token1] = pairObject[pair] const feeRate = fee / (1 + fee) logs.forEach((log: any) => { addOneToken({ chain, balances: dailyVolume, token0, token1, amount0: log.amount0In, amount1: log.amount1In }) addOneToken({ chain, balances: dailyVolume, token0, token1, amount0: log.amount0Out, amount1: log.amount1Out }) addOneToken({ chain, balances: dailyFees, token0, token1, amount0: Number(log.amount0In) * feeRate, amount1: Number(log.amount1In) * feeRate }) addOneToken({ chain, balances: dailyFees, token0, token1, amount0: Number(log.amount0Out) * feeRate, amount1: Number(log.amount1Out) * feeRate }) addOneToken({ chain, balances: dailyRevenue, token0, token1, amount0: Number(log.amount0In) * feeRate * protocolFee, amount1: Number(log.amount1In) * feeRate * protocolFee }) addOneToken({ chain, balances: dailyRevenue, token0, token1, amount0: Number(log.amount0Out) * feeRate * protocolFee, amount1: Number(log.amount1Out) * feeRate * protocolFee }) addOneToken({ chain, balances: dailySupplySideRevenue, token0, token1, amount0: Number(log.amount0In) * feeRate * (1 - protocolFee), amount1: Number(log.amount1In) * feeRate * (1 - protocolFee) }) addOneToken({ chain, balances: dailySupplySideRevenue, token0, token1, amount0: Number(log.amount0Out) * feeRate * (1 - protocolFee), amount1: Number(log.amount1Out) * feeRate * (1 - protocolFee) }) }) }) return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue: dailyRevenue, dailySupplySideRevenue: dailySupplySideRevenue, dailyProtocolRevenue: dailyRevenue, }; }; const methodology = { Fees: "Fees from swap transactions.", UserFees: "Fees from swap transactions.", Revenue: "Protocol share from swap fees.", ProtocolRevenue: "Protocol share from swap fees.", SupplySideRevenue: "Liquidity providers share from swap fees.", HoldersRevenue: "Holders does not earn any revenue.", } const adapters: SimpleAdapter = { version: 1, fetch, adapter: chainConfig, methodology, }; export default adapters; ================================================ FILE: dexs/bsx/index.ts ================================================ import { SimpleAdapter, FetchV2 } from "../../adapters/types"; import fetchURL from "../../utils/fetchURL"; import { CHAIN } from "../../helpers/chains"; import { getTimestampAtStartOfPreviousDayUTC } from "../../utils/date"; interface IBsxStatsResponse { volume_24h: string; volume_total: string; } const fetchBsxVolumeData: FetchV2 = async ({ endTimestamp }) => { const url = "https://api.bsx.exchange/defillama-stats?end_time=" + endTimestamp * 1e9; const data: IBsxStatsResponse = await fetchURL(url); const dailyVolume = Number(data.volume_24h).toFixed(2); const totalVolume = Number(data.volume_total).toFixed(2); return { timestamp: endTimestamp, dailyVolume, }; } const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.BASE]: { fetch: fetchBsxVolumeData, start: '2024-04-01', }, }, deadFrom: "2025-11-20", }; export default adapter; ================================================ FILE: dexs/bulbaswap-v2.ts ================================================ import { SimpleAdapter, FetchOptions } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { httpPost } from "../utils/fetchURL"; const v2Fees = 0.0035; const v2Endpoints = "https://api.bulbaswap.io/v1/subgraph-apis/v2"; const fetchV2Data = async (_: any, _tt: any, options: FetchOptions) => { const dayID = Math.floor(options.startOfDay / 86400); const factoryQuery = `{ uniswapFactory(id: "0x8D2A8b8F7d200d75Bf5F9E84e01F9272f90EFB8b") { totalLiquidityUSD totalVolumeUSD txCount } uniswapDayData(id: ${dayID}) { dailyVolumeUSD date } }`; const response = await httpPost(v2Endpoints, { query: factoryQuery, }); const dailyVolume = response.data.uniswapDayData.dailyVolumeUSD const result = { dailyVolume, dailyFees: (Number(dailyVolume) * v2Fees).toString(), }; return result; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.MORPH]: { fetch: fetchV2Data, start: '2024-10-27', }, }, }; export default adapter; ================================================ FILE: dexs/bulbaswap-v3.ts ================================================ import { SimpleAdapter, FetchOptions } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { httpPost } from "../utils/fetchURL"; const v3Endpoints = "https://api.bulbaswap.io/v1/subgraph-apis/v3"; const fetchV3Data = async (_: any, _tt: any, options: FetchOptions) => { const v3FactoryQuery = `{ factory(id: "0xFf8578C2949148A6F19b7958aE86CAAb2779CDDD") { totalValueLockedUSD totalVolumeUSD totalFeesUSD txCount } uniswapDayData(id: ${Math.floor(options.startOfDay / 86400)}) { volumeUSD feesUSD } }`; const response = await httpPost(v3Endpoints, { query: v3FactoryQuery, }); const dayData = response.data.uniswapDayData || {}; return { dailyVolume: dayData.volumeUSD || "0", dailyFees: dayData.feesUSD || "0", }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.MORPH]: { fetch: fetchV3Data, start: '2024-10-19', }, }, }; export default adapter; ================================================ FILE: dexs/bullaexchange/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const BULLA_API_URL = "https://api.gamma.xyz/frontend/externalApis/bulla/pools"; interface BullaPool { calculated24h: { volumeUSD: number; feesUSD: number; }; } interface BullaResponse { data: { pools: BullaPool[]; }; } const fetch = async (options: FetchOptions) => { const dailyFees = options.createBalances(); const dailyProtocolRevenue = options.createBalances(); const dailySupplySideRevenue = options.createBalances(); const dailyHoldersRevenue = options.createBalances(); // No holder revenue for now const response: BullaResponse = await fetchURL(BULLA_API_URL); const totalDailyFees = response.data.pools.reduce((acc, pool) => { return acc + (pool.calculated24h?.feesUSD || 0); }, 0); const protocolRevenue = totalDailyFees * 0.25; const supplySideRevenue = totalDailyFees * 0.75; // Add fees to balances (in USD) dailyFees.addUSDValue(totalDailyFees); dailyProtocolRevenue.addUSDValue(protocolRevenue); dailySupplySideRevenue.addUSDValue(supplySideRevenue); const dailyVolume = options.createBalances(); dailyVolume.addUSDValue( response.data.pools.reduce((acc, pool) => { return acc + (pool.calculated24h?.volumeUSD || 0); }, 0) ); return { dailyFees, dailyVolume, dailyRevenue: dailyProtocolRevenue, dailyUserFees: dailyFees, // User fees are the same as total fees dailyProtocolRevenue, dailySupplySideRevenue, dailyHoldersRevenue, }; }; const adapter: SimpleAdapter = { version: 2, adapter: { [CHAIN.BERACHAIN]: { fetch, runAtCurrTime: true, }, }, methodology: { Fees: "Trading fees collected by Bulla exchange", UserFees: "Trading fees paid by users", Revenue: "Protocol revenue from trading fees (25% of total fees, per fee switch)", ProtocolRevenue: "Revenue retained by the protocol (25% of fees, per fee switch)", SupplySideRevenue: "Revenue shared with liquidity providers (75% of total fees, per fee switch)", }, }; export default adapter; ================================================ FILE: dexs/bullbit-ai/index.ts ================================================ import { Dependencies, FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getETHReceived } from "../../helpers/token"; const FIXED_PLATFORM_FEE = 1 // 1% const feeReceiverMultisig = [ "0x87D30c1a5a79b060d7F6FBEa7791c381a2aFc7Ad", ] const fetch: any = async (options: FetchOptions) => { const dailyFees = options.createBalances(); await getETHReceived({ targets: feeReceiverMultisig, balances: dailyFees, options }); const dailyVolume = dailyFees.clone(100 / FIXED_PLATFORM_FEE) return { dailyVolume: dailyVolume, dailyFees: dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, } } const adapter: SimpleAdapter = { version: 2, fetch, chains: [CHAIN.BSC], pullHourly: true, start: '2025-08-16', dependencies: [Dependencies.ALLIUM], methodology: { Fees: 'All fees paid by users for launching, trading tokens.', Revenue: 'All fees collected by bullbit.ai protocol.', ProtocolRevenue: 'All fees collected by bullbit.ai protocol.', } } export default adapter ================================================ FILE: dexs/bullbit-perp-dex/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; import { METRIC } from "../../helpers/metrics"; const fetch = async (_a: any, _b: any, options: FetchOptions) => { const response = await fetchURL( `https://beta.bullbit.ai/services/one/v1/info/trading-data?from=${options.startTimestamp}&to=${options.endTimestamp}` ); const todaysData = response.find((day: any) => day.date === options.startOfDay); if (!todaysData) { throw new Error(`No data found for date ${options.startOfDay}`); } const dailyFees = options.createBalances(); const dailyVolume = options.createBalances(); dailyVolume.addUSDValue(todaysData.totalVolume); dailyFees.addUSDValue(todaysData.totalFee, METRIC.TRADING_FEES); return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, }; }; const methodology = { Volume: "Volume is sourced via Bullbit's official API, representing executed trades on the Execute engine.", Fees: "Fees are sourced via Bullbit's official API, representing trading fees collected by the protocol.", Revenue: "All fees are revenue", ProtocolRevenue: "All fees go to the protocol", }; const breakdownMethodology = { Fees: { [METRIC.TRADING_FEES]: "Trading fees charged on perp trades", }, Revenue: { [METRIC.TRADING_FEES]: "Trading fees charged on perp trades", }, ProtocolRevenue: { [METRIC.TRADING_FEES]: "Trading fees charged on perp trades", }, }; const adapter: SimpleAdapter = { version: 1, chains: [CHAIN.OFF_CHAIN], fetch, start: "2026-03-27", methodology, breakdownMethodology, }; export default adapter; ================================================ FILE: dexs/bullet-perp/index.ts ================================================ import { CHAIN } from "../../helpers/chains"; import { httpGet } from "../../utils/fetchURL"; import { SimpleAdapter } from "../../adapters/types"; const BASE_URL = "https://tradingapi.bullet.xyz"; async function fetch(_: any) { const [exchangeInfo, tickers] = await Promise.all([ httpGet(`${BASE_URL}/fapi/v1/exchangeInfo`), httpGet(`${BASE_URL}/fapi/v1/ticker/24hr`), ]); const perpSymbols = new Set( exchangeInfo.symbols .filter((s: any) => s.contractType === "Perp") .map((s: any) => s.symbol) ); const dailyVolume = tickers .filter((ticker: any) => perpSymbols.has(ticker.symbol)) .reduce((sum: number, ticker: any) => { const vol = Number(ticker.quoteVolume); if (!Number.isFinite(vol)) throw new Error(`Invalid quoteVolume for symbol: ${ticker.symbol}`); return sum + vol; }, 0); return { dailyVolume }; } const adapter: SimpleAdapter = { version: 2, fetch, chains: [CHAIN.SOLANA], runAtCurrTime: true, start: "2026-02-12", } export default adapter; ================================================ FILE: dexs/bunni-v2.ts ================================================ import * as sdk from "@defillama/sdk"; import { CHAIN } from "../helpers/chains"; import { request, } from "graphql-request"; import type { FetchOptions, SimpleAdapter } from "../adapters/types"; const endpoints: any = { [CHAIN.ETHEREUM]: sdk.graph.modifyEndpoint('5NFnHtgpdzB3JhVyiKQgnV9dZsewqJtX5HZfAT9Kg66r'), [CHAIN.ARBITRUM]: sdk.graph.modifyEndpoint('96tZMr51QupqWYamom12Yki5AqCJEiHWbVUpzUpvu9oB'), [CHAIN.BASE]: sdk.graph.modifyEndpoint('3oawHiCt7L9wJTEY9DynwAEmoThy8bvRhuMZdaaAooqW'), [CHAIN.UNICHAIN]: sdk.graph.modifyEndpoint('J22JEPtqL847G44v7E5gTsxmNosoLtKQUDAvnhRhzj25'), [CHAIN.BSC]: sdk.graph.modifyEndpoint('FfnRstqDWGGevsbf9rRg1vNctrb38Hd791zzaaKc7AGz'), }; const fetch = async (timestamp: number, _: any, { chain }: FetchOptions) => { const endpoint = endpoints[chain] const graphQuery = `{ protocolDaySnapshots (first:1000, orderBy: periodEnd, orderDirection: desc) { id volumeUSD periodStart periodEnd totalValueLockedUSD swapFeesUSD hookFeesUSD } }`; const { protocolDaySnapshots } = await request(endpoint, graphQuery); const snapshot = protocolDaySnapshots.find((snapshot: any) => +snapshot.periodStart <= timestamp && +snapshot.periodEnd >= timestamp); if (!snapshot) return { dailyVolume: 0, dailyFees: 0, } return { dailyVolume: snapshot.volumeUSD, dailyFees: +snapshot.swapFeesUSD + +snapshot.hookFeesUSD, } }; const adapter: SimpleAdapter = { doublecounted: true, fetch, chains: Object.keys(endpoints), methodology: { Fees: 'Swap and hook fees paid by users.', } }; export default adapter; ================================================ FILE: dexs/byreal/index.ts ================================================ import { FetchResultV2, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from '../../helpers/chains'; import { httpGet } from "../../utils/fetchURL" import { Agent } from "https" const agent = new Agent({ family: 4 }); const fetch = async (): Promise => { const response = await httpGet(`https://api2.byreal.io/byreal/api/dex/v2/overview/global`, { httpsAgent: agent }) const data = response.result.data return { dailyVolume: data.volumeUsd24h, dailyFees: data.feeUsd24h, dailyUserFees: data.feeUsd24h, dailyRevenue: data.feeUsd24h * 0.12, // 12% dailyProtocolRevenue: data.feeUsd24h * 0.12, // 12% Treasury dailySupplySideRevenue: data.feeUsd24h * 0.88, // 88% }; }; const adapter: SimpleAdapter = { adapter: { [CHAIN.SOLANA]: { fetch: fetch, runAtCurrTime: true, start: '2025-06-27', }, }, methodology: { Volume: 'Total token swap volumes retrieved from Byreal API.', Fees: 'All fees from token swaps.', UserFees: 'Users pay fees on every token swap.', Revenue: 'Amount of 12% swap fees to Byreal treasury.', ProtocolRevenue: 'Amount of 12% swap fees to Byreal treasury.', SupplySideRevenue: 'Amount of 88% swap fees distributed to LPs.', } }; export default adapter; ================================================ FILE: dexs/c3-exchange/index.ts ================================================ import { Adapter, BaseAdapter, FetchOptions, FetchResultV2, FetchV2, } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; const barsEndpoint = "https://api.c3.io/v1/markets/{id}/bars"; const ONE_DAY_IN_MILISECONDS = 60 * 60 * 24 * 1000; const HALF_DAY_IN_MILISECONDS = ONE_DAY_IN_MILISECONDS / 2; const marketsOfChains = { [CHAIN.ALGORAND]: ["ALGO-USDC"], [CHAIN.AVAX]: ["AVAX-USDC"], [CHAIN.BITCOIN]: ["WBTC-USDC"], [CHAIN.ETHEREUM]: ["ETH-USDC"], [CHAIN.ARBITRUM]: ["ARB-USDC"], [CHAIN.BSC]: ["BNB-USDC"], [CHAIN.SOLANA]: ["SOL-USDC", "PYTH-USDC", "W-USDC"], }; async function fetchVolume({ chain, startOfDay, }: FetchOptions): Promise { const markets = marketsOfChains[chain]; const from = Math.floor(startOfDay) * 1000 - HALF_DAY_IN_MILISECONDS; const to = Math.floor(startOfDay) * 1000 + HALF_DAY_IN_MILISECONDS; const barsPromises = markets.map((market) => { const endpoint = barsEndpoint.replace("{id}", market); const url = `${endpoint}?from=${from}&to=${to}&granularity=1D`; return fetchURL(url); }); const volume24h = (await Promise.all(barsPromises)).reduce((acc, bars) => { const last = bars[bars.length - 1]; const quoteVolume = last?.quoteVolume ?? 0; return acc + +quoteVolume; }, 0); return { dailyVolume: Math.round(volume24h), timestamp: startOfDay, }; } function adapterConstructor( fetchVolumeFunc: FetchV2, chains: string[] ): Adapter { const chainVolumes: BaseAdapter = chains.reduce( (obj, chain) => ({ ...obj, [chain]: { fetch: fetchVolumeFunc, start: '2023-07-01', // 1st July 2023, 00:00:00 GMT // runAtCurrTime: false, }, }), {} ); return { methodology: { Volume: "Volume is calculated by summing the quote token volume of all trades settled on the protocol that day.", }, version: 2, adapter: chainVolumes, }; } const adapter: Adapter = adapterConstructor( fetchVolume, Object.keys(marketsOfChains) ); export default adapter; ================================================ FILE: dexs/cables/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const address: any = { [CHAIN.ARBITRUM]: "0xfA12DCB2e1FD72bD92E8255Db6A781b2c76adC20", [CHAIN.AVAX]: "0xfA12DCB2e1FD72bD92E8255Db6A781b2c76adC20" } const event = "event SwapExecuted(uint256 indexed nonceAndMeta,address taker,address destTrader,uint256 destChainId,address srcAsset,address destAsset,uint256 srcAmount,uint256 destAmount)" const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const logs = await options.getLogs({ target: address[options.chain], eventAbi: event }) logs.forEach(log => { dailyVolume.add(log.destAsset, log.destAmount) }) return { dailyVolume } }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.ARBITRUM]: { fetch: fetch, start: '2024-09-30', }, [CHAIN.AVAX]: { fetch: fetch, start: '2024-09-30', }, }, }; export default adapter; ================================================ FILE: dexs/camelot-v3/index.ts ================================================ import { FetchOptions, SimpleAdapter } from '../../adapters/types'; import { CHAIN } from '../../helpers/chains'; import { getUniV3LogAdapter } from '../../helpers/uniswap'; // Camelot V3 uses Algebra (Uniswap V3-style concentrated liquidity) // Fees are pool-specific and read on-chain from the Algebra pool configuration // Fee distribution (V3): // - ~80% to Liquidity Providers // - ~20% to protocol-controlled revenue (xGRAIL + treasury) // Source: https://docs.camelot.exchange/tokenomics/protocol-earnings // Architecture: https://docs.camelot.exchange/protocol/amm-v3 const methodology = { Fees: 'Trading fees charged on swaps. Camelot V3 uses Algebra with dynamic fees.', UserFees: 'Users pay dynamic fees on each swap (typically 0.05% to 1%).', Revenue: 'Portion of trading fees that goes to the protocol (3%) and xGRAIL holders (17%), totaling 20% of swap fees.', ProtocolRevenue: '3% of trading fees go to the protocol.', HoldersRevenue: '17% of trading fees go to xGRAIL holders via Real Yield Staking.', SupplySideRevenue: '80% of trading fees go to liquidity providers.', }; const breakdownMethodology = { UserFees: { 'Trading fees': 'Dynamic fees paid by users on each swap, typically ranging from 0.05% to 1% of trade volume depending on market conditions', }, Fees: { 'Trading fees': 'Total trading fees collected from all swaps on Camelot V3 pools using Algebra\'s dynamic fee model', }, Revenue: { 'Protocol fees': 'Combined protocol-controlled revenue (20% of trading fees) split between protocol treasury (3%) and xGRAIL holders (17%)', }, ProtocolRevenue: { 'Protocol fees': 'Portion of trading fees allocated to the protocol treasury, equal to 3% of total swap fees', }, HoldersRevenue: { 'Tokenholder fees': 'Portion of trading fees distributed to xGRAIL holders through Real Yield Staking, equal to 17% of total swap fees', }, SupplySideRevenue: { 'LP fees': 'Portion of trading fees distributed to liquidity providers who supply capital to the pools, equal to 80% of total swap fees', }, }; // Fee split ratios const REVENUE_RATIO = 0.2; // 20% total protocol-controlled const USER_FEES_RATIO = 1; // Users pay 100% of fees const PROTOCOL_REVENUE_RATIO = 0.03; // 3% protocol const HOLDERS_REVENUE_RATIO = 0.17; // 17% xGRAIL holders const adapterConfig = { userFeesRatio: USER_FEES_RATIO, revenueRatio: REVENUE_RATIO, protocolRevenueRatio: PROTOCOL_REVENUE_RATIO, holdersRevenueRatio: HOLDERS_REVENUE_RATIO, isAlgebraV3: true, }; const adapter: SimpleAdapter = { version: 2, methodology, breakdownMethodology, adapter: { [CHAIN.APECHAIN]: { fetch: getUniV3LogAdapter({ factory: '0x10aA510d94E094Bd643677bd2964c3EE085Daffc', ...adapterConfig, }), start: '2024-10-15', }, [CHAIN.ARBITRUM]: { fetch: async (options: FetchOptions) => { // Arbitrum has two factories that need to be combined const adapter1 = getUniV3LogAdapter({ factory: '0x1a3c9B1d2F0529D97f2afC5136Cc23e58f1FD35B', ...adapterConfig, blacklistPools: [ '0xf3527ef8de265eaa3716fb312c12847bfba66cef', '0x7788a3538c5fc7f9c7c8a74eac4c898fc8d87d92', '0x8467f85a834159c26227b21f9898ca0fa606eaa8', ], }); const adapter2 = getUniV3LogAdapter({ factory: '0xd490f2f6990c0291597fd1247651b4e0dcf684dd', ...adapterConfig, }); const [res1, res2] = await Promise.all([ adapter1(options), adapter2(options), ]); // Combine results from both factories if (res2.dailyFees) res1.dailyFees.addBalances(res2.dailyFees); if (res2.dailyVolume) res1.dailyVolume.addBalances(res2.dailyVolume); if (res2.dailyRevenue) res1.dailyRevenue.addBalances(res2.dailyRevenue); if (res2.dailyProtocolRevenue) res1.dailyProtocolRevenue.addBalances(res2.dailyProtocolRevenue); if (res2.dailyHoldersRevenue) res1.dailyHoldersRevenue.addBalances(res2.dailyHoldersRevenue); if (res2.dailySupplySideRevenue) res1.dailySupplySideRevenue.addBalances(res2.dailySupplySideRevenue); if (res2.dailyUserFees) res1.dailyUserFees.addBalances(res2.dailyUserFees); return res1; }, start: '2023-03-31', }, [CHAIN.GRAVITY]: { fetch: getUniV3LogAdapter({ factory: '0x10aA510d94E094Bd643677bd2964c3EE085Daffc', ...adapterConfig, }), start: '2024-07-04', }, [CHAIN.RARI]: { fetch: getUniV3LogAdapter({ factory: '0xcF8d0723e69c6215523253a190eB9Bc3f68E0FFa', ...adapterConfig, }), start: '2024-06-05', }, [CHAIN.REYA]: { fetch: getUniV3LogAdapter({ factory: '0x10aA510d94E094Bd643677bd2964c3EE085Daffc', ...adapterConfig, }), start: '2024-06-20', }, // [CHAIN.SANKO]: { // fetch: getUniV3LogAdapter({ // factory: '0xcF8d0723e69c6215523253a190eB9Bc3f68E0FFa', // ...adapterConfig, // }), // start: '2024-04-17', // }, }, }; export default adapter; ================================================ FILE: dexs/canonic/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const USDM = '0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7' const MAOBS = [ { address: '0xaD7e5CBfB535ceC8d2E58Dca17b11d9bA76f555E', base: '0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072', quote: USDM }, // BTC.b / USDm { address: '0x23469683e25b780DFDC11410a8e83c923caDF125', base: '0x4200000000000000000000000000000000000006', quote: USDM }, // WETH / USDm { address: '0xDf1576c3C82C9f8B759C69f4cF256061C6Fe1f9e', base: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', quote: USDM }, // USDT0 / USDm { address: '0x20C7B6B34bB8B8efb46828cF9383BFf8b7856E46', base: '0x28B7E77f82B25B95953825F1E3eA0E36c1c29861', quote: USDM }, // MEGA / USDm ] const EVENT_ABI = 'event RungFilled(address indexed taker, bool indexed isBuy, uint16 indexed rung, uint256 baseAmount, uint256 quoteAmount, uint256 priceE18)' const FEE_DENOM = 1_000_000 const fetch = async (options: FetchOptions) => { const dailyVolume = options.createBalances(); const dailyFees = options.createBalances(); const rungFilledLogs = await options.getLogs({ targets: MAOBS.map(m => m.address), eventAbi: EVENT_ABI, flatten: false }); const takerFees = await options.api.multiCall({ calls: MAOBS.map(m => ({ target: m.address })), abi: 'uint32:takerFee' }); for (const [index, market] of MAOBS.entries()) { const logs = rungFilledLogs[index]; const takerFee = takerFees[index]; for (const log of logs) { dailyVolume.add(USDM, log.quoteAmount); if (log.isBuy) { const amount = Number(log.baseAmount) const fee = amount * takerFee / FEE_DENOM dailyFees.add(market.base, fee) } else { const amount = Number(log.quoteAmount) const fee = amount * takerFee / FEE_DENOM dailyFees.add(market.quote, fee) } } } return { dailyVolume, dailyFees, dailyUserFees: dailyFees, dailyRevenue: dailyFees, dailyProtocolRevenue: dailyFees, dailySupplySideRevenue: 0, } } const methodology = { Fees: 'Taker fees charged on every trade. Buy orders pay fees in the base token, sell orders pay in the quote token.', UserFees: 'Same as Fees — all fees are paid by takers.', Revenue: '100% of taker fees are sent to the protocol fee collector.', ProtocolRevenue: 'All collected fees go to the protocol treasury.', SupplySideRevenue: 'CLP vault LPs earn from market-making spread, not from protocol fees.', } const adapter: SimpleAdapter = { version: 2, pullHourly: true, fetch, methodology, start: '2026-02-06', chains: [CHAIN.MEGAETH], } export default adapter ================================================ FILE: dexs/cap-finance-v4.ts ================================================ import { Address } from '@defillama/sdk/build/types'; import { FetchOptions, SimpleAdapter } from '../adapters/types'; import { CHAIN } from '../helpers/chains'; const config: Record = { [CHAIN.ARBITRUM]: { trades: [ '0xbE4A45BDdFC9e0647FbA313a2bD96B6De8B65C15', '0x26396Ffd65e2d89Ce853CC4076Df20272Fc69E5A', '0x08b1d6fE01660911b939e9c896Ab53aBa231F101', ], }, }; const abis = { positionIncreased: 'event PositionIncreased(uint256 indexed orderId, address indexed user, string market, bool isLong, uint256 size, uint256 margin, uint256 price, uint256 positionMargin, uint256 positionSize, uint256 positionPrice, int256 fundingTracker, uint256 fee, uint256 keeperFee)', positionDecreased: 'event PositionDecreased(uint256 indexed orderId, address indexed user, string market, bool isLong, uint256 size, uint256 margin, uint256 price, uint256 positionMargin, uint256 positionSize, uint256 positionPrice, int256 fundingTracker, uint256 fee, uint256 keeperFee, int256 pnl, int256 fundingFee)', }; const fetch = async (options: FetchOptions) => { const chainConfig = config[options.chain]; const dailyVolume = options.createBalances(); const allLogs = await Promise.all( chainConfig.trades.flatMap((tradeContract: Address) => [ options.getLogs({ target: tradeContract, eventAbi: abis.positionIncreased, }), options.getLogs({ target: tradeContract, eventAbi: abis.positionDecreased, }), ]) ); for (const logs of allLogs) { for (const log of logs) { const sizeUsd = Number(log.size.toString()) / 1e8; dailyVolume.addUSDValue(sizeUsd); } } return { dailyVolume, }; }; const methodology = { Volume: 'Daily volume represents the total USD value traded.', }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, adapter: { [CHAIN.ARBITRUM]: { fetch, start: '2023-01-14', }, }, methodology, }; export default adapter; ================================================ FILE: dexs/capybara-exchange/index.ts ================================================ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { addOneToken } from "../../helpers/prices"; // ─── Kaia mainnet addresses ──────────────────────────────────────────────────── /** Wombat single-sided AMM pools (HighCovRatioFeePool style) */ const WOMBAT_POOLS = [ "0x6389dBfa1427a3b0a89cDdc7eA9BBda6E73dECE7", // Main Pool (Wormhole) "0x540cce8Ed7d210f71EEAbb9e7Ed7698AC745e077", // Stable Pool (Wormhole) "0x5CDE63386D78362267d9A3edC8DA204bB64D07D3", // LST Pool "0x4b63eC6284810f62CecBa6F03CF17413b0f4cEc3", // KRWO Pool "0x005A8ED563E802B05E5D59df98f8A6548c14A4d7", // LRT Pool "0x1dE1578476d9B4237F963eca5D37500Fc33DF3D1", // Main Pool (Stargate) "0x2c0537f3360838B50Ab90cB8cD78beAb8Fc1590C", // Stable Pool (Stargate) "0x872E7e7422bcAcdcb37f7FffB0cfe3f2F0D6C546", // Superwalk Pool ]; // ─── Event ABIs const WOMBAT_SWAP_V2 = "event SwapV2(address indexed sender, address fromToken, address toToken, uint256 fromAmount, uint256 toAmount, uint256 toTokenFee, address indexed to)"; // ─── Fetch ───────────────────────────────────────────────────────────────────── const fetch = async (options: FetchOptions) => { const { createBalances, getLogs, chain } = options; const dailyVolume = createBalances(); const dailyFees = createBalances(); const dailyRevenue = createBalances(); const dailySupplySideRevenue = createBalances(); // Wombat single-sided AMM pools const wombatLogs = await getLogs({ targets: WOMBAT_POOLS, eventAbi: WOMBAT_SWAP_V2 }); for (const log of wombatLogs) { const { fromToken, toToken, fromAmount, toAmount, toTokenFee } = log; addOneToken({ chain, balances: dailyVolume, token0: fromToken, amount0: fromAmount, token1: toToken, amount1: toAmount }); // toTokenFee is the exact haircut amount denominated in toToken, emitted by the contract dailyFees.add(toToken, toTokenFee); // All Wombat pool fees go to LPs (supply side) — no protocol revenue dailySupplySideRevenue.add(toToken, toTokenFee); } return { dailyVolume, dailyFees, dailyRevenue, dailySupplySideRevenue }; }; const methodology = { Volume: "Notional volume from Wombat single-sided AMM pools (V2 and V3 AMM tracked separately via factory configs)", Fees: "Wombat pools: 4 bps haircut on each swap", Revenue: "No protocol revenue from Wombat pools", SupplySideRevenue: "All Wombat pool fees (4 bps) go to liquidity providers", }; const adapter: SimpleAdapter = { version: 2, pullHourly: true, methodology, adapter: { [CHAIN.KLAYTN]: { fetch, start: "2024-05-15", }, }, }; export default adapter; ================================================ FILE: dexs/capybara-perp/index.ts ================================================ import request, { gql } from 'graphql-request'; import { FetchOptions, SimpleAdapter } from '../../adapters/types'; import { CHAIN } from '../../helpers/chains'; const ENDPOINTS: { [key: string]: string } = { [CHAIN.KLAYTN]: 'https://perp.capybara.exchange/api/subgraph?chainId=8217', }; const getVolumeAndFee = gql` query QueryChartAccumulativeData($dayAgo: BigInt!) { marketHourDatas(startTime_gt: $dayAgo, orderBy: startTime, orderDirection: desc) { startTime totalFee tradeVolume } } `; const fetch = async (options: FetchOptions) => { const dailyFees = options.createBalances(); const dailyVolume = options.createBalances(); const { startTimestamp, endTimestamp } = options; const { marketHourDatas } = await request(ENDPOINTS[options.chain], getVolumeAndFee, { dayAgo: String(startTimestamp), }); const { fees, volume } = marketHourDatas.filter((data: any) => data.startTime >= startTimestamp && data.startTime < endTimestamp).reduce((acc: { fees: number, volume: number }, curr: any) => { acc.fees += +curr.totalFee / 1e18; acc.volume += +curr.tradeVolume / 1e18; return acc; }, { fees: 0, volume: 0 }); dailyFees.addCGToken("lair-staked-kaia", fees); dailyVolume.addCGToken("lair-staked-kaia", volume); return { dailyVolume, dailyFees, // Fees gets divided among Protcol and supply side but exact ratio couldn't be found } }; const methodology = { Fees: "Trading fees paid by users", Volume: "Notional volume of all trades in the protocol, includes leverage", } const adapter: SimpleAdapter = { version: 2, chains: [CHAIN.KLAYTN], fetch, start: '2024-09-29', methodology, deadFrom: '2026-02-04', }; export default adapter; ================================================ FILE: dexs/carbon/index.ts ================================================ import { FetchOptions, FetchResult, SimpleAdapter, } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import fetchURL from "../../utils/fetchURL"; async function fetch(_a: any, _b: any, options: FetchOptions): Promise { const formatDate = () => { const todayInUtc = new Date(options.startOfDay * 1000).toUTCString(); const parts = todayInUtc.split(' '); return `${parts[0].replace(',', '')} ${parts[2]} ${parts[1]} ${parts[3]} 00:00:00 GMT+0000 (Coordinated Universal Time)` } const dailyFees = options.createBalances(); const dailyVolume = options.createBalances(); const openInterestAtEnd = options.createBalances(); const response = await fetchURL("https://app.carbon.inc/analytics"); const analyticsData = response.match( /