├── .github └── workflows │ ├── check-urls.yml │ ├── coins.yml │ └── defi.yml ├── .gitignore ├── .gitmodules ├── coins ├── .gitignore ├── README.md ├── coins2.ts ├── env.js ├── jest.config.js ├── package-lock.json ├── package.json ├── resources ├── resources2 │ └── api-cloudfront-distribution.yml ├── serverless.yml ├── src │ ├── __mocks__ │ ├── adapters │ │ ├── bridges │ │ │ ├── anyswap.ts │ │ │ ├── aptosFa.ts │ │ │ ├── arbitrum.ts │ │ │ ├── arbitrum_nova.ts │ │ │ ├── astrzk.ts │ │ │ ├── avax.ts │ │ │ ├── axelar.ts │ │ │ ├── base.ts │ │ │ ├── brc20.ts │ │ │ ├── broken │ │ │ │ └── ported.ts │ │ │ ├── bsc.ts │ │ │ ├── celer.ts │ │ │ ├── cosmos.ts │ │ │ ├── era.ts │ │ │ ├── fantom.ts │ │ │ ├── flow.ts │ │ │ ├── fraxtal.ts │ │ │ ├── fuel.ts │ │ │ ├── gasTokens.ts │ │ │ ├── harmony.ts │ │ │ ├── hop.ts │ │ │ ├── index.test.ts │ │ │ ├── index.ts │ │ │ ├── layerzero.ts │ │ │ ├── layerzeroOFTs.ts │ │ │ ├── linea.ts │ │ │ ├── manta.ts │ │ │ ├── mantle.ts │ │ │ ├── morph.ts │ │ │ ├── neon_evm.ts │ │ │ ├── optimism.ts │ │ │ ├── overwrites.ts │ │ │ ├── polygon.ts │ │ │ ├── polygon_zkevm.ts │ │ │ ├── scroll.ts │ │ │ ├── solana.ts │ │ │ ├── sophon.ts │ │ │ ├── symbiosis.ts │ │ │ ├── synapse.ts │ │ │ ├── unichain.ts │ │ │ ├── xdai.ts │ │ │ ├── zircuit.ts │ │ │ └── zklink.ts │ │ ├── ethers.ts │ │ ├── index.ts │ │ ├── liquidStaking │ │ │ ├── ankr │ │ │ │ ├── ankr.ts │ │ │ │ └── index.ts │ │ │ ├── ifil │ │ │ │ └── index.ts │ │ │ ├── pxeth │ │ │ │ ├── abi.json │ │ │ │ ├── index.ts │ │ │ │ └── pxeth.ts │ │ │ ├── sthapt │ │ │ │ └── index.ts │ │ │ └── xailocker │ │ │ │ ├── abi.json │ │ │ │ ├── index.ts │ │ │ │ └── xailocker.ts │ │ ├── markets │ │ │ ├── 0xequity │ │ │ │ ├── index.ts │ │ │ │ └── xequity.ts │ │ │ ├── aftermath.ts │ │ │ ├── aktionariat │ │ │ │ ├── aktionariat.ts │ │ │ │ └── index.ts │ │ │ ├── alex.ts │ │ │ ├── arrakis │ │ │ │ ├── arrakis.ts │ │ │ │ └── index.ts │ │ │ ├── balanced.ts │ │ │ ├── balancer │ │ │ │ ├── abi.json │ │ │ │ ├── balancer.ts │ │ │ │ ├── balancerV2.ts │ │ │ │ ├── balancerV3.ts │ │ │ │ ├── index.ts │ │ │ │ └── linearPools.ts │ │ │ ├── bitcow.ts │ │ │ ├── cetus.ts │ │ │ ├── crosscurve │ │ │ │ └── index.ts │ │ │ ├── curve │ │ │ │ ├── abi.json │ │ │ │ ├── contracts.json │ │ │ │ ├── curve2.ts │ │ │ │ ├── gauges.ts │ │ │ │ └── index.ts │ │ │ ├── elexium.ts │ │ │ ├── ergopad.ts │ │ │ ├── graphCoins.ts │ │ │ ├── hop │ │ │ │ ├── abi.json │ │ │ │ ├── addresses.json │ │ │ │ ├── hop.ts │ │ │ │ └── index.ts │ │ │ ├── jarvis │ │ │ │ ├── index.ts │ │ │ │ └── jarvis.ts │ │ │ ├── kodiak.ts │ │ │ ├── maverick │ │ │ │ ├── abi.json │ │ │ │ ├── contracts.json │ │ │ │ └── index.ts │ │ │ ├── minswap.ts │ │ │ ├── minswap2.ts │ │ │ ├── momentum.ts │ │ │ ├── ociswap.ts │ │ │ ├── pancakeStable.ts │ │ │ ├── parallelProtocol │ │ │ │ ├── index.ts │ │ │ │ └── parallelProtocol.ts │ │ │ ├── phux │ │ │ │ ├── abi.json │ │ │ │ ├── index.ts │ │ │ │ └── phux.ts │ │ │ ├── platypus │ │ │ │ ├── abi.json │ │ │ │ ├── index.ts │ │ │ │ └── platypus.ts │ │ │ ├── radix.ts │ │ │ ├── samm.ts │ │ │ ├── stargate │ │ │ │ ├── abi.json │ │ │ │ ├── contracts.json │ │ │ │ ├── index.ts │ │ │ │ └── stargate.ts │ │ │ ├── steer │ │ │ │ ├── index.ts │ │ │ │ └── steer.ts │ │ │ ├── ston.ts │ │ │ ├── sundaeswap.ts │ │ │ ├── sundaeswapv3.ts │ │ │ ├── tangleswap.ts │ │ │ ├── thala │ │ │ │ └── index.ts │ │ │ ├── thena.ts │ │ │ ├── tinyman.ts │ │ │ ├── todo.md │ │ │ ├── uniswap │ │ │ │ ├── abi.json │ │ │ │ ├── extraLp.ts │ │ │ │ ├── index.ts │ │ │ │ ├── uniswap.ts │ │ │ │ └── v3.ts │ │ │ ├── wingriders.ts │ │ │ ├── wombat │ │ │ │ ├── abi.json │ │ │ │ ├── index.ts │ │ │ │ ├── wombat.ts │ │ │ │ └── wombatWrapped.ts │ │ │ ├── xexchange.ts │ │ │ └── xlpt.ts │ │ ├── moneyMarkets │ │ │ ├── aave-debt │ │ │ │ ├── aaveDebt.ts │ │ │ │ └── index.ts │ │ │ ├── aave │ │ │ │ ├── aave.ts │ │ │ │ ├── abi.json │ │ │ │ └── index.ts │ │ │ ├── aries.ts │ │ │ ├── compound │ │ │ │ ├── abi.json │ │ │ │ ├── compound.ts │ │ │ │ └── index.ts │ │ │ ├── dforce.ts │ │ │ ├── euler │ │ │ │ ├── abi.json │ │ │ │ ├── euler.ts │ │ │ │ ├── eulerV2.ts │ │ │ │ ├── index.ts │ │ │ │ └── vault.abi.json │ │ │ ├── folks-finance │ │ │ │ ├── folks-finance.ts │ │ │ │ └── index.ts │ │ │ └── silo.ts │ │ ├── nft │ │ │ ├── chainlink │ │ │ │ ├── chainlink.ts │ │ │ │ ├── index.ts │ │ │ │ ├── priceFeeds.ts │ │ │ │ └── priceFeeds_jpegd.ts │ │ │ └── reservoir │ │ │ │ └── index.ts │ │ ├── oracles │ │ │ ├── pragma.ts │ │ │ ├── pyth.ts │ │ │ └── pythAggregatorV3.ts │ │ ├── other │ │ │ ├── abi.json │ │ │ ├── abracadabra.ts │ │ │ ├── collateralizedAssets.ts │ │ │ ├── defichain.ts │ │ │ ├── distressed.ts │ │ │ ├── distressedAssets.ts │ │ │ ├── few.ts │ │ │ ├── fraxtalGas.ts │ │ │ ├── glp.ts │ │ │ ├── gmd.ts │ │ │ ├── gmdV2.ts │ │ │ ├── gmxV2.ts │ │ │ ├── index.ts │ │ │ ├── kSTRK.ts │ │ │ ├── liquity.ts │ │ │ ├── manualInput.ts │ │ │ ├── metronome.ts │ │ │ ├── mooBvmEth.ts │ │ │ ├── nstSTRK.ts │ │ │ ├── odpxWethLP.ts │ │ │ ├── opal.ts │ │ │ ├── optimBonds.ts │ │ │ ├── others2.ts │ │ │ ├── pods.ts │ │ │ ├── realt.ts │ │ │ ├── sbtc.ts │ │ │ ├── seamless.ts │ │ │ ├── shlb.ts │ │ │ ├── steadefi_eth.ts │ │ │ ├── steadefi_usdc_arb.ts │ │ │ ├── steadefi_usdc_eth.ts │ │ │ ├── steadefi_usdc_link.ts │ │ │ ├── steadefi_usdc_wbtc.ts │ │ │ ├── steadefi_wbtc.ts │ │ │ ├── stkaurabal.ts │ │ │ ├── sweth.ts │ │ │ ├── synthetix.ts │ │ │ ├── teahouse.ts │ │ │ ├── ton.ts │ │ │ ├── unknownToken.ts │ │ │ ├── unknownTokensV3.ts │ │ │ ├── usdrif.ts │ │ │ ├── velgd.ts │ │ │ ├── warlord.ts │ │ │ ├── wcgUSD.ts │ │ │ └── zarban.ts │ │ ├── readme.md │ │ ├── rwa │ │ │ ├── abi.json │ │ │ ├── asseto.ts │ │ │ ├── backed.ts │ │ │ ├── cyclex.ts │ │ │ ├── digift.ts │ │ │ ├── dinari.ts │ │ │ ├── fortunafi.ts │ │ │ ├── hashnote.ts │ │ │ ├── hiyield.ts │ │ │ ├── kuma.ts │ │ │ ├── midas.ts │ │ │ ├── ondo.ts │ │ │ ├── pareto.ts │ │ │ ├── reservoir-protocol.ts │ │ │ ├── stobox │ │ │ │ └── index.ts │ │ │ ├── t-rize.ts │ │ │ ├── thepac.ts │ │ │ └── xu3o8.ts │ │ ├── solana │ │ │ ├── jtoDerivs.ts │ │ │ ├── jupAg.ts │ │ │ ├── kamino.ts │ │ │ ├── pst.ts │ │ │ ├── saber │ │ │ │ └── index.ts │ │ │ ├── sanctum.ts │ │ │ ├── solend │ │ │ │ └── index.ts │ │ │ ├── util │ │ │ │ ├── lavarage.ts │ │ │ │ └── tokenMetadata.ts │ │ │ └── utils.ts │ │ ├── tezos │ │ │ ├── index.ts │ │ │ └── tezos.ts │ │ ├── tokenMapping.json │ │ ├── tokenMapping_added.json │ │ ├── utils.ts │ │ ├── utils │ │ │ ├── block.ts │ │ │ ├── compound-fork.ts │ │ │ ├── database.ts │ │ │ ├── dbInterfaces.ts │ │ │ ├── erc20.ts │ │ │ ├── erc4626.ts │ │ │ ├── gasTokens.ts │ │ │ ├── getWrites.ts │ │ │ ├── rpcProxy.js │ │ │ ├── sdk.ts │ │ │ ├── sdkInterfaces.ts │ │ │ ├── starknet.ts │ │ │ ├── sui.ts │ │ │ ├── uniV2.ts │ │ │ ├── updateTokenMapping.js │ │ │ └── yieldTokens.ts │ │ └── yield │ │ │ ├── alchemix │ │ │ ├── abi.json │ │ │ ├── alchemix.ts │ │ │ └── index.ts │ │ │ ├── ambit-finance │ │ │ └── index.ts │ │ │ ├── apiDerivs.ts │ │ │ ├── balancer4626.ts │ │ │ ├── beefy │ │ │ ├── beefy.ts │ │ │ └── index.ts │ │ │ ├── chai.ts │ │ │ ├── concentrator │ │ │ ├── abi.json │ │ │ ├── concentrator.ts │ │ │ └── index.ts │ │ │ ├── convex │ │ │ ├── abi.json │ │ │ ├── convex.ts │ │ │ └── index.ts │ │ │ ├── convexStaked.ts │ │ │ ├── derivs.ts │ │ │ ├── eigenpie.ts │ │ │ ├── etherfi.ts │ │ │ ├── fx-protocol │ │ │ ├── abi.json │ │ │ ├── fx-protocol.ts │ │ │ └── index.ts │ │ │ ├── fxsp.ts │ │ │ ├── gamma.ts │ │ │ ├── glpDerivs.ts │ │ │ ├── hlp.ts │ │ │ ├── indexCoop.ts │ │ │ ├── jeurx.ts │ │ │ ├── jpegd │ │ │ ├── abi.json │ │ │ └── index.ts │ │ │ ├── level-finance │ │ │ ├── index.ts │ │ │ └── levelFinance.ts │ │ │ ├── liquidly.ts │ │ │ ├── mean-finance │ │ │ ├── index.ts │ │ │ └── mean-finance.ts │ │ │ ├── misc4626 │ │ │ ├── index.ts │ │ │ ├── misc.ts │ │ │ ├── tokens.json │ │ │ └── tokensQiDAO.json │ │ │ ├── mux │ │ │ └── index.ts │ │ │ ├── ondo │ │ │ ├── index.ts │ │ │ └── ondo.ts │ │ │ ├── pendle │ │ │ ├── api.ts │ │ │ ├── index.ts │ │ │ ├── pendle.ts │ │ │ └── penpie.ts │ │ │ ├── quickperps │ │ │ ├── index.ts │ │ │ └── quickperps.ts │ │ │ ├── sandglass │ │ │ └── index.ts │ │ │ ├── spectra.ts │ │ │ ├── stakeDao │ │ │ └── index.ts │ │ │ ├── tempest │ │ │ ├── index.ts │ │ │ ├── rsweth.abi.json │ │ │ ├── symmetric.abi.json │ │ │ └── tempest.ts │ │ │ ├── timeless │ │ │ ├── index.ts │ │ │ └── timeless.ts │ │ │ ├── timeswap │ │ │ ├── index.ts │ │ │ └── timeswap.ts │ │ │ ├── vela │ │ │ ├── abi.json │ │ │ ├── contracts.json │ │ │ └── index.ts │ │ │ ├── vesper │ │ │ └── index.ts │ │ │ ├── yearn │ │ │ ├── abi.json │ │ │ ├── index.ts │ │ │ └── yearnV2.ts │ │ │ ├── yield-protocol │ │ │ ├── index.ts │ │ │ └── yield-protocol.ts │ │ │ └── yield-yak │ │ │ ├── index.ts │ │ │ └── yieldYak.ts │ ├── cli │ │ ├── checkWrongBlocks.ts │ │ ├── deleteLatestWritesFromAdapter.ts │ │ ├── deletePreviewCgCoins.ts │ │ ├── displayLatestItems.ts │ │ ├── importHistoricalPrices.ts │ │ ├── readItem.ts │ │ ├── refill.ts │ │ ├── refillAdapter.ts │ │ ├── staleMappings.ts │ │ ├── storeBridgedCoins.ts │ │ ├── test.ts │ │ ├── writeItem.ts │ │ └── writeOverwrites.ts │ ├── corsPreflight.ts │ ├── fallback.test.ts │ ├── fallback.ts │ ├── fetchCoinpaprikaData.ts │ ├── genesisBlockTimes.ts │ ├── getBatchHistoricalCoins.ts │ ├── getBatchHistoricalCoinsSpan.ts │ ├── getBlock.ts │ ├── getChains.ts │ ├── getCoinFirstTimestamp.ts │ ├── getCoinPriceChart.ts │ ├── getCoinPrices.ts │ ├── getCoins.test.ts │ ├── getCoins.ts │ ├── getCurrentCoins.ts │ ├── getHistoricalCoins.ts │ ├── getMcaps.ts │ ├── getPercentageChange.ts │ ├── getVolume.ts │ ├── listCoins.ts │ ├── scripts │ │ ├── bridges.ts │ │ ├── checkRpcBlocks.ts │ │ ├── coingecko.ts │ │ ├── coingecko2.ts │ │ ├── coingeckoUtils.ts │ │ ├── defiCoins.ts │ │ └── test.ts │ ├── storeBridgedCoins.ts │ ├── storeCoins.ts │ ├── test.ts │ ├── triggerFetchCoingeckoData.ts │ ├── updateCoin.ts │ └── utils │ │ ├── cache │ │ ├── getLogs.ts │ │ └── index.ts │ │ ├── coingeckoPlatforms.test.ts │ │ ├── coingeckoPlatforms.ts │ │ ├── coins3 │ │ ├── cli │ │ │ ├── consume.ts │ │ │ └── newTopic.ts │ │ ├── es.ts │ │ ├── jsonValidation.ts │ │ ├── kafka.ts │ │ ├── produce.ts │ │ ├── redis.ts │ │ └── utils.ts │ │ ├── date.ts │ │ ├── getCoinsUtils.ts │ │ ├── keys.ts │ │ ├── missingCoins.ts │ │ ├── processCoin.ts │ │ ├── r2.ts │ │ ├── shared │ │ ├── timestampUtils.ts │ │ └── ton.ts └── tsconfig.json ├── common └── chainToCoingeckoId.ts └── defi ├── .babelrc ├── .gitignore ├── .prettierrc ├── README.md ├── dev-metrics ├── config.js ├── db-scripts │ ├── postgres.sql │ ├── queries.js │ └── views.sql ├── db.js ├── env.js ├── index.js ├── package-lock.json ├── package.json ├── scripts │ ├── addArchives.js │ ├── addLogsToDB.sh │ ├── createMappingFromElectricRepo.js │ ├── downloadTomlFile.js │ ├── fixProjectReport.js │ ├── generateProjectReport.js │ ├── pullTwitterDataLocally.js │ ├── temp │ │ ├── bashLoop.sh │ │ ├── createChartData.js │ │ ├── dbCleanup.js │ │ ├── deleteOrgsAndRepos.js │ │ ├── readLargeFile.js │ │ ├── testDBConnection.js │ │ ├── testDBQuery.js │ │ ├── testInsertDataToDB.js │ │ ├── testReadAndProcessFromArchive.js │ │ ├── unzip.js │ │ └── writeToElastic.js │ ├── updateOrgAndRepoInfo.js │ └── updateTwitterData.js ├── updateDevMapping.ts └── utils │ ├── archive.js │ ├── cache.js │ ├── git.js │ ├── index.js │ ├── r2.js │ └── twitter.js ├── docker-compose.yml ├── env.js ├── jest.config.js ├── l2 ├── adapters │ ├── ada.ts │ ├── index.ts │ ├── manual.ts │ └── thirdParty.ts ├── cli │ ├── backfillAll.ts │ ├── backfillSingle.ts │ ├── chainNameChanged.ts │ ├── checkForDuplicates.ts │ ├── findGoodChains.ts │ ├── testCoinBreakdowns.ts │ └── testL2.ts ├── constants.ts ├── flows.ts ├── incoming.ts ├── index.ts ├── metadata.ts ├── native.ts ├── outgoing.ts ├── storeToDb.ts ├── test.ts ├── tvl.ts ├── types.ts └── utils.ts ├── package-lock.json ├── package.json ├── resources ├── api-cloudfront-distribution.yml ├── api-gateway-errors.yml └── dynamodb-table.yml ├── serverless.yml ├── src ├── __mocks__ │ └── @sentry │ │ ├── serverless.ts │ │ └── tracing.ts ├── __snapshots__ │ └── fallback.test.ts.snap ├── adaptors │ ├── cli │ │ ├── backfillUtilities │ │ │ ├── README.md │ │ │ ├── auto.ts │ │ │ ├── backfillFunction.ts │ │ │ ├── backfill_all.ts │ │ │ ├── dataset │ │ │ │ ├── pancake-v1.data │ │ │ │ ├── pancake-v1.ods │ │ │ │ ├── terra1_astroport_volume.csv │ │ │ │ └── terraswap_terra1.csv │ │ │ ├── executeAsyncBackfill.ts │ │ │ ├── getBackfillEvent.ts │ │ │ └── index.ts │ │ ├── checkNonEnabledDexs.ts │ │ ├── others │ │ │ ├── fixTimestamps.ts │ │ │ ├── getCSV.ts │ │ │ ├── removeAdaptorData.ts │ │ │ └── replaceAdaptorId.ts │ │ ├── runCachedRes.ts │ │ ├── runGetOverview.ts │ │ ├── runGetProtocolSummary.ts │ │ ├── runNotifyStatus.ts │ │ ├── runStoreDexVolume.ts │ │ ├── runTriggerStoreAdaptorData.ts │ │ └── setup.ts │ ├── data │ │ ├── aggregator-derivatives │ │ │ ├── config.ts │ │ │ └── index.ts │ │ ├── aggregators │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.ts.snap │ │ │ ├── config.ts │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── bridge-aggregators │ │ │ ├── config.ts │ │ │ └── index.ts │ │ ├── checkDuplicateIds.ts │ │ ├── configs.ts │ │ ├── derivatives │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.ts.snap │ │ │ ├── config.ts │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── dexs │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.ts.snap │ │ │ ├── config.ts │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── fees │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.ts.snap │ │ │ ├── config.ts │ │ │ ├── index.test.ts │ │ │ ├── index.ts │ │ │ └── rules.ts │ │ ├── helpers │ │ │ ├── categories.ts │ │ │ ├── generateProtocolAdaptorsList.ts │ │ │ └── methodology.ts │ │ ├── incentives │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.ts.snap │ │ │ ├── config.ts │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── options │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.ts.snap │ │ │ ├── config.ts │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── royalties │ │ │ ├── config.ts │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ └── types.ts │ ├── db-utils │ │ ├── AdapterRecord.ts │ │ ├── AdapterRecord2.ts │ │ ├── adaptor-record.test.ts │ │ ├── adaptor-record.ts │ │ ├── base.ts │ │ ├── collection-info.ts │ │ ├── db2.ts │ │ └── dynamo-reserved-keywords.ts │ ├── handlers │ │ ├── getOverview │ │ │ └── index.ts │ │ ├── getOverviewProcess │ │ │ └── index.ts │ │ ├── getProtocol │ │ │ └── index.ts │ │ ├── helpers │ │ │ ├── __snapshots__ │ │ │ │ └── generateCleanRecords.test.ts.snap │ │ │ ├── convertRecordDataCurrency.ts │ │ │ ├── generateCleanRecords.test.ts │ │ │ ├── generateCleanRecords.ts │ │ │ ├── generateProtocolAdaptorSummary.ts │ │ │ ├── getCachedReturnValue.ts │ │ │ └── processEventParameters.ts │ │ ├── notifyStatus.ts │ │ ├── refreshDimensionOverviewCache │ │ │ └── index.ts │ │ ├── storeAdaptorData │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ ├── refillScript.ts │ │ │ ├── scripts │ │ │ │ ├── findMissingBlockscoutChains.ts │ │ │ │ └── storeAllBlockscoutData.ts │ │ │ └── storeAll.ts │ │ ├── triggerNotificationAndBackfill.ts │ │ ├── triggerNotificationAndBackfill2.ts │ │ ├── triggerNotifyStatus.ts │ │ └── triggerStoreAdaptorData.ts │ ├── readme.md │ ├── utils.ts │ └── utils │ │ ├── canGetBlock.ts │ │ ├── getAllChainsFromAdaptors.ts │ │ ├── getDataPoints.ts │ │ ├── getDirectories.ts │ │ ├── handleErrors.ts │ │ ├── notify.ts │ │ ├── removeErrors.ts │ │ ├── storeR2Response │ │ └── index.ts │ │ └── volumeCalcs.ts ├── api-keys │ └── checkApiKey.ts ├── api2 │ ├── Dockerfile │ ├── cache │ │ ├── file-cache.ts │ │ └── index.ts │ ├── constants.ts │ ├── cron-task │ │ ├── appMetadata.ts │ │ ├── dimensions.ts │ │ ├── githubMetrics.ts │ │ ├── index.ts │ │ └── raises.ts │ ├── db │ │ ├── index.ts │ │ └── tables.ts │ ├── ecosystem.config.js │ ├── env.ts │ ├── index.ts │ ├── routes │ │ ├── dimensions.ts │ │ ├── index.ts │ │ ├── internalRoutes.ts │ │ └── utils.ts │ ├── scripts │ │ ├── _start.sh │ │ ├── build.sh │ │ ├── checkDevMetrics.ts │ │ ├── checkForDeadProtocols.ts │ │ ├── checkProtocolsMissingDimensions.ts │ │ ├── copyToPG.ts │ │ ├── dimensions │ │ │ ├── checkDimensions.ts │ │ │ ├── dimMigrationCustom.ts │ │ │ ├── dimensionVersionsStats.ts │ │ │ ├── dimensions-migration-part-1.ts │ │ │ ├── dimensions-migration-part-2.ts │ │ │ ├── fixNegativeValues.ts │ │ │ ├── fixProtocolDataTypeRecords.ts │ │ │ ├── fixUndefinedValue.ts │ │ │ ├── getProtocolDataTypeRecords.ts │ │ │ ├── listNegativeValues.ts │ │ │ ├── listUndefinedValues.ts │ │ │ ├── migrateBreakdownData.ts │ │ │ ├── printDimensionRunStats.js │ │ │ ├── renameIds.ts │ │ │ ├── testDimensionsPG.ts │ │ │ └── updateDimensionsData.ts │ │ ├── docker_prod_start.sh │ │ ├── prod_start.sh │ │ ├── rekt-rss │ │ │ ├── index.ts │ │ │ ├── package-lock.json │ │ │ └── package.json │ │ ├── test.ts │ │ ├── tmp │ │ │ ├── checkRefill.ts │ │ │ └── getHackHallmarkList.ts │ │ └── updateExtensionTwitterConfig.ts │ ├── tests │ │ ├── parentProtocol.test.ts │ │ ├── protocol.test.ts │ │ ├── treasury.test.ts │ │ └── utils.ts │ └── utils │ │ ├── cachedFunctions.ts │ │ ├── craftParentProtocolV2.ts │ │ ├── craftProtocolV2.ts │ │ ├── dimensionsUtils.ts │ │ ├── failOnError.ts │ │ ├── index.ts │ │ └── time.ts ├── cacheConfig.ts ├── cli │ ├── backfillEmissions.ts │ ├── buildCoingeckoSymbols.py │ ├── buildCoingeckoSymbols.ts │ ├── buildRequires.ts │ ├── buildTvlModuleData.js │ ├── check6moDrops.ts │ ├── checkChart.ts │ ├── checkProtocolsToList.ts │ ├── checkRefillable.ts │ ├── checkTokensInUsdMatchesTokens.ts │ ├── clearProtocolCache.ts │ ├── coingeckoUpdater.ts │ ├── coingeckoUpdaterParent.ts │ ├── copyListing.ts │ ├── countMisrepresented.ts │ ├── customFill.ts │ ├── customFillAll.ts │ ├── deleteAtDate.ts │ ├── deleteChain.ts │ ├── deleteCoinsDDB.ts │ ├── deleteLatestDayTvl.ts │ ├── deleteLatestDayTvlAllProtocols.ts │ ├── deleteProtocolsDate.ts │ ├── deleteToken.ts │ ├── deleteTvl.ts │ ├── displayData.ts │ ├── displayItems.ts │ ├── dynamodb.ts │ ├── fillLast.ts │ ├── fillOld.ts │ ├── fillOldChain.ts │ ├── findDeadDomains.ts │ ├── findDrop.ts │ ├── findDroppedCoins.ts │ ├── findDroppedTokens.js │ ├── findGoodUnlocks.ts │ ├── findSimilarRaises.ts │ ├── findStaleTvl.ts │ ├── findUntaggedProtocolsInRaises.ts │ ├── findUntaggedRaises.ts │ ├── findUnupdated.ts │ ├── fixDecimals.ts │ ├── getItem.ts │ ├── getNftSales.ts │ ├── hourlyInflows.ts │ ├── importFromDb.ts │ ├── importHistoricalPrices.ts │ ├── importRaw.ts │ ├── interactive-dimensions.ts │ ├── interactive.ts │ ├── liquidity │ │ ├── findDiffChainsInYields.ts │ │ ├── findDuplicateSymbols.ts │ │ └── getCoinLiquidity.ts │ ├── main.ts │ ├── mapForkedFromtoId.ts │ ├── moveTreasuries.ts │ ├── old-scripts │ │ ├── cacheTest.ts │ │ ├── customFillOhm.ts │ │ ├── huobi_stUSDT.ts │ │ └── migrateTreasury.ts │ ├── protocolStats.ts │ ├── recomputeDaily.ts │ ├── refillFromBackup.ts │ ├── refillNpmData.ts │ ├── refillWithHourly.ts │ ├── refreshProtocolsCache.ts │ ├── removeCorrupted.ts │ ├── replaceChain.ts │ ├── search │ │ └── setup.sh │ ├── setHistoricalTokens.ts │ ├── temp │ │ └── stUSDT2_hourly.ts │ ├── users │ │ ├── README.md │ │ ├── deprecated │ │ │ └── refillHistoricalActiveUsers.ts │ │ ├── findMissingUsers.ts │ │ ├── findMostUsedChainsForUsers.ts │ │ ├── findProtocolsMissingHistoricalData.ts │ │ ├── queries │ │ │ ├── gas.ts │ │ │ ├── newUsers.ts │ │ │ ├── txs.ts │ │ │ └── users.ts │ │ ├── refilChainTxs.ts │ │ ├── refillChain.ts │ │ ├── refillChainGas.ts │ │ ├── refillChainUsers.ts │ │ ├── refillChainsTxs.ts │ │ ├── refillNewChainUsers.ts │ │ ├── refillNewUsers.ts │ │ ├── refillUsers.ts │ │ └── single │ │ │ ├── deleteProtocolUserData.ts │ │ │ ├── refillSingleProtocol.ts │ │ │ └── utils │ │ │ └── deleteUserData.ts │ ├── utils.ts │ └── utils │ │ └── clearProtocolCache.ts ├── constants.ts ├── constants │ └── chainsByOracle.ts ├── corsPreflight.ts ├── depositedContracts │ ├── constants.ts │ ├── helpers.ts │ └── types.ts ├── developers │ ├── npm.ts │ └── utils.ts ├── dexAggregators │ └── db │ │ ├── Models │ │ ├── PermitBlackList.ts │ │ └── SwapEvent.ts │ │ ├── getHistory.ts │ │ ├── getLatestSwap.ts │ │ ├── getPermitBlackList.ts │ │ ├── getSwapDailyVolume.ts │ │ ├── getSwapTotalVolume.ts │ │ ├── index.ts │ │ ├── saveBlacklistPemrit.ts │ │ └── saveEvent.ts ├── dimension-scripts │ ├── checkLastDayDerivativesUrgent.js │ ├── checkLastDayFeesUrgent.js │ └── checkLastDayVolumeUrgent.js ├── externalEndpointsCache │ └── index.ts ├── fallback.test.ts ├── fallback.ts ├── fetchLiquidations.ts ├── getActiveUsers.ts ├── getBlackListedTokens.ts ├── getCategories.ts ├── getChainAssetFlows.ts ├── getChainAssetHistoricalFlows.ts ├── getChainAssets.ts ├── getChainAssetsChart.ts ├── getChains.ts ├── getChart.ts ├── getCoins.ts ├── getConfig.ts ├── getContractName.ts ├── getDataset.ts ├── getDefaultChart.ts ├── getDepositedContracts.ts ├── getEmissionProtocol.ts ├── getEmissions.ts ├── getEmissionsBreakdown.ts ├── getEmissionsList.ts ├── getForks.ts ├── getFormattedChains.ts ├── getHacks.ts ├── getHistoricalLiquidity.ts ├── getHourlyData.ts ├── getInflows.ts ├── getLatestSwap.ts ├── getNewsArticles.ts ├── getNpmData.ts ├── getOracles.ts ├── getProtocol.test.ts ├── getProtocol.ts ├── getProtocolTvl.ts ├── getProtocolUsers.ts ├── getProtocols.test.ts ├── getProtocols.ts ├── getRaises.ts ├── getSimpleChainDataset.ts ├── getSmolConfig.ts ├── getSwapDailyVolume.ts ├── getSwapTotalVolume.ts ├── getSwapsHistory.ts ├── getTokenInProtocols.ts ├── getTotalProtocolUsersData.ts ├── getTreasury.ts ├── getUpdatedProtocol.ts ├── getYieldsConfig.ts ├── governance │ ├── cache.ts │ ├── compound.ts │ ├── getLogs.ts │ ├── getSnapshotIds.ts │ ├── icp │ │ ├── icp.test.ts │ │ ├── icp.ts │ │ ├── nns.ts │ │ ├── sns.ts │ │ └── taggr.ts │ ├── snapshot.ts │ ├── snapshotQueries.ts │ ├── tally.ts │ ├── test.ts │ ├── types.ts │ └── utils.ts ├── growthReport.ts ├── jest-dynalite-config.json ├── liquidationsUtils │ └── index.ts ├── monitorDexResponse.ts ├── nfts │ ├── generateJson.ts │ ├── output │ │ └── parentCompanies.json │ └── parentCompanies.ts ├── notifyOutdated.ts ├── notifyStaleCoins.ts ├── operationalCosts │ ├── README.md │ ├── daos.ts │ ├── generateOutput.ts │ └── output │ │ └── expenses.json ├── overrideChainAssets.ts ├── protocols │ ├── data.test.ts │ ├── data.ts │ ├── data2.ts │ ├── data3.ts │ ├── data4.ts │ ├── dexVolumes.ts │ ├── entities.ts │ ├── import.test.ts │ ├── parentProtocols.ts │ ├── tags.ts │ ├── treasury.ts │ └── types.ts ├── reportError.ts ├── runLocalTVL.ts ├── sendDiscordMessage.ts ├── server-scripts │ ├── notifyOutdated.ts │ └── notifyStablecoinSpikes.ts ├── setupTestEnv.js ├── stats │ ├── getMissedUpdates.ts │ └── getOutdated.ts ├── storeActiveUsers.ts ├── storeActiveUsersRetrieve.ts ├── storeAggregatorEvent.ts ├── storeBlacklistPermit.ts ├── storeChainAssetFlows.ts ├── storeChainAssets.ts ├── storeChainNftVolume.ts ├── storeCsvDataset.ts ├── storeEmissions.ts ├── storeEmissionsIndex.ts ├── storeEmissionsUtils.ts ├── storeFullTokenlist.ts ├── storeGetCharts.ts ├── storeGetProtocols.ts ├── storeGovernance.ts ├── storeLangs.ts ├── storeLiquidations.ts ├── storeNpmData.ts ├── storeProtocolsLiquidity.ts ├── storeSortedTokenlist.ts ├── storeTokenList.ts ├── storeTreasuryInterval.ts ├── storeTvlInterval.ts ├── storeTvlInterval │ ├── blocks.ts │ ├── computeTVL.ts │ ├── getAndStoreTvl.ts │ ├── staleCoins.ts │ ├── storeNewTokensValueLocked.ts │ ├── storeNewTvl.ts │ ├── storeNewTvl2.ts │ ├── storeTvls.test.ts │ └── storeTvls.ts ├── storeTvlTask.ts ├── storeTvlUtils │ └── craftCsvDataset.ts ├── triggerFetchLiquidations.ts ├── triggerStoreTreasuries.ts ├── triggerStoreTvls.ts ├── twitter │ ├── db.ts │ ├── migrateTwitterData.ts │ ├── setLastTweet.ts │ ├── updateTwitterData.ts │ └── utils.ts ├── types.ts ├── updateSearch.ts ├── users │ ├── data-adapters.test.ts │ ├── storeUsers.ts │ ├── tables.sql │ └── utils.ts └── utils │ ├── airtable.ts │ ├── coingeckoPlatforms.test.ts │ ├── coingeckoPlatforms.ts │ ├── craftParentProtocol.ts │ ├── craftProtocol.ts │ ├── csvDataLoader.ts │ ├── date.test.ts │ ├── date.ts │ ├── discord.ts │ ├── error.ts │ ├── excludeProtocols.ts │ ├── findOutdated.ts │ ├── getLastRecord.ts │ ├── getProtocolTvl.ts │ ├── imports │ ├── importAdapter.ts │ └── importDexAdapters.ts │ ├── normalizeChain.ts │ ├── normalizeChains.test.ts │ ├── pThrottle │ ├── index.d.ts │ └── index.ts │ ├── r2.ts │ ├── s3.ts │ ├── shared │ ├── bridgedTvlPostgres.ts │ ├── coingeckoLocks.ts │ ├── constants.ts │ ├── dynamodb.test.ts │ ├── dynamodb.ts │ ├── getDBConnection.ts │ ├── getRecordClosestToTimestamp.ts │ ├── getRecordEarliestTimestamp.ts │ ├── index.ts │ ├── invokeLambda.ts │ ├── lambda-response.test.ts │ ├── lambda-response.ts │ ├── parseRequestBody.test.ts │ ├── parseRequestBody.ts │ ├── setEnvSecrets.ts │ ├── shuffleArray.ts │ ├── sleep.ts │ ├── withTimeout.ts │ └── wrap.ts │ ├── sluggify.ts │ ├── standardizeProtocolName.ts │ └── symbols │ ├── convert.ts │ └── symbols.json ├── tsconfig.json ├── ui-tool ├── .gitignore ├── package-lock.json ├── package.json ├── public │ ├── gib.webp │ ├── index.html │ └── manifest.json └── src │ ├── App.css │ ├── App.js │ ├── dimensions.ts │ ├── index.css │ ├── index.js │ ├── server.ts │ └── tvl.ts └── webpack.config.js /.github/workflows/check-urls.yml: -------------------------------------------------------------------------------- 1 | name: Check URLs 2 | 3 | on: 4 | schedule: 5 | - cron: '0 8 * * 0' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Set up Ruby 14 | uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 15 | with: 16 | ruby-version: 2.6 17 | - name: Install awesome_bot 18 | run: gem install awesome_bot -v 1.20.0 19 | - name: Check URLs 20 | run: awesome_bot defi/src/protocols/* --allow-redirect --request-delay 0.2 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .webpack 3 | .env 4 | .serverless 5 | imported-db 6 | docker 7 | .DS_Store 8 | .esbuild 9 | .vscode 10 | 11 | defi/src/cli/tmp 12 | defi/dev-metrics/app-data 13 | defi/dev-metrics/runner/repo 14 | defi/src/api2/local-scripts 15 | defi/.safe_commit_hash 16 | defi/.current_commit_hash 17 | */api2-cache 18 | *.log -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "DefiLlama-Adapters"] 2 | path = defi/DefiLlama-Adapters 3 | url = https://github.com/DefiLlama/DefiLlama-Adapters.git 4 | branch = main 5 | [submodule "defi/dimension-adapters"] 6 | path = defi/dimension-adapters 7 | url = https://github.com/DefiLlama/dimension-adapters.git 8 | [submodule "defi/emissions-adapters"] 9 | path = defi/emissions-adapters 10 | url = https://github.com/DefiLlama/emissions-adapters.git 11 | -------------------------------------------------------------------------------- /coins/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | .serverless 4 | .esbuild 5 | -------------------------------------------------------------------------------- /coins/README.md: -------------------------------------------------------------------------------- 1 | # Coins server 2 | 3 | For usage: https://defillama.com/docs/api 4 | For contributions: https://docs.llama.fi/coin-prices-api -------------------------------------------------------------------------------- /coins/env.js: -------------------------------------------------------------------------------- 1 | ../defi/env.js -------------------------------------------------------------------------------- /coins/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | }; -------------------------------------------------------------------------------- /coins/resources: -------------------------------------------------------------------------------- 1 | ../defi/resources/ -------------------------------------------------------------------------------- /coins/src/__mocks__: -------------------------------------------------------------------------------- 1 | ../../defi/src/__mocks__ -------------------------------------------------------------------------------- /coins/src/adapters/bridges/aptosFa.ts: -------------------------------------------------------------------------------- 1 | import { Token } from "./index"; 2 | import { fetch } from "../utils"; 3 | 4 | export default async function bridge(): Promise { 5 | const res = (await fetch( 6 | "https://raw.githubusercontent.com/PanoraExchange/Aptos-Tokens/refs/heads/main/token-list.json", 7 | )) as any[]; 8 | 9 | const tokens: Token[] = []; 10 | res.map(({ decimals, symbol, faAddress, tokenAddress, coinGeckoId }) => { 11 | if (faAddress && coinGeckoId) 12 | tokens.push({ 13 | from: `aptos:${faAddress}`, 14 | to: `coingecko:${coinGeckoId}`, 15 | decimals, 16 | symbol, 17 | }); 18 | else if (faAddress && tokenAddress) 19 | tokens.push({ 20 | from: `aptos:${faAddress}`, 21 | to: `aptos:${tokenAddress}`, 22 | decimals, 23 | symbol, 24 | }); 25 | if (coinGeckoId && tokenAddress) 26 | tokens.push({ 27 | from: `aptos:${tokenAddress}`, 28 | to: `coingecko:${coinGeckoId}`, 29 | decimals, 30 | symbol, 31 | }); 32 | }); 33 | 34 | return tokens; 35 | } 36 | -------------------------------------------------------------------------------- /coins/src/adapters/bridges/arbitrum_nova.ts: -------------------------------------------------------------------------------- 1 | import { fetch, formatExtraTokens } from "../utils"; 2 | 3 | export default async function bridge() { 4 | // https://tokenlist.arbitrum.io/ArbTokenLists/42170_arbed_gemini_token_list.json 5 | const bridge = ( 6 | await fetch("https://tokenlist.arbitrum.io/ArbTokenLists/42170_arbed_uniswap_labs_default.json") 7 | ).tokens as any[]; 8 | 9 | return bridge 10 | .map((token) => { 11 | if (token.extensions == null) 12 | return { 13 | from: `arbitrum_nova:${token.address}`, 14 | to: `null`, 15 | symbol: token.symbol, 16 | decimals: token.decimals 17 | }; 18 | const bridged = token.extensions.bridgeInfo[1].tokenAddress; 19 | return { 20 | from: `arbitrum_nova:${token.address}`, 21 | to: `ethereum:${bridged}`, 22 | symbol: token.symbol, 23 | decimals: token.decimals 24 | }; 25 | }) 26 | .filter((t) => t.to != "null") 27 | .concat(extraTokens); 28 | } 29 | 30 | const extraTokens = formatExtraTokens("arbitrum_nova", []); 31 | -------------------------------------------------------------------------------- /coins/src/adapters/bridges/base.ts: -------------------------------------------------------------------------------- 1 | import { Token } from "./index"; 2 | import { fetch, formatExtraTokens } from "../utils"; 3 | 4 | export default async function bridge(): Promise { 5 | const bridge = ( 6 | await fetch("https://static.optimism.io/optimism.tokenlist.json") 7 | ).tokens as any[]; 8 | 9 | const ethUrlMap = bridge 10 | .filter((token) => token.chainId === 1) 11 | .reduce((all, token) => { 12 | all[token.logoURI] = token; 13 | return all; 14 | }, {}); 15 | 16 | const tokens: Token[] = []; 17 | bridge 18 | .filter((token) => token.chainId === 8453) 19 | .map((optToken) => { 20 | const ethToken = ethUrlMap[optToken.logoURI]; 21 | if (ethToken === undefined) return; 22 | tokens.push({ 23 | from: `base:${optToken.address}`, 24 | to: `ethereum:${ethToken.address}`, 25 | symbol: optToken.symbol, 26 | decimals: optToken.decimals 27 | }); 28 | }); 29 | const response = [tokens, extraTokens] 30 | 31 | return response.flat() 32 | } 33 | 34 | const extraTokens = formatExtraTokens("base", []); 35 | -------------------------------------------------------------------------------- /coins/src/adapters/bridges/fantom.ts: -------------------------------------------------------------------------------- 1 | export default async function bridge() { 2 | return [ 3 | { 4 | from: "fantom:0x658b0c7613e890ee50b8c4bc6a3f41ef411208ad", 5 | to: "coingecko#ethereum", 6 | symbol: "FETH", 7 | decimals: 18, 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /coins/src/adapters/bridges/linea.ts: -------------------------------------------------------------------------------- 1 | import { fetch, formatExtraTokens } from "../utils"; 2 | 3 | const chain = 'linea' 4 | export default async function bridge() { 5 | const bridge = ( 6 | await fetch("https://raw.githubusercontent.com/Consensys/linea-token-list/main/json/linea-mainnet-token-fulllist.json") 7 | ).tokens as any[]; 8 | 9 | return bridge 10 | .filter((token) => token.chainId === 59144 && token.extension?.rootChainId === 1 && token.tokenType.includes('bridged')) 11 | .map((token) => { 12 | const bridged = token.extension.rootAddress; 13 | return { 14 | from: `${chain}:${token.address}`, 15 | to: `ethereum:${bridged}`, 16 | symbol: token.symbol, 17 | decimals: token.decimals 18 | }; 19 | }) 20 | .filter((t) => t.to != "null") 21 | .concat(extraTokens); 22 | } 23 | 24 | const extraTokens = formatExtraTokens(chain, []); 25 | -------------------------------------------------------------------------------- /coins/src/adapters/bridges/manta.ts: -------------------------------------------------------------------------------- 1 | import { Token } from "./index"; 2 | import { fetch, formatExtraTokens } from "../utils"; 3 | 4 | export default async function bridge(): Promise { 5 | const bridge = ( 6 | await fetch("https://raw.githubusercontent.com/Manta-Network/manta-pacific-token-list/main/json/manta-pacific-mainnet-token-list.json") 7 | ).tokens as any[]; 8 | 9 | const tokens: Token[] = []; 10 | bridge 11 | .filter((token) => token.chainId === 169) 12 | .map((optToken) => { 13 | if (optToken.extension?.rootChainId !== 1) return; 14 | const ethToken = optToken.extension?.rootAddress 15 | if (ethToken === undefined) return; 16 | tokens.push({ 17 | from: `manta:${optToken.address}`, 18 | to: `ethereum:${ethToken}`, 19 | symbol: optToken.symbol, 20 | decimals: optToken.decimals 21 | }); 22 | }); 23 | const response = [tokens, extraTokens] 24 | 25 | return response.flat() 26 | } 27 | 28 | const extraTokens = formatExtraTokens("manta", []); 29 | -------------------------------------------------------------------------------- /coins/src/adapters/bridges/neon_evm.ts: -------------------------------------------------------------------------------- 1 | import { Token } from "./index"; 2 | import { fetch, formatExtraTokens } from "../utils"; 3 | 4 | export default async function bridge(): Promise { 5 | const bridge = ( 6 | await fetch("https://raw.githubusercontent.com/neonlabsorg/token-list/main/tokenlist.json") 7 | ).tokens as any[]; 8 | 9 | const tokens: Token[] = []; 10 | bridge 11 | .map((token) => { 12 | if (token.chainId !== 245022934 || !token.address_spl) return; 13 | tokens.push({ 14 | from: `neon_evm:${token.address}`, 15 | to: `solana:${token.address_spl}`, 16 | symbol: token.symbol, 17 | decimals: token.decimals 18 | }); 19 | }); 20 | const response = [tokens, extraTokens] 21 | 22 | return response.flat() 23 | } 24 | 25 | const extraTokens = formatExtraTokens("neon_evm", []); 26 | -------------------------------------------------------------------------------- /coins/src/adapters/bridges/overwrites.ts: -------------------------------------------------------------------------------- 1 | import { getCurrentUnixTimestamp } from '../../utils/date' 2 | import {cgPK} from '../../utils/keys' 3 | // After changing this you need to run cli/writeOverwrites! 4 | 5 | const timestamp = getCurrentUnixTimestamp() 6 | export const overwrites = [ 7 | { 8 | PK: "asset#fantom:0x260b3e40c714ce8196465ec824cd8bb915081812", 9 | SK: 0, 10 | created: timestamp, 11 | redirect: cgPK('iron-finance'), // polygon:0x4a81f8796e0c6ad4877a51c86693b0de8093f2ef 12 | symbol: "IronICE", 13 | decimals: 18, 14 | } 15 | ] -------------------------------------------------------------------------------- /coins/src/adapters/bridges/zircuit.ts: -------------------------------------------------------------------------------- 1 | import { Token } from "./index"; 2 | import { fetch } from "../utils"; 3 | import { chainIdMap } from "./celer"; 4 | 5 | export default async function bridge(): Promise { 6 | const res = (await fetch("https://bridge.zircuit.com/api/tokens")) as any[]; 7 | 8 | const tokens: Token[] = []; 9 | res.map( 10 | ({ 11 | chainId, 12 | addressLocal, 13 | addressRemote, 14 | symbol, 15 | decimalsLocal: decimals, 16 | }) => { 17 | if (!(chainId in chainIdMap)) return; 18 | const to = `${chainIdMap[chainId]}:${addressRemote}`; 19 | tokens.push({ 20 | from: `zircuit:${addressLocal}`, 21 | to, 22 | decimals, 23 | symbol, 24 | }); 25 | }, 26 | ); 27 | 28 | return tokens; 29 | } 30 | -------------------------------------------------------------------------------- /coins/src/adapters/ethers.ts: -------------------------------------------------------------------------------- 1 | import {providers} from "@defillama/sdk/build/general" 2 | 3 | export {providers} -------------------------------------------------------------------------------- /coins/src/adapters/liquidStaking/ankr/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./ankr"; 2 | 3 | export function ankr(timestamp: number = 0) { 4 | return getTokenPrices(timestamp); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/liquidStaking/ifil/index.ts: -------------------------------------------------------------------------------- 1 | import { getApi } from "../../utils/sdk"; 2 | import getWrites from "../../utils/getWrites"; 3 | 4 | export async function ifil(timestamp: number) { 5 | const chain = "filecoin"; 6 | const api = await getApi(chain, timestamp); 7 | 8 | const rate = await api.call({ 9 | abi: "function convertToAssets(uint256 assets) external view returns (uint256)", 10 | target: "0xe764Acf02D8B7c21d2B6A8f0a96C78541e0DC3fd", 11 | params: 1e12, 12 | }); 13 | 14 | const pricesObject: any = { 15 | "0x690908f7fa93afC040CFbD9fE1dDd2C2668Aa0e0": { 16 | underlying: "0x0000000000000000000000000000000000000000", 17 | price: rate / 1e12, 18 | }, 19 | }; 20 | 21 | return getWrites({ 22 | chain, 23 | timestamp, 24 | pricesObject, 25 | projectName: "iFIL", 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /coins/src/adapters/liquidStaking/pxeth/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "getStakingValidatorCount": { 3 | "inputs": [], 4 | "name": "getStakingValidatorCount", 5 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 6 | "stateMutability": "view", 7 | "type": "function" 8 | }, 9 | "pendingDeposit": { 10 | "inputs": [], 11 | "name": "pendingDeposit", 12 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | "buffer": { 17 | "inputs": [], 18 | "name": "buffer", 19 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 20 | "stateMutability": "view", 21 | "type": "function" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /coins/src/adapters/liquidStaking/pxeth/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./pxeth"; 2 | 3 | export function pxeth(timestamp: number = 0) { 4 | return getTokenPrices(timestamp); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/liquidStaking/xailocker/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "curvePoolQuoteAlXaiToXai": { 3 | "stateMutability":"view", 4 | "type":"function", 5 | "name":"get_dy", 6 | "inputs": [ 7 | {"name":"i","type":"int128"}, 8 | {"name":"j","type":"int128"}, 9 | {"name":"dx","type":"uint256"} 10 | ], 11 | "outputs": [{"name":"","type":"uint256"}] 12 | }, 13 | "previewSharesToLiquidity": { 14 | "type": "function", 15 | "name": "previewSharesToLiquidity", 16 | "inputs": [ 17 | { "name": "amount", "type": "uint256", "internalType": "uint256" } 18 | ], 19 | "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], 20 | "stateMutability": "view" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /coins/src/adapters/liquidStaking/xailocker/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrice from "./xailocker"; 2 | 3 | export function xailocker(timestamp: number = 0) { 4 | return getTokenPrice(timestamp); 5 | } -------------------------------------------------------------------------------- /coins/src/adapters/markets/0xequity/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./xequity"; 2 | 3 | export function xequity(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices("arbitrum", timestamp), 6 | getTokenPrices("base", timestamp), 7 | getTokenPrices("unit0", timestamp), 8 | ]); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/aktionariat/index.ts: -------------------------------------------------------------------------------- 1 | import * as sdk from "@defillama/sdk"; 2 | import getTokenPrices from "./aktionariat"; 3 | 4 | export function aktionariat(timestamp: number = 0) { 5 | return Promise.all([ 6 | getTokenPrices( 7 | "ethereum", 8 | sdk.graph.modifyEndpoint('2ZoJCp4S7YP7gbYN2ndsYNjPeZBV1PMti7BBoPRRscNq'), 9 | timestamp, 10 | ["0xb4272071ecadd69d933adcd19ca99fe80664fc08"] // ignore only xchf, other stable pairings are not used 11 | ), 12 | getTokenPrices( 13 | "optimism", 14 | sdk.graph.modifyEndpoint('3QfEXbPfP23o3AUzcmjTfRtUUd4bfrFj3cJ4jET57CTX'), 15 | timestamp, 16 | ["0xe4f27b04cc7729901876b44f4eaa5102ec150265"] // ignore only xchf, other stable pairings are not used 17 | ), 18 | ]); 19 | } -------------------------------------------------------------------------------- /coins/src/adapters/markets/arrakis/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices, { config } from "./arrakis"; 2 | 3 | const chains = Object.keys(config) 4 | 5 | export function arrakis(timestamp: number = 0) { 6 | return Promise.all(chains.map(i => getTokenPrices(i, timestamp))) 7 | } 8 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/hop/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "getVirtualPrice": { 3 | "inputs": [], 4 | "name": "getVirtualPrice", 5 | "outputs": [ 6 | { 7 | "internalType": "uint256", 8 | "name": "", 9 | "type": "uint256" 10 | } 11 | ], 12 | "stateMutability": "view", 13 | "type": "function" 14 | }, 15 | "getToken": { 16 | "inputs": [{ "internalType": "uint8", "name": "index", "type": "uint8" }], 17 | "name": "getToken", 18 | "outputs": [ 19 | { "internalType": "contract IERC20", "name": "", "type": "address" } 20 | ], 21 | "stateMutability": "view", 22 | "type": "function" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/hop/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./hop"; 2 | 3 | export function hop(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices(timestamp, "polygon"), 6 | getTokenPrices(timestamp, "xdai"), 7 | getTokenPrices(timestamp, "optimism"), 8 | getTokenPrices(timestamp, "arbitrum") 9 | ]); 10 | } 11 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/jarvis/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./jarvis"; 2 | 3 | export function jarvis(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices("polygon", timestamp), 6 | ]); 7 | } 8 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/maverick/contracts.json: -------------------------------------------------------------------------------- 1 | { 2 | "ethereum": { 3 | "poolInfo": "0x9980ce3b5570e41324904f46A06cE7B466925E23", 4 | "pools": [ 5 | "0xB0ba344cdf607DD952c6CBF70B21cAED77c3D200" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /coins/src/adapters/markets/parallelProtocol/index.ts: -------------------------------------------------------------------------------- 1 | import { getTokenPrices } from "./parallelProtocol"; 2 | 3 | export function parallelProtocol(timestamp: number) { 4 | return getTokenPrices("ethereum", timestamp); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/phux/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./phux"; 2 | 3 | export function phux(timestamp: number = 0) { 4 | return getTokenPrices("pulse", timestamp); 5 | } -------------------------------------------------------------------------------- /coins/src/adapters/markets/platypus/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./platypus"; 2 | 3 | export function platypus(timestamp: number = 0) { 4 | return getTokenPrices(timestamp); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/stargate/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalLiquidity": "function totalLiquidity() view returns (uint256)" 3 | } 4 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/stargate/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./stargate"; 2 | 3 | export function stargate(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices("ethereum", timestamp), 6 | getTokenPrices("bsc", timestamp), 7 | getTokenPrices("avax", timestamp), 8 | getTokenPrices("polygon", timestamp), 9 | getTokenPrices("arbitrum", timestamp), 10 | getTokenPrices("optimism", timestamp), 11 | getTokenPrices("base", timestamp), 12 | getTokenPrices("fantom", timestamp), 13 | getTokenPrices("kava", timestamp), 14 | getTokenPrices("lightlink", timestamp) 15 | ]); 16 | } 17 | -------------------------------------------------------------------------------- /coins/src/adapters/markets/steer/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices, { supportedChains } from "./steer"; 2 | 3 | 4 | 5 | export function steer(timestamp: number = 0) { 6 | return Promise.all(supportedChains.map(i => getTokenPrices(i, timestamp))) 7 | } -------------------------------------------------------------------------------- /coins/src/adapters/markets/todo.md: -------------------------------------------------------------------------------- 1 | - xJOE 2 | - qiAVAX, crTokens, tokens from comp forks 3 | - aTokens on other chains 4 | - uniswap/sushiswap LPs 5 | - yTokens 6 | - curve lps 7 | - -------------------------------------------------------------------------------- /coins/src/adapters/moneyMarkets/aave-debt/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices, { config } from "./aaveDebt"; 2 | 3 | const chains = Object.keys(config) 4 | 5 | export function aaveDebt(timestamp: number = 0) { 6 | return Promise.all(chains.map(i => getTokenPrices(i, timestamp))) 7 | } 8 | -------------------------------------------------------------------------------- /coins/src/adapters/moneyMarkets/compound/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "exchangeRateStored": { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "exchangeRateStored", 6 | "outputs": [{ "name": "", "type": "uint256" }], 7 | "payable": false, 8 | "stateMutability": "view", 9 | "type": "function" 10 | }, 11 | "getAllMarkets": { 12 | "constant": true, 13 | "inputs": [], 14 | "name": "getAllMarkets", 15 | "outputs": [ 16 | { "internalType": "contract CToken[]", "name": "", "type": "address[]" } 17 | ], 18 | "payable": false, 19 | "stateMutability": "view", 20 | "type": "function" 21 | }, 22 | "underlying": { 23 | "constant": true, 24 | "inputs": [], 25 | "name": "underlying", 26 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 27 | "payable": false, 28 | "stateMutability": "view", 29 | "type": "function" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /coins/src/adapters/moneyMarkets/dforce.ts: -------------------------------------------------------------------------------- 1 | import { compoundPrices } from "../utils/compound-fork"; 2 | 3 | const config = { 4 | arbitrum: "0x8e7e9ea9023b81457ae7e6d2a51b003d421e5408", 5 | optimism: "0xdF0e115aA822443df9200Cc5d0260FA8E1aF06F5", 6 | }; 7 | 8 | export function dforce(timestamp: number) { 9 | return Promise.all( 10 | Object.entries(config).map(([chain, comptroller]: any) => 11 | compoundPrices({ 12 | chain, 13 | timestamp, 14 | comptroller, 15 | projectName: "dforce", 16 | abis: { 17 | marketsAbi: "address[]:getAlliTokens", 18 | }, 19 | }), 20 | ), 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /coins/src/adapters/moneyMarkets/euler/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "convertBalanceToUnderlying": { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "balance", 7 | "type": "uint256" 8 | } 9 | ], 10 | "name": "convertBalanceToUnderlying", 11 | "outputs": [ 12 | { 13 | "internalType": "uint256", 14 | "name": "", 15 | "type": "uint256" 16 | } 17 | ], 18 | "stateMutability": "view", 19 | "type": "function" 20 | }, 21 | "underlyingAsset": { 22 | "inputs": [], 23 | "name": "underlyingAsset", 24 | "outputs": [ 25 | { 26 | "internalType": "address", 27 | "name": "", 28 | "type": "address" 29 | } 30 | ], 31 | "stateMutability": "view", 32 | "type": "function" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /coins/src/adapters/moneyMarkets/folks-finance/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./folks-finance"; 2 | 3 | export function folksFinance(timestamp: number = 0) { 4 | return getTokenPrices("avax", timestamp); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/nft/chainlink/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./chainlink"; 2 | 3 | export function chainlinkNFT(timestamp: number = 0) { 4 | return getTokenPrices("ethereum", timestamp); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/nft/chainlink/priceFeeds_jpegd.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | ethereum: [ 3 | { 4 | underlying: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', 5 | nfts: [ 6 | { // ether rock 7 | token: "0xa3f5998047579334607c47a6a2889bf87a17fc02", 8 | oracle: "0x9921da2908CC59b13ddbcF45e64BFA91c78c4249", 9 | }, 10 | ], 11 | artBlocks: { 12 | underlying: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', 13 | nfts: [ 14 | { 15 | label: "chromie-squiggle", 16 | oracle: "0x753eF2495D09D6650573F5389fDA3A57017f302A", 17 | }, 18 | { 19 | label: "fidenza", 20 | oracle: "0x1a6fA849D5bF62F9b7B83D125E77e15292c54b4f", 21 | }, 22 | { 23 | label: "ringer", 24 | oracle: "0x927318B867f0939Ab501dFd7b1B8d60E52ea5B59", 25 | }, 26 | ], 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /coins/src/adapters/other/defichain.ts: -------------------------------------------------------------------------------- 1 | import { addToDBWritesList } from "../utils/database"; 2 | import { Write } from "../utils/dbInterfaces"; 3 | 4 | export default (timestamp: number) => { 5 | const writes: Write[] = []; 6 | const mapping: { [apiKey: string]: { cgId: string; symbol: string } } = { 7 | eth: { cgId: "ethereum", symbol: "ETH" }, 8 | dfi: { cgId: "defichain", symbol: "DFI" }, 9 | btc: { cgId: "bitcoin", symbol: "BTC" }, 10 | usdt: { cgId: "tether", symbol: "USDT" }, 11 | usdc: { cgId: "usd-coin", symbol: "USDC" }, 12 | dusd: { cgId: "decentralized-usd", symbol: "DUSD" }, 13 | }; 14 | 15 | Object.keys(mapping).map((from: string) => 16 | addToDBWritesList( 17 | writes, 18 | "defichain", 19 | from, 20 | undefined, 21 | 0, 22 | mapping[from].symbol, 23 | timestamp, 24 | "defichain", 25 | 1, 26 | `coingecko#${mapping[from].cgId}`, 27 | ), 28 | ); 29 | 30 | return writes; 31 | }; 32 | -------------------------------------------------------------------------------- /coins/src/adapters/other/fraxtalGas.ts: -------------------------------------------------------------------------------- 1 | import { nullAddress } from "../../utils/shared/constants"; 2 | import { 3 | addToDBWritesList, 4 | getTokenAndRedirectDataMap, 5 | } from "../utils/database"; 6 | import { Write } from "../utils/dbInterfaces"; 7 | 8 | export async function fraxtalGas(timestamp: number = 0) { 9 | const redirect = 10 | timestamp != 0 && timestamp < 1745949877 ? "frax-ether" : "frax-share"; 11 | 12 | const data = await getTokenAndRedirectDataMap( 13 | [redirect], 14 | "coingecko", 15 | timestamp, 16 | ); 17 | 18 | if (!(`coingecko#${redirect}` in data)) 19 | throw new Error(`no redirect data for fraxtalGas ${timestamp}`); 20 | 21 | const writes: Write[] = []; 22 | const { price, symbol, confidence } = data[`coingecko#${redirect}`]; 23 | addToDBWritesList( 24 | writes, 25 | "fraxtal", 26 | nullAddress, 27 | price, 28 | 18, 29 | symbol, 30 | timestamp, 31 | "fraxtal-gas", 32 | confidence ?? 1, 33 | ); 34 | 35 | return writes; 36 | } 37 | -------------------------------------------------------------------------------- /coins/src/adapters/other/optimBonds.ts: -------------------------------------------------------------------------------- 1 | import getWrites from "../utils/getWrites"; 2 | import { Write } from "../utils/dbInterfaces"; 3 | 4 | export function optimBonds(timestamp: number = 0) { 5 | const pricesObject: any = { 6 | OptimBond1: { 7 | underlying: "lovelace", 8 | price: 100, 9 | symbol: "OptimBond1", 10 | decimals: 0, 11 | }, 12 | }; 13 | 14 | const writes: Write[] = []; 15 | return getWrites({ 16 | chain: "cardano", 17 | timestamp, 18 | writes, 19 | pricesObject, 20 | projectName: "optimBonds", 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /coins/src/adapters/other/realt.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | import { Write } from "../utils/dbInterfaces"; 4 | import { addToDBWritesList } from "../utils/database"; 5 | 6 | export default async function getTokenPrices(chain: 'ethereum' | 'xdai', timestamp: number) { 7 | const res = await axios.get<{ 8 | symbol: string, 9 | tokenPrice: number, 10 | ethereumContract?: string, 11 | gnosisContract?: string, 12 | }[]>('https://api.realt.community/v1/token') 13 | 14 | const tokens = res.data.filter(x => chain === 'ethereum' ? x.ethereumContract != undefined : x.gnosisContract != undefined) 15 | 16 | const writes: Write[] = []; 17 | tokens.forEach(token => { 18 | addToDBWritesList( 19 | writes, 20 | chain, 21 | chain === 'ethereum' ? token.ethereumContract! : token.gnosisContract!, 22 | token.tokenPrice, 23 | 18, 24 | token.symbol, 25 | timestamp, 26 | "realt", 27 | 1, 28 | undefined, 29 | ); 30 | }) 31 | 32 | return writes; 33 | } 34 | -------------------------------------------------------------------------------- /coins/src/adapters/other/usdrif.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import getWrites from "../utils/getWrites"; 3 | 4 | const chain = "rsk"; 5 | 6 | const usdRIFToken = { 7 | address: "0x3a15461d8ae0f0fb5fa2629e9da7d66a794a6e37", 8 | symbol: "USDRIF", 9 | decimals: 18, 10 | }; 11 | 12 | export function usdrif(timestamp: number = 0) { 13 | return getTokenPrice(timestamp); 14 | } 15 | 16 | async function getTokenPrice(timestamp: number) { 17 | 18 | const response = await axios.get(`https://api.geckoterminal.com/api/v2/networks/rootstock/tokens/${usdRIFToken.address}/pools`) 19 | 20 | const [pool] = response.data.data; 21 | const price = pool.attributes.token_price_usd; 22 | const pricesObject: { [key: string]: any } = {}; 23 | 24 | pricesObject[usdRIFToken.address] = { 25 | token: usdRIFToken.address, 26 | price, 27 | symbol: usdRIFToken.symbol, 28 | decimals: usdRIFToken.decimals, 29 | }; 30 | 31 | return getWrites({ 32 | chain, 33 | timestamp, 34 | pricesObject, 35 | projectName: "usdrif", 36 | }); 37 | } -------------------------------------------------------------------------------- /coins/src/adapters/other/velgd.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | import { Write } from "../utils/dbInterfaces"; 3 | import { addToDBWritesList, getTokenAndRedirectData } from "../utils/database"; 4 | 5 | export default async function getTokenPrice(timestamp: number) { 6 | if (timestamp != 0) return []; 7 | const writes: Write[] = []; 8 | 9 | const [rate, [{ price: underlyingPrice }]] = await Promise.all([ 10 | (await fetch("https://vestadex.com/api/price?pair=VEGLD,EGLD")).json(), 11 | getTokenAndRedirectData(["WEGLD-bd4d79"], "elrond", timestamp), 12 | ]); 13 | 14 | addToDBWritesList( 15 | writes, 16 | "VEGLD-2b9319", 17 | "elrond", 18 | rate.price * underlyingPrice, 19 | 18, 20 | "VEGLD", 21 | timestamp, 22 | "sweth", 23 | 1, 24 | ); 25 | 26 | return writes; 27 | } 28 | -------------------------------------------------------------------------------- /coins/src/adapters/rwa/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "latestAnswer": { 3 | "inputs": [], 4 | "name": "latestAnswer", 5 | "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], 6 | "stateMutability": "view", 7 | "type": "function" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /coins/src/adapters/rwa/hashnote.ts: -------------------------------------------------------------------------------- 1 | import { Write } from "../utils/dbInterfaces"; 2 | import { getApi } from "../utils/sdk"; 3 | import { addToDBWritesList } from "../utils/database"; 4 | const abi = 'function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)' 5 | 6 | export async function hashnote(timestamp: number): Promise { 7 | const symbol = 'USYC' 8 | const api = await getApi("ethereum", timestamp); 9 | const tokenPrice = (await api.call({ abi, target: "0x4c48bcb2160F8e0aDbf9D4F3B034f1e36d1f8b3e", })).answer / 1e8; 10 | 11 | const writes: Write[] = []; 12 | addToDBWritesList(writes, 'canto', '0xfb8255f0de21acebf490f1df6f0bdd48cc1df03b', tokenPrice, 6, symbol, timestamp, "hashnote-rwa", 0.8,); 13 | addToDBWritesList(writes, 'ethereum', '0x136471a34f6ef19fe571effc1ca711fdb8e49f2b', tokenPrice, 6, symbol, timestamp, "hashnote-rwa", 0.8,); 14 | 15 | return writes; 16 | } 17 | -------------------------------------------------------------------------------- /coins/src/adapters/rwa/hiyield.ts: -------------------------------------------------------------------------------- 1 | import { Write } from "../utils/dbInterfaces"; 2 | import { getApi } from "../utils/sdk"; 3 | import { addToDBWritesList } from "../utils/database"; 4 | 5 | export async function hiyield(timestamp: number): Promise { 6 | const chain = "canto"; 7 | const address = "0x0E4289a95207CA653b60B0eB0b5848f29F4C3f72"; 8 | const symbol = "hyVWEAX"; 9 | const api = await getApi("canto", timestamp); 10 | const poolInfo = await api.call({ 11 | abi: "function poolInfo() external view returns(uint256, uint256, uint256, uint256, uint256)", 12 | target: address, 13 | }); 14 | 15 | const tokenPrice = poolInfo[4] / 1e18; 16 | 17 | const writes: Write[] = []; 18 | 19 | addToDBWritesList( 20 | writes, 21 | chain, 22 | address, 23 | tokenPrice, 24 | 18, 25 | symbol, 26 | timestamp, 27 | "hiyield-rwa", 28 | 0.8 29 | ); 30 | 31 | return writes; 32 | } 33 | -------------------------------------------------------------------------------- /coins/src/adapters/solana/kamino.ts: -------------------------------------------------------------------------------- 1 | import { Write } from "../utils/dbInterfaces"; 2 | import { addToDBWritesList } from "../utils/database"; 3 | 4 | import rpcProxy from "../utils/rpcProxy"; 5 | 6 | const markets: string[] = [ 7 | "DxXdAyU3kCjnyggvHmY5nAwg5cRbbmdyX3npfDMjjMek", 8 | "7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF", 9 | ]; 10 | 11 | export async function kamino(timestamp: number) { 12 | if (timestamp != 0) throw new Error(`Kamino adapter only works for current`); 13 | 14 | const reserves: any[] = (await Promise.all(markets.map(rpcProxy.kamino.reserves))).flat(); 15 | 16 | const writes: Write[] = []; 17 | for (let { price, token, decimals, symbol } of reserves) { 18 | 19 | addToDBWritesList(writes, "solana", token, price, decimals, `Kamino Reserve Collateral (${symbol}) Token`, timestamp, "kamino", 0.8,); 20 | } 21 | 22 | return writes; 23 | } 24 | -------------------------------------------------------------------------------- /coins/src/adapters/tezos/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./tezos"; 2 | 3 | export function tezos(timestamp: number = 0) { 4 | return getTokenPrices(timestamp); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/utils/block.ts: -------------------------------------------------------------------------------- 1 | import { api, blocks } from "@defillama/sdk"; 2 | import { getCurrentUnixTimestamp } from "../../utils/date"; 3 | import fetch from "node-fetch"; 4 | 5 | export default async function getBlock( 6 | chain: any, 7 | timestamp: number, 8 | ): Promise { 9 | if (timestamp == 0) return; 10 | if (chain == "era") { 11 | try { 12 | return ( 13 | await fetch( 14 | `https://coins.llama.fi/block/${chain}/${ 15 | timestamp == 0 ? getCurrentUnixTimestamp() : timestamp 16 | }`, 17 | ).then((res: any) => res.json()) 18 | ).height; 19 | } catch { 20 | throw new Error(`unable to find era block height at this timestamp`); 21 | } 22 | } 23 | return api.util 24 | .lookupBlock(timestamp, { chain }) 25 | .then((blockData) => blockData.block); 26 | } 27 | -------------------------------------------------------------------------------- /coins/src/adapters/utils/rpcProxy.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const client = axios.create({ 4 | baseURL: process.env.RPC_PROXY_URL, 5 | timeout: 30000, 6 | }) 7 | 8 | export default { 9 | kamino: { 10 | reserves: async (market) => { 11 | const { data } = await client.get('/kamino/lend/'+market) 12 | return data 13 | }, 14 | }, 15 | } -------------------------------------------------------------------------------- /coins/src/adapters/utils/sdkInterfaces.ts: -------------------------------------------------------------------------------- 1 | export interface Result { 2 | success: boolean; 3 | input: { 4 | target: string; 5 | params: any[]; 6 | }; 7 | output: any; 8 | } 9 | export interface Multicall { 10 | target: string; 11 | params: any[]; 12 | } 13 | export interface MultiCallResults { 14 | output: Result[]; 15 | } 16 | export interface TokenInfos { 17 | supplies: Result[]; 18 | lpDecimals: Result[]; 19 | underlyingDecimalAs: Result[]; 20 | underlyingDecimalBs: Result[]; 21 | symbolAs: Result[]; 22 | symbolBs: Result[]; 23 | lpSymbols: Result[]; 24 | } 25 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/alchemix/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "staticToDynamicAmount": { 3 | "inputs": [ 4 | { "internalType": "uint256", "name": "amount", "type": "uint256" } 5 | ], 6 | "name": "staticToDynamicAmount", 7 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 8 | "stateMutability": "view", 9 | "type": "function" 10 | }, 11 | "aToken": { 12 | "inputs": [], 13 | "name": "ATOKEN", 14 | "outputs": [ 15 | { "internalType": "contract IERC20", "name": "", "type": "address" } 16 | ], 17 | "stateMutability": "view", 18 | "type": "function" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/alchemix/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./alchemix"; 2 | 3 | export function alchemix(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices("optimism", timestamp), 6 | getTokenPrices("xdai", timestamp), 7 | // getTokenPrices("avax", timestamp), 8 | ]); 9 | } 10 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/beefy/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices, { config } from "./beefy"; 2 | 3 | const chains = Object.keys(config) 4 | 5 | export function beefy(timestamp: number = 0) { 6 | return Promise.all(chains.map(i => getTokenPrices(i, timestamp))) 7 | } 8 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/concentrator/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "nav":{"inputs":[],"name":"nav","outputs":[{"internalType":"uint256","name":"_nav","type":"uint256"}],"stateMutability":"view","type":"function"} 3 | } -------------------------------------------------------------------------------- /coins/src/adapters/yield/concentrator/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./concentrator"; 2 | 3 | export function concentrator(timestamp: number = 0) { 4 | return Promise.all([getTokenPrices(timestamp, "ethereum")]); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/convex/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./convex"; 2 | 3 | export function convex(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices(timestamp, "ethereum"), 6 | getTokenPrices(timestamp, "arbitrum") 7 | ]); 8 | } 9 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/fx-protocol/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "nav":{"inputs":[],"name":"nav","outputs":[{"internalType":"uint256","name":"_nav","type":"uint256"}],"stateMutability":"view","type":"function"} 3 | } -------------------------------------------------------------------------------- /coins/src/adapters/yield/fx-protocol/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./fx-protocol"; 2 | 3 | export function fxProtocol(timestamp: number = 0) { 4 | return Promise.all([getTokenPrices(timestamp, "ethereum")]); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/hlp.ts: -------------------------------------------------------------------------------- 1 | import { Write } from "../utils/dbInterfaces"; 2 | import getWrites from "../utils/getWrites"; 3 | import { getApi } from "../utils/sdk"; 4 | 5 | async function getTokenPrices(chain: string, timestamp: number) { 6 | // logic taken from vaultka: https://github.com/DefiLlama/DefiLlama-Adapters/pull/7633/files 7 | const api = await getApi(chain, timestamp) 8 | const rum = '0x739fe1BE8CbBeaeA96fEA55c4052Cd87796c0a89' 9 | const hlp = '0x4307fbDCD9Ec7AEA5a1c2958deCaa6f316952bAb' 10 | const priceAbi = "function getHLPPrice(bool maximize) public view returns (uint256)" 11 | const hlpPrice = await api.call({ target: rum, abi: priceAbi, params: true as any }) 12 | const pricesObject: any = { 13 | [hlp]: { price: hlpPrice / 1e12 } 14 | } 15 | const writes: Write[] = []; 16 | return getWrites({ chain, timestamp, writes, pricesObject, projectName: 'hlp' }) 17 | } 18 | 19 | export function hlp(timestamp: number = 0) { 20 | return getTokenPrices("arbitrum", timestamp); 21 | } 22 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/jpegd/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": { 3 | "inputs": [], 4 | "name": "token", 5 | "outputs": [ 6 | { 7 | "internalType": "contract ERC20Upgradeable", 8 | "name": "", 9 | "type": "address" 10 | } 11 | ], 12 | "stateMutability": "view", 13 | "type": "function" 14 | }, 15 | "totalAssets": { 16 | "inputs": [], 17 | "name": "totalAssets", 18 | "outputs": [ 19 | { "internalType": "uint256", "name": "assets", "type": "uint256" } 20 | ], 21 | "stateMutability": "view", 22 | "type": "function" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/level-finance/index.ts: -------------------------------------------------------------------------------- 1 | import { config, getTokenPrices} from "./levelFinance"; 2 | 3 | export function levelFinance(timestamp: number = 0) { 4 | return Promise.all(Object.keys(config).map(chain => getTokenPrices(timestamp, chain))) 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/mean-finance/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./mean-finance"; 2 | 3 | export function meanFinance(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices("optimism", timestamp), 6 | getTokenPrices("polygon", timestamp), 7 | getTokenPrices("arbitrum", timestamp), 8 | getTokenPrices("ethereum", timestamp), 9 | getTokenPrices("bsc", timestamp), 10 | getTokenPrices("xdai", timestamp), 11 | getTokenPrices("moonbeam", timestamp), 12 | getTokenPrices("rsk", timestamp), 13 | getTokenPrices("avalanche", timestamp), 14 | getTokenPrices("base", timestamp), 15 | ]); 16 | } 17 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/mean-finance/mean-finance.ts: -------------------------------------------------------------------------------- 1 | import { calculate4626Prices } from "../../utils/erc4626"; 2 | import { fetch } from "../../utils"; 3 | 4 | export default async function getTokenPrices(chain: string, timestamp: number) { 5 | const { transforms }: { transforms: { type: string; dependent: string }[] } = await fetch( 6 | `https://api.balmy.xyz/v1/transforms/networks/${chain}/transforms`, 7 | ); 8 | const tokens4626 = transforms 9 | .filter((t) => t.type === "ERC4626") 10 | .map(({ dependent }) => dependent); 11 | return await unwrap4626(chain, tokens4626, timestamp, "mean-finance"); 12 | } 13 | 14 | export async function unwrap4626( 15 | chain: string, 16 | tokens: string[], 17 | timestamp: number, 18 | adapter: string, 19 | ) { 20 | return calculate4626Prices(chain, timestamp, tokens, adapter) 21 | } 22 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/misc4626/misc.ts: -------------------------------------------------------------------------------- 1 | import { unwrap4626 } from "../mean-finance/mean-finance"; 2 | import tokens from "./tokens.json"; 3 | 4 | export default async function getTokenPrices(chain: string, timestamp: number) { 5 | const tokens4626: string[] = Object.values((tokens as any)[chain]); 6 | return unwrap4626(chain, tokens4626, timestamp, "misc4626"); 7 | } 8 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/misc4626/tokensQiDAO.json: -------------------------------------------------------------------------------- 1 | { 2 | "arbitrum": { 3 | "gDAI": "0x4fc050d75dba5bf2d6ebd3667ffec731a45b1f35", 4 | "mooCurveWSTETH": "0xf05f0e8760ce9a32df05549309ebef7ddb2190fe" 5 | }, 6 | "optimism": { 7 | "wsETH": "0x926b92b15385981416a5e0dcb4f8b31733d598cf", 8 | "Moo Curve wstETH": "0x480798fac621add14113ecc82638305c260ceaf1", 9 | "WETH yVault": "0x22f39d6535df5767f8f57fee3b2f941410773ec4" 10 | }, 11 | "polygon": { 12 | "stMATIC": "0x4c8dfb55d08bd030814cb6fe774420f3c01a5edb", 13 | "wstETH": "0xcc03032fbf096f14a2de8809c79d8b584151212b", 14 | "gDAI": "0x2dea91e68fdc5693b63924c5fee0a28cfb78a801", 15 | "MaticX": "0x2acd702f7d35d3d2915663d7f7cbdf2863ec6e79" 16 | }, 17 | "base": { 18 | "cbETH": "0xc765d6b7ea9d4b9ccd8cbadbb0e4726d68e195e4", 19 | "wsETH": "0x96c8f7d6ea190df5c5ef2ebab6ecd2a86262b810" 20 | }, 21 | "ethereum": { 22 | "stETH": "0x9414e766E8B59473599b9968aAf52CDCd07f59a9" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/ondo/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./ondo"; 2 | 3 | export function ondo(timestamp: number = 0) { 4 | return getTokenPrices(timestamp) 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/quickperps/index.ts: -------------------------------------------------------------------------------- 1 | import { config, getTokenPrices} from "./quickperps"; 2 | 3 | export function quickperps(timestamp: number = 0) { 4 | return Promise.all(Object.keys(config).map(chain => getTokenPrices(timestamp, chain))) 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/tempest/index.ts: -------------------------------------------------------------------------------- 1 | import getTempestTokenPrices from "./tempest"; 2 | 3 | const chains = [ 4 | "ethereum", 5 | "swellchain", 6 | "scroll" 7 | ]; 8 | 9 | export function tempest(timestamp: number = 0) { 10 | return Promise.all( 11 | chains.map((chain) => { 12 | return getTempestTokenPrices(chain, timestamp); 13 | }) 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/timeless/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices, { config } from "./timeless"; 2 | 3 | const chains = Object.keys(config) 4 | 5 | export function timeless(timestamp: number = 0) { 6 | return Promise.all(chains.map(i => getTokenPrices(i, timestamp))) 7 | } 8 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/timeswap/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices, { config } from "./timeswap"; 2 | 3 | export function timeswap(timestamp: number = 0) { 4 | return Promise.all( 5 | Object.keys(config).map((chain: string) => 6 | getTokenPrices(chain, timestamp), 7 | ), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/vela/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalUsd": { 3 | "inputs": [], 4 | "name": "totalUSD", 5 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 6 | "stateMutability": "view", 7 | "type": "function" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/vela/contracts.json: -------------------------------------------------------------------------------- 1 | { 2 | "arbitrum": { 3 | "vault": "0xC4ABADE3a15064F9E3596943c699032748b13352", 4 | "VLP": "0xC5b2D9FDa8A82E8DcECD5e9e6e99b78a9188eB05" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/vesper/index.ts: -------------------------------------------------------------------------------- 1 | import getYieldWrites from "../../utils/yieldTokens"; 2 | import fetch from "node-fetch"; 3 | 4 | const chainIdMap: { [id: number]: string } = { 1: "ethereum" }; 5 | 6 | type Res = { 7 | chainId: number; 8 | address: string; 9 | }; 10 | 11 | export async function vesper(timestamp: number = 0) { 12 | const res: Res[] = await fetch( 13 | `https://api.vesper.finance/pools?stages=prod`, 14 | ).then((r) => r.json()); 15 | 16 | const chainIds: number[] = [...new Set(res.map((p: any) => p.chainId))]; 17 | 18 | return Promise.all( 19 | chainIds.map((id: number) => { 20 | const tokens = res 21 | .filter((p: any) => p.chainId == id) 22 | .map((p: any) => p.address); 23 | 24 | return getYieldWrites({ 25 | chain: chainIdMap[id], 26 | timestamp, 27 | tokens, 28 | priceAbi: "uint256:pricePerShare", 29 | underlyingAbi: "address:token", 30 | projectName: "vesper", 31 | }); 32 | }), 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/yearn/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./yearnV2"; 2 | 3 | export function yearn(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices("ethereum", timestamp), 6 | getTokenPrices("base", timestamp), 7 | getTokenPrices("optimism", timestamp), 8 | ]); 9 | } 10 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/yield-protocol/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "./yield-protocol"; 2 | 3 | export function yieldProtocol(timestamp: number = 0) { 4 | return Promise.all([ 5 | getTokenPrices("arbitrum", timestamp), 6 | getTokenPrices("ethereum", timestamp), 7 | ]); 8 | } 9 | -------------------------------------------------------------------------------- /coins/src/adapters/yield/yield-yak/index.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices, { config } from "./yieldYak"; 2 | 3 | export function yieldYak(timestamp: number = 0) { 4 | return Promise.all(Object.keys(config).map(chain => getTokenPrices(chain, timestamp))); 5 | } 6 | -------------------------------------------------------------------------------- /coins/src/cli/checkWrongBlocks.ts: -------------------------------------------------------------------------------- 1 | import { blockPK } from "../getBlock" 2 | import ddb, { getHistoricalValues } from "../utils/shared/dynamodb" 3 | 4 | const chains = ["ethereum"] 5 | const DRY_RUN:boolean = true 6 | 7 | async function main() { 8 | await Promise.all(chains.map(async chain=>{ 9 | const entries = await getHistoricalValues(blockPK(chain)) 10 | let lastHeight = 0 11 | entries.forEach(entry=>{ 12 | if(entry.height < lastHeight){ 13 | console.log(entry, lastHeight) 14 | if(DRY_RUN === false){ 15 | ddb.delete({ 16 | Key:{ 17 | PK: entry.PK, 18 | SK: entry.SK 19 | } 20 | }) 21 | } 22 | } else { 23 | lastHeight = entry.height 24 | } 25 | }) 26 | })) 27 | } 28 | 29 | main() -------------------------------------------------------------------------------- /coins/src/cli/deleteLatestWritesFromAdapter.ts: -------------------------------------------------------------------------------- 1 | import { stargate } from "../adapters/markets/stargate"; 2 | import { getCurrentUnixTimestamp } from "../utils/date"; 3 | import ddb from "../utils/shared/dynamodb"; 4 | 5 | const secondsToDelete = 4*3600; 6 | 7 | async function main(){ 8 | const writes = await stargate() 9 | const start = getCurrentUnixTimestamp() - secondsToDelete 10 | await Promise.all(writes.flat().map(async coin=>{ 11 | const records = (await ddb.query({ 12 | ExpressionAttributeValues: { 13 | ":pk": coin.PK, 14 | ":sk": start 15 | }, 16 | KeyConditionExpression: "PK = :pk AND SK > :sk", 17 | })).Items 18 | if(records === undefined){ 19 | return 20 | } 21 | await Promise.all(records.map(r=>ddb.delete({ 22 | Key:{ 23 | PK: r.PK, 24 | SK: r.SK 25 | } 26 | }))) 27 | })) 28 | } 29 | main() -------------------------------------------------------------------------------- /coins/src/cli/displayLatestItems.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config() 2 | import ddb from "../utils/shared/dynamodb"; 3 | import adapterResults from "../../adapterResults.json" 4 | 5 | const start = 1660313930 6 | 7 | async function main() { 8 | await Promise.all(Array.from(new Set(adapterResults[0].map(item=>item.PK))).map(async item => { 9 | const lastResults = await ddb 10 | .query({ 11 | ExpressionAttributeValues: { 12 | ":pk": item, 13 | ":start": start, 14 | }, 15 | KeyConditionExpression: `PK = :pk AND SK >= :start`, 16 | //ScanIndexForward: search === "high", 17 | }) 18 | if((lastResults.Items?.length ?? 0)>0){ 19 | console.table(lastResults.Items) 20 | } 21 | })) 22 | } 23 | 24 | main(); 25 | -------------------------------------------------------------------------------- /coins/src/cli/readItem.ts: -------------------------------------------------------------------------------- 1 | import dynamodb from "../utils/shared/dynamodb"; 2 | 3 | async function main(){ 4 | console.log(await dynamodb.get({PK:`asset#${process.argv[2]}`, SK:0})) 5 | } 6 | main() 7 | 8 | // Example: 9 | // tableName='prod-coins-table' AWS_REGION='eu-central-1' npx ts-node src/cli/readItem.ts cardano:fbae99b8679369079a7f6f0da14a2cf1c2d6bfd3afdf3a96a64ab67a0014df1047454e5358 -------------------------------------------------------------------------------- /coins/src/cli/refillAdapter.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config() 2 | import { writeFileSync } from "fs"; 3 | import adapters from "../adapters/index"; 4 | import { batchWrite } from "../utils/shared/dynamodb"; 5 | 6 | const adapterName = "backed"; 7 | const timestamp = +(new Date())/1e3; 8 | 9 | async function main() { 10 | const adapter = adapters[adapterName][adapterName]; 11 | if (adapter === undefined) { 12 | throw new Error(`Adapter "${adapterName}" doesn't exist`) 13 | } 14 | if (process.env.HISTORICAL !== "true") { 15 | throw new Error("You must set env variable HISTORICAL to 'true'") 16 | } 17 | 18 | const results: any[] = await adapter(timestamp); 19 | writeFileSync("adapterResults.json", JSON.stringify(results)) 20 | await batchWrite(results.flat(), true); 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /coins/src/cli/storeBridgedCoins.ts: -------------------------------------------------------------------------------- 1 | import handler from "../storeBridgedCoins" 2 | 3 | handler() -------------------------------------------------------------------------------- /coins/src/cli/test.ts: -------------------------------------------------------------------------------- 1 | import getTokenPrices from "../adapters/moneyMarkets/compound/compound"; 2 | const lastWeek = 1658357999; 3 | async function main() { 4 | await getTokenPrices( 5 | "ethereum", 6 | "0x3d9819210a31b4961b30ef54be2aed79b9c9cd3b", 7 | lastWeek 8 | ); 9 | // "bsc", 10 | // "0xca143ce32fe78f1f7019d7d551a6402fc5350c73", 11 | // "https://bsc.streamingfast.io/subgraphs/name/pancakeswap/exchange-v2" 12 | } 13 | main(); 14 | 15 | // ts-node coins/src/cli/test.ts 16 | -------------------------------------------------------------------------------- /coins/src/cli/writeItem.ts: -------------------------------------------------------------------------------- 1 | import dynamodb from "../utils/shared/dynamodb"; 2 | 3 | async function main() { 4 | await dynamodb.put({ 5 | PK: `asset#cardano:fbae99b8679369079a7f6f0da14a2cf1c2d6bfd3afdf3a96a64ab67a0014df1047454e5358`, 6 | SK: 0, 7 | symbol: 'GENSX', 8 | created: 1690064168, 9 | confidence: 0.99, 10 | decimals: 6, 11 | redirect: 'coingecko#genius-x', 12 | }) 13 | } 14 | main() 15 | 16 | // Example: 17 | // tableName='prod-coins-table' AWS_REGION='eu-central-1' npx ts-node src/cli/writeItem.ts -------------------------------------------------------------------------------- /coins/src/cli/writeOverwrites.ts: -------------------------------------------------------------------------------- 1 | import { overwrites } from '../adapters/bridges/overwrites' 2 | import { batchWrite } from '../utils/shared/dynamodb' 3 | 4 | async function main() { 5 | await batchWrite(overwrites, true) 6 | } 7 | main() -------------------------------------------------------------------------------- /coins/src/corsPreflight.ts: -------------------------------------------------------------------------------- 1 | ../../defi/src/corsPreflight.ts -------------------------------------------------------------------------------- /coins/src/fallback.test.ts: -------------------------------------------------------------------------------- 1 | ../../defi/src/fallback.test.ts -------------------------------------------------------------------------------- /coins/src/fallback.ts: -------------------------------------------------------------------------------- 1 | ../../defi/src/fallback.ts -------------------------------------------------------------------------------- /coins/src/getCoins.test.ts: -------------------------------------------------------------------------------- 1 | 2 | import fetch from "node-fetch"; 3 | import handler from "./getCoins"; 4 | 5 | describe("snapshot of error provided", () => { 6 | it("executes as expected", async () => { 7 | const body = JSON.stringify({ 8 | "coins": [ 9 | "ethereum:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 10 | "avax:0x9e295b5b976a184b14ad8cd72413ad846c299660", 11 | "bsc:0x0cf8e180350253271f4b917ccfb0accc4862f262", 12 | "solana:3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh", 13 | "dogechain:0xfea7a6a0b346362bf88a9e4a88416b77a57d6c2a", 14 | "avax:0xfea7976733f47557860f4483f2147a3e99c76b58", 15 | "bsc:0x385ff2b2fc61164604c5bdc708ccff611fe9c42d" 16 | ] 17 | }) 18 | const response = JSON.parse(((await handler({body} as any)) as any).body) 19 | expect(response).toEqual(await fetch(`https://coins.llama.fi/prices`, { 20 | method: "POST", 21 | body 22 | }).then(r=>r.json())); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /coins/src/listCoins.ts: -------------------------------------------------------------------------------- 1 | import { DocumentClient } from "aws-sdk/clients/dynamodb"; 2 | import fs from "fs"; 3 | import path from "path"; 4 | import { getCurrentUnixTimestamp } from "./utils/date"; 5 | const file = path.resolve(__dirname, "./coinRepository.json"); 6 | 7 | export async function storePks( 8 | results: DocumentClient.PutItemInputAttributeMap[] 9 | ) { 10 | let repo = JSON.parse(fs.readFileSync(file).toString()); 11 | results 12 | .filter((r: any) => r.SK != 0) 13 | .map((r: any) => { 14 | repo[r.PK] = r.SK; 15 | }); 16 | fs.writeFileSync(file, JSON.stringify(repo)); 17 | } 18 | 19 | export async function checkOutdated(hours: number = 2) { 20 | const timeNow = getCurrentUnixTimestamp(); 21 | const repo = JSON.parse(fs.readFileSync(file).toString()); 22 | let outDatedList: string[] = []; 23 | Object.entries(repo).map((c: any) => { 24 | if (c[1] < timeNow - 3600 * hours) { 25 | outDatedList.push(`${c[0]} since ${c[1]}`); 26 | } 27 | }); 28 | console.log(outDatedList); 29 | } 30 | -------------------------------------------------------------------------------- /coins/src/scripts/bridges.ts: -------------------------------------------------------------------------------- 1 | import { storeTokens } from "../adapters/bridges"; 2 | import { storeR2JSONString } from "../utils/r2"; 3 | 4 | async function bridges() { 5 | process.env.tableName = "prod-coins-table"; 6 | const bridgedTokens = await storeTokens(); 7 | await storeR2JSONString( 8 | `bridgedTokens.json`, 9 | JSON.stringify(bridgedTokens), 10 | 60 * 60, 11 | ); 12 | process.exit(); 13 | } 14 | bridges(); // ts-node src/scripts/bridges.ts 15 | -------------------------------------------------------------------------------- /coins/src/scripts/test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | batchWrite2WithAlerts, 3 | batchWriteWithAlerts, 4 | } from "../adapters/utils/database"; 5 | import { getCurrentUnixTimestamp } from "../utils/date"; 6 | 7 | export default async function test() { 8 | try { 9 | const result = [ 10 | { 11 | PK: "runner.test", 12 | SK: getCurrentUnixTimestamp(), 13 | price: 0, 14 | timestamp: 0, 15 | Symbol: "", 16 | confidence: 0, 17 | }, 18 | { 19 | PK: "runner.test", 20 | SK: 0, 21 | price: 0, 22 | timestamp: 0, 23 | Symbol: "", 24 | confidence: 0, 25 | }, 26 | ]; 27 | 28 | await Promise.all([ 29 | batchWriteWithAlerts(result, true), 30 | batchWrite2WithAlerts(result), 31 | ]); 32 | console.log(`test runner done`); 33 | } catch (e) { 34 | console.error(`test runner failed ${e}`); 35 | } 36 | console.log("connections closed"); 37 | process.exit(0); 38 | } 39 | test(); 40 | // ts-node src/scripts/test.ts 41 | -------------------------------------------------------------------------------- /coins/src/storeBridgedCoins.ts: -------------------------------------------------------------------------------- 1 | import { storeTokens } from "./adapters/bridges"; 2 | import { storeR2JSONString } from "./utils/r2"; 3 | 4 | export default async function handler() { 5 | const bridgedTokens = await storeTokens() 6 | await storeR2JSONString(`bridgedTokens.json`, JSON.stringify(bridgedTokens), 60 * 60); 7 | } 8 | -------------------------------------------------------------------------------- /coins/src/triggerFetchCoingeckoData.ts: -------------------------------------------------------------------------------- 1 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 2 | import fetch from "node-fetch"; 3 | import invokeLambda from "./utils/shared/invokeLambda"; 4 | import { shuffleArray } from "./utils/shared/shuffleArray"; 5 | 6 | const hourlyLambda = `coins-prod-fetchHourlyCoingeckoData`; 7 | const step = 500; 8 | const handler = (lambdaFunctioName: string) => async () => { 9 | const coins = await fetch( 10 | `https://pro-api.coingecko.com/api/v3/coins/list?include_platform=true&x_cg_pro_api_key=${process.env.CG_KEY}`, 11 | ).then((r) => r.json()); 12 | shuffleArray(coins) 13 | for (let i = 0; i < coins.length; i += step) { 14 | const event = { 15 | coins: coins.slice(i, i + step), 16 | depth: 0, 17 | }; 18 | await invokeLambda(lambdaFunctioName, event); 19 | } 20 | }; 21 | 22 | export const triggerNewFetches = wrapScheduledLambda( 23 | handler(`coins-prod-fetchCoingeckoData2`), 24 | ); 25 | export const triggerHourlyFetches = wrapScheduledLambda(handler(hourlyLambda)); 26 | -------------------------------------------------------------------------------- /coins/src/utils/coingeckoPlatforms.test.ts: -------------------------------------------------------------------------------- 1 | ../../../defi/src/utils/coingeckoPlatforms.test.ts -------------------------------------------------------------------------------- /coins/src/utils/coins3/cli/consume.ts: -------------------------------------------------------------------------------- 1 | import { topics } from "../jsonValidation"; 2 | import { getConsumer } from "../kafka"; 3 | 4 | const run = async () => { 5 | await Promise.all( 6 | topics.map(async (topic) => { 7 | const consumer = await getConsumer(topic); 8 | await consumer.subscribe({ topic, fromBeginning: true }); 9 | 10 | await consumer.run({ 11 | eachMessage: async ({ topic, partition, message }: any) => { 12 | console.log({ 13 | topic, 14 | partition, 15 | offset: message.offset, 16 | value: message.value.toString(), 17 | }); 18 | }, 19 | }); 20 | }), 21 | ); 22 | }; 23 | 24 | run().catch(console.error); 25 | // ts-node coins/src/utils/coins3/cli/consume.ts 26 | -------------------------------------------------------------------------------- /coins/src/utils/coins3/cli/newTopic.ts: -------------------------------------------------------------------------------- 1 | import { getKafka } from "../kafka"; 2 | 3 | const createTopic = async () => { 4 | const kafka = getKafka(); 5 | const admin = kafka.admin(); 6 | await admin.connect(); 7 | 8 | // Create a topic 9 | await admin.createTopics({ 10 | topics: [ 11 | { 12 | topic: "current", // Replace with your topic name 13 | numPartitions: 1, // Number of partitions 14 | replicationFactor: 1, // Replication factor 15 | }, 16 | ], 17 | }); 18 | 19 | console.log("Topic created successfully"); 20 | 21 | // Disconnect the admin client 22 | await admin.disconnect(); 23 | }; 24 | 25 | createTopic().catch(console.error); 26 | // ts-node coins/src/utils/coins3/cli/newTopic.ts 27 | -------------------------------------------------------------------------------- /coins/src/utils/coins3/redis.ts: -------------------------------------------------------------------------------- 1 | import Redis, { Redis as RedisClient } from "ioredis"; 2 | 3 | let redisClient: RedisClient; 4 | 5 | export function getRedis(): RedisClient { 6 | if (!redisClient) { 7 | const redisConfig = process.env.REDIS_CLIENT_CONFIG; 8 | if (!redisConfig) { 9 | throw new Error("Missing REDIS_CLIENT_CONFIG"); 10 | } 11 | const [host, port, password] = redisConfig.split("---"); 12 | redisClient = new Redis({ 13 | host, 14 | port: Number(port), 15 | password 16 | }); 17 | } 18 | 19 | return redisClient; 20 | } -------------------------------------------------------------------------------- /coins/src/utils/coins3/utils.ts: -------------------------------------------------------------------------------- 1 | export function normalizeCoinId(coinId: string): string { 2 | coinId = coinId.toLowerCase(); 3 | const replaceSubStrings = ["asset#", "coingecko#", "coingecko:", "ethereum:"]; 4 | const replaceSubStringLengths = replaceSubStrings.map((str) => str.length); 5 | 6 | for (let i = 0; i < replaceSubStrings.length; i++) { 7 | const subStr = replaceSubStrings[i]; 8 | const subStrLength = replaceSubStringLengths[i]; 9 | if (coinId.startsWith(subStr)) { 10 | coinId = coinId.slice(subStrLength); 11 | } 12 | } 13 | coinId = coinId.replace(/\//g, ":"); 14 | if (coinId.length === 75 && coinId.startsWith('starknet:')) 15 | coinId = coinId.replace('0x0', '0x') 16 | return coinId; 17 | } 18 | -------------------------------------------------------------------------------- /coins/src/utils/date.ts: -------------------------------------------------------------------------------- 1 | export function toUNIXTimestamp(ms: number) { 2 | return Math.round(ms / 1000); 3 | } 4 | 5 | export function getCurrentUnixTimestamp() { 6 | return toUNIXTimestamp(Date.now()); 7 | } 8 | -------------------------------------------------------------------------------- /coins/src/utils/keys.ts: -------------------------------------------------------------------------------- 1 | export function cgPK(cgId: string) { 2 | return `coingecko#${cgId}`; 3 | } -------------------------------------------------------------------------------- /coins/src/utils/r2.ts: -------------------------------------------------------------------------------- 1 | ../../../defi/src/utils/r2.ts -------------------------------------------------------------------------------- /coins/src/utils/shared: -------------------------------------------------------------------------------- 1 | ../../../defi/src/utils/shared/ -------------------------------------------------------------------------------- /coins/tsconfig.json: -------------------------------------------------------------------------------- 1 | ../defi/tsconfig.json -------------------------------------------------------------------------------- /defi/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "14" 8 | } 9 | } 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /defi/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .webpack 3 | .env 4 | .serverless 5 | imported-db 6 | docker 7 | .DS_Store 8 | .esbuild 9 | src/utils/imports/adapters.ts 10 | src/utils/imports/tvlAdapterData.json 11 | src/utils/imports/adapters_volumes.ts 12 | src/utils/imports/adapters_fees.ts 13 | src/utils/imports/aggregator-derivatives_adapters.ts 14 | src/utils/imports/adapters_liquidations.ts 15 | src/utils/imports/fees_adapters.ts 16 | src/utils/imports/dexs_adapters.ts 17 | src/utils/imports/options_adapters.ts 18 | src/utils/imports/aggregators_adapters.ts 19 | src/utils/imports/incentives_adapters.ts 20 | src/utils/imports/protocols_adapters.ts 21 | src/utils/imports/emissions_adapters.ts 22 | src/utils/imports/bridge-aggregators_adapters.ts 23 | src/emissions/utils/*.png 24 | .vscode 25 | src/dexVolumes/cli/backfillUtilities/output 26 | src/adaptors/cli/*/output 27 | src/api2/metadata.json 28 | .cache 29 | src/api2/.api2-cache -------------------------------------------------------------------------------- /defi/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "quoteProps": "consistent", 3 | "printWidth": 120, 4 | "tabWidth": 2 5 | } 6 | -------------------------------------------------------------------------------- /defi/dev-metrics/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | users: ['ZunamiProtocol', 'planetfinance', 'polycatfi', 'UniWswap', 'LfgSwap', 'forgesx', 'MaiaDao', 'cr3k', 'ThenafiBNB'], 3 | blacklistedOrgs: [], 4 | blacklistedRepoMapping: { 5 | 'KyberNetwork': ['KyberNetwork.github.io'], 6 | 'ethereum': ['solc-bin', 'discv4-dns-lists'], 7 | } 8 | } -------------------------------------------------------------------------------- /defi/dev-metrics/db-scripts/queries.js: -------------------------------------------------------------------------------- 1 | 2 | const TABLES = { 3 | devAgg: 'view_agg_dev_monthly_commits', 4 | contributersAgg: 'view_agg_contributer_monthly_commits', 5 | } 6 | 7 | const owner_query_contributers = `SELECT 8 | commit_month, 9 | COUNT(DISTINCT developer) AS developer_count 10 | FROM ${TABLES.contributersAgg} 11 | WHERE 12 | (:orgs IS NULL OR owner IN (:orgs)) 13 | AND (:repos IS NULL OR repo IN (:repos)) 14 | GROUP BY 15 | commit_month 16 | ORDER BY 17 | commit_month ASC;` 18 | 19 | const owner_query = `SELECT 20 | commit_month, 21 | COUNT(DISTINCT developer) AS developer_count 22 | FROM ${TABLES.devAgg} 23 | WHERE 24 | (:orgs IS NULL OR owner IN (:orgs)) 25 | AND (:repos IS NULL OR repo IN (:repos)) 26 | GROUP BY 27 | commit_month 28 | ORDER BY 29 | commit_month ASC;` 30 | 31 | module.exports = { 32 | TABLES, 33 | owner_query, 34 | owner_query_contributers, 35 | } -------------------------------------------------------------------------------- /defi/dev-metrics/env.js: -------------------------------------------------------------------------------- 1 | const ENV = process.env 2 | 3 | module.exports = { 4 | db_name: ENV.DEV_METRICS_DB_NAME, 5 | host: ENV.DEV_METRICS_DB_HOST, 6 | port: ENV.DEV_METRICS_DB_PORT, 7 | user: ENV.DEV_METRICS_DB_USERNAME, 8 | password: ENV.DEV_METRICS_DB_PASSWORD, 9 | R2_ENDPOINT: ENV.R2_ENDPOINT, 10 | R2_ACCESS_KEY_ID: ENV.R2_ACCESS_KEY_ID, 11 | R2_SECRET_ACCESS_KEY: ENV.R2_SECRET_ACCESS_KEY, 12 | GITHUB_API_KEY: ENV.GITHUB_API_KEY, 13 | } -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/addLogsToDB.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | script_dir="$(dirname "$(readlink -f "$0")")" 4 | root_dir="$(dirname "$script_dir")" 5 | 6 | function printTitle() { 7 | echo "" 8 | echo "=======================" 9 | echo $1 10 | echo "=======================" 11 | echo "" 12 | } 13 | 14 | 15 | printTitle "Installing dependencies (parent folder)..." 16 | cd $root_dir/.. 17 | # time npm i 18 | 19 | printTitle "Installing dependencies..." 20 | cd $root_dir 21 | # time npm i 22 | 23 | printTitle "Updating dev mapping from our data.ts files" 24 | time npx ts-node updateDevMapping.ts 25 | 26 | printTitle "download toml file data from electric-capital repo" 27 | # time node $script_dir/createMappingFromElectricRepo.js 28 | # time node $script_dir/downloadTomlFile.js 29 | 30 | printTitle "Update org/repo details in DB" 31 | time node $script_dir/updateOrgAndRepoInfo.js 32 | 33 | printTitle "Pull event logs from git archive" 34 | # time node $script_dir/addArchives.js 35 | -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/downloadTomlFile.js: -------------------------------------------------------------------------------- 1 | const cache = require('../utils/cache') 2 | const { getTomlFile } = require('../utils/r2') 3 | 4 | cache.clearTempFolders() 5 | 6 | async function main() { 7 | const tomlFile = await getTomlFile() 8 | cache.writeJSON('tomlData.json', tomlFile, { compressed: false }) 9 | process.exit(0) 10 | } 11 | 12 | main() 13 | -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/pullTwitterDataLocally.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process'); 2 | 3 | let isRunning = false; 4 | 5 | function runCommand() { 6 | if (!isRunning) { 7 | isRunning = true; 8 | const start = +new Date() 9 | const bash_script = ` 10 | cd ${__dirname}/.. 11 | npm run update-dev-mapping 12 | npm run update-twitter 13 | ` 14 | console.log('Start pulling data'); 15 | const childProcess = spawn('bash', ['-c', bash_script], { stdio: 'inherit' }); 16 | 17 | childProcess.on('close', (code) => { 18 | const runTime = ((+(new Date) - start) / 1e3).toFixed(1) 19 | console.log(`[Done] runtime: ${runTime}s `) 20 | isRunning = false; 21 | }) 22 | 23 | } 24 | } 25 | 26 | // Initial run 27 | runCommand(); 28 | 29 | // Schedule the command to run every 30 minutes 30 | const interval = 2 * 60 * 60 * 1000; // 30 minutes in milliseconds - assuming the IP is ratelimited for 30 minutes 31 | setInterval(runCommand, interval); 32 | -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/temp/bashLoop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | script_dir="$(dirname "$(readlink -f "$0")")" 4 | 5 | echo "Script directory: $script_dir" 6 | 7 | while true; do 8 | # Run your process in the background 9 | echo "Running process..." 10 | # Replace the command below with your actual process 11 | # Example: ./your_process.sh & 12 | node $script_dir/addArchives.js & 13 | 14 | # Sleep for 12 minutes 15 | sleep 720 16 | 17 | # Kill the running process 18 | echo "Stopping process..." 19 | pkill -f addArchives 20 | 21 | # Sleep for 4 minutes 22 | sleep 240 23 | done 24 | -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/temp/deleteOrgsAndRepos.js: -------------------------------------------------------------------------------- 1 | const { ORGS_MISSING_FROM_TOML } = require('../../utils/index') 2 | const { GitOwner, GitRepo, sequelize, } = require('../../db') 3 | 4 | async function main() { 5 | await sequelize.sync() 6 | console.log('org length: ', ORGS_MISSING_FROM_TOML.length) 7 | return deleteGitOwnerWithRepos(ORGS_MISSING_FROM_TOML) 8 | } 9 | 10 | const deleteGitOwnerWithRepos = async (ownerNames) => { 11 | try { 12 | // Delete GitRepos associated with the given owner names 13 | await GitRepo.destroy({ 14 | where: { 15 | owner: ownerNames, 16 | }, 17 | }); 18 | 19 | // Delete GitOwners based on the owner names 20 | await GitOwner.destroy({ 21 | where: { 22 | name: ownerNames, 23 | }, 24 | }); 25 | 26 | console.log('Deletion successful'); 27 | } catch (error) { 28 | console.error('Deletion failed:', error); 29 | } 30 | } 31 | // Call the function with the URL of the json.tz file 32 | main() 33 | .catch(console.error) 34 | .then(() => sequelize.close()) 35 | .then(() => process.exit(0)) 36 | -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/temp/testDBConnection.js: -------------------------------------------------------------------------------- 1 | const { GitOwner, GitRepo, sequelize, addRawCommit, } = require('../../db') 2 | 3 | async function main() { 4 | await sequelize.sync() 5 | const testOrg = await GitOwner.findOne({ where: { name: 'DefiLlama' } }) 6 | console.log(testOrg) 7 | process.exit(0) 8 | 9 | } 10 | 11 | 12 | main() 13 | -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/temp/testDBQuery.js: -------------------------------------------------------------------------------- 1 | const { getOrgMonthyAggregation, getOrgContributersMonthyAggregation} = require('../db') 2 | 3 | async function run() { 4 | const org = 'ethereum' 5 | const orgMonthlyAgg = await getOrgMonthyAggregation(org) 6 | const orgContributersMonthlyAgg = await getOrgContributersMonthyAggregation(org) 7 | console.log({orgMonthlyAgg, orgContributersMonthlyAgg}) 8 | } 9 | 10 | run().catch(console.error).then(process.exit) -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/temp/testInsertDataToDB.js: -------------------------------------------------------------------------------- 1 | const { addArchive } = require('../utils/archive') 2 | const { sequelize } = require('../db') 3 | 4 | const archive_file = '2022-04-03-11' 5 | 6 | async function main() { 7 | await sequelize.sync() 8 | 9 | await addArchive(archive_file) 10 | sequelize.close() 11 | } 12 | 13 | // Call the function with the URL of the json.tz file 14 | main().then(() => process.exit(0)).catch(console.error) 15 | -------------------------------------------------------------------------------- /defi/dev-metrics/scripts/temp/unzip.js: -------------------------------------------------------------------------------- 1 | const org = 'ethereum' 2 | const repo = 'go-ethereum' 3 | 4 | 5 | 6 | const cache = require('../cache') 7 | const { turnToElasticLog } = require('../../utils') 8 | const orgData = cache.getOrgDataFile(org) 9 | const repoData = Object.values(orgData.repos).find(i => i.name === repo) 10 | const logs = cache.getRepoLogFile(org, repo) 11 | // const logsLog = cache.getRepoLogFile(org, repo, false) 12 | const elasticLog = logs.logs.map(i => turnToElasticLog({log: i, repoData, orgName: org})).filter(i => !i.message.startsWith('Merge pull request #')) 13 | console.log(logs.logs.length, elasticLog.length) 14 | // console.log(logs) 15 | cache.writeJSON('temp/org-'+org, orgData, { compressed: false }) 16 | cache.writeJSON('temp/repo-raw-'+repo, logs, { compressed: false }) 17 | // cache.writeJSON('temp/repo-'+repo, repoDataLog, { compressed: false }) 18 | cache.writeJSON('temp/repo-elastic-'+repo, elasticLog, { compressed: false }) -------------------------------------------------------------------------------- /defi/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | dynamodb-local: 4 | command: "-jar DynamoDBLocal.jar -sharedDb -optimizeDbBeforeStartup -dbPath ./data" 5 | image: "amazon/dynamodb-local:latest" 6 | container_name: dynamodb-local 7 | ports: 8 | - "8000:8000" 9 | volumes: 10 | - "./docker/dynamodb:/home/dynamodblocal/data" 11 | working_dir: /home/dynamodblocal 12 | -------------------------------------------------------------------------------- /defi/jest.config.js: -------------------------------------------------------------------------------- 1 | 2 | // Jest config 3 | module.exports = { 4 | roots: ['/src'], 5 | testRegex: '(.*\\.test\\.(tsx?|jsx?))$', 6 | transform: { 7 | '^.+\\.ts$': 'ts-jest', 8 | '^.+\\.js$': 'babel-jest', 9 | }, 10 | // preset: "jest-dynalite", 11 | moduleFileExtensions: ['ts', 'js', 'json', 'node'], 12 | transformIgnorePatterns: [ 13 | '/node_modules/(?!@polkadot|@babel/runtime/helpers/esm/)' 14 | ], 15 | testPathIgnorePatterns: ["src/adaptorsImprov", "src/adaptors"], 16 | detectOpenHandles: true, 17 | forceExit: true, 18 | maxWorkers: 1, 19 | ci: false, 20 | cacheDirectory: '/tmp/jest-cache', 21 | testEnvironment: "node", 22 | globals: { 23 | "ts-jest": { 24 | transpileOnly: true, 25 | isolatedModules: true, 26 | diagnostics: false, 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /defi/l2/adapters/ada.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | 3 | export async function fetchAdaTokens(): Promise { 4 | const res = await fetch(`https://api.muesliswap.com/token-list`).then((r) => r.json()); 5 | const coins = res 6 | .filter((c: any) => c.supply.circulating != null) 7 | .map((c: any) => ({ 8 | supply: c.supply.circulating, 9 | symbol: c.symbol, 10 | decimals: c.decimalPlaces, 11 | address: c.address.policyId, 12 | })); 13 | 14 | return coins.map((c: any) => `cardano:${c.address}`); 15 | } 16 | -------------------------------------------------------------------------------- /defi/l2/cli/findGoodChains.ts: -------------------------------------------------------------------------------- 1 | import { allChainKeys } from "../constants"; 2 | import fetch from "node-fetch"; 3 | import { getChainDisplayName } from "../../src/utils/normalizeChain"; 4 | 5 | async function main() { 6 | const allChains: { name: string; tvl: number }[] = await fetch("https://api.llama.fi/v2/chains").then((r) => 7 | r.json() 8 | ); 9 | const supportedChainDisplayNames: { [displayName: string]: string } = {}; 10 | allChainKeys.map((c) => { 11 | supportedChainDisplayNames[getChainDisplayName(c, true)] = c; 12 | }); 13 | 14 | const missingChains: { name: string; tvl: number }[] = []; 15 | allChains.map(({ name, tvl }) => { 16 | if (Object.keys(supportedChainDisplayNames).includes(name)) return; 17 | const tvlInMillions = Number((tvl / 1e6).toFixed(0)); 18 | missingChains.push({ name, tvl: tvlInMillions }); 19 | }); 20 | 21 | missingChains.sort((a, b) => b.tvl - a.tvl); 22 | console.log(missingChains.slice(0, 10)); 23 | } 24 | main(); // ts-node defi/l2/cli/findGoodChains.ts 25 | -------------------------------------------------------------------------------- /defi/l2/index.ts: -------------------------------------------------------------------------------- 1 | import chainAssets from "../l2/tvl"; 2 | import { storeR2JSONString } from "../src/utils/r2"; 3 | import { getCurrentUnixTimestamp } from "../src/utils/date"; 4 | import storeHistorical from "../l2/storeToDb"; 5 | // import setEnvSecrets from "./utils/shared/setEnvSecrets"; 6 | 7 | export default async function storeChainAssets(override: boolean) { 8 | // await setEnvSecrets(); 9 | const res: any = await chainAssets(override); 10 | res.timestamp = getCurrentUnixTimestamp(); 11 | // let a = JSON.stringify(res); 12 | // let b = JSON.parse(a); 13 | await storeR2JSONString("chainAssets", JSON.stringify(res)); 14 | await storeHistorical(res); 15 | console.log("chain assets stored"); 16 | process.exit(); 17 | } 18 | -------------------------------------------------------------------------------- /defi/l2/metadata.ts: -------------------------------------------------------------------------------- 1 | import { Chain } from "@defillama/sdk/build/general"; 2 | 3 | export async function fetchMetadata(chain: Chain) { 4 | return { chain }; 5 | } 6 | -------------------------------------------------------------------------------- /defi/resources/api-gateway-errors.yml: -------------------------------------------------------------------------------- 1 | Resources: 2 | GatewayResponseDefault4XX: 3 | Type: 'AWS::ApiGateway::GatewayResponse' 4 | Properties: 5 | ResponseParameters: 6 | gatewayresponse.header.Access-Control-Allow-Origin: "'*'" 7 | gatewayresponse.header.Access-Control-Allow-Headers: "'*'" 8 | ResponseType: DEFAULT_4XX 9 | RestApiId: 10 | Ref: 'ApiGatewayRestApi' 11 | GatewayResponseDefault5XX: 12 | Type: 'AWS::ApiGateway::GatewayResponse' 13 | Properties: 14 | ResponseParameters: 15 | gatewayresponse.header.Access-Control-Allow-Origin: "'*'" 16 | gatewayresponse.header.Access-Control-Allow-Headers: "'*'" 17 | ResponseType: DEFAULT_5XX 18 | RestApiId: 19 | Ref: 'ApiGatewayRestApi' 20 | -------------------------------------------------------------------------------- /defi/resources/dynamodb-table.yml: -------------------------------------------------------------------------------- 1 | Resources: 2 | DynamoTable: 3 | Type: AWS::DynamoDB::Table 4 | DeletionPolicy: Retain # Make sure the tables can't be deleted by CloudFormation/Serverless 5 | Properties: 6 | TableName: ${self:custom.tableName} 7 | AttributeDefinitions: 8 | - AttributeName: PK 9 | AttributeType: S 10 | - AttributeName: SK 11 | AttributeType: N 12 | KeySchema: 13 | - AttributeName: PK 14 | KeyType: HASH 15 | - AttributeName: SK 16 | KeyType: RANGE 17 | # Set the capacity to auto-scale 18 | BillingMode: PAY_PER_REQUEST 19 | -------------------------------------------------------------------------------- /defi/src/__mocks__/@sentry/serverless.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | const AWSLambda = { 3 | init: () => {}, 4 | wrapHandler: (f: Function) => f, 5 | captureException() {}, 6 | }; 7 | 8 | export { AWSLambda }; 9 | -------------------------------------------------------------------------------- /defi/src/__mocks__/@sentry/tracing.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | function addExtensionMethods() {} 3 | 4 | export { addExtensionMethods }; 5 | -------------------------------------------------------------------------------- /defi/src/__snapshots__/fallback.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`snapshot of error provided executes as expected 1`] = ` 4 | Object { 5 | "body": "{\\"message\\":\\"This endpoint doesn't exist\\"}", 6 | "headers": Object { 7 | "Access-Control-Allow-Credentials": "true", 8 | "Access-Control-Allow-Origin": "*", 9 | "Content-Type": "application/json", 10 | }, 11 | "statusCode": 400, 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /defi/src/adaptors/cli/backfillUtilities/auto.ts: -------------------------------------------------------------------------------- 1 | import "../setup" 2 | import { autoBackfill } from "./backfillFunction" 3 | 4 | (async () => { 5 | try{ 6 | await autoBackfill(process.argv) 7 | } catch(e){ 8 | console.log(e) 9 | process.exit(0) 10 | } 11 | })() -------------------------------------------------------------------------------- /defi/src/adaptors/cli/backfillUtilities/dataset/pancake-v1.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefiLlama/defillama-server/2c08af5d517e7f56965ba85d372cc484dab93d8c/defi/src/adaptors/cli/backfillUtilities/dataset/pancake-v1.ods -------------------------------------------------------------------------------- /defi/src/adaptors/cli/backfillUtilities/index.ts: -------------------------------------------------------------------------------- 1 | import { AdapterType } from "@defillama/dimension-adapters/adapters/types" 2 | import "../setup.ts" 3 | import executeAsyncBackfill from "./executeAsyncBackfill" 4 | import getBackfillEvent from "./getBackfillEvent" 5 | /* import printDexsList from "./printDexsList" */ 6 | 7 | enum RUNS { 8 | PRINT_DEXS_LIST, 9 | GET_BACKFILL_EVENT, 10 | EXECUTE_ASYNC_BACKFILL 11 | } 12 | 13 | const RUN: RUNS = RUNS.EXECUTE_ASYNC_BACKFILL 14 | 15 | switch (Number(RUN)) { 16 | case RUNS.PRINT_DEXS_LIST: 17 | /* printDexsList() */ 18 | break 19 | case RUNS.GET_BACKFILL_EVENT: 20 | // Make sure to edit based on your needs! 21 | getBackfillEvent("uniswap" , AdapterType.DEXS, true) 22 | break 23 | case RUNS.EXECUTE_ASYNC_BACKFILL: 24 | executeAsyncBackfill() 25 | break 26 | default: 27 | console.log("No case") 28 | break 29 | } -------------------------------------------------------------------------------- /defi/src/adaptors/cli/checkNonEnabledDexs.ts: -------------------------------------------------------------------------------- 1 | import config from "../../adaptors/data/fees/config"; 2 | import config_new from "../data/fees/config"; 3 | 4 | const moduleKeys_old = Object.keys(config) 5 | const modules_new = Object.keys(config_new) 6 | 7 | console.log("Adapters NOT included") 8 | moduleKeys_old.forEach(adapter => { 9 | if (!modules_new.includes(adapter)) 10 | console.log(adapter) 11 | }) 12 | -------------------------------------------------------------------------------- /defi/src/adaptors/cli/others/removeAdaptorData.ts: -------------------------------------------------------------------------------- 1 | import "../setup.ts" 2 | import { removeAdaptorRecord, AdaptorRecordType } from "../../db-utils/adaptor-record" 3 | import { ProtocolType } from "@defillama/dimension-adapters/adapters/types" 4 | 5 | (async () => { 6 | console.log("Removing...") 7 | const ok = await Promise.all([ 8 | await removeAdaptorRecord("146", AdaptorRecordType.dailyFees, ProtocolType.PROTOCOL), 9 | await removeAdaptorRecord("146", AdaptorRecordType.dailyRevenue, ProtocolType.PROTOCOL), 10 | await removeAdaptorRecord("146", AdaptorRecordType.totalFees, ProtocolType.PROTOCOL), 11 | await removeAdaptorRecord("146", AdaptorRecordType.totalRevenue, ProtocolType.PROTOCOL) 12 | ]) 13 | console.log(ok) 14 | })() 15 | -------------------------------------------------------------------------------- /defi/src/adaptors/cli/others/replaceAdaptorId.ts: -------------------------------------------------------------------------------- 1 | import "../setup.ts" 2 | import { removeAdaptorRecord, AdaptorRecordType, getAdaptorRecord, storeAdaptorRecord } from "../../db-utils/adaptor-record" 3 | import { ProtocolType } from "@defillama/dimension-adapters/adapters/types" 4 | 5 | 6 | (async () => { 7 | const eventTimestamp = Math.trunc(Date.now()/1000) 8 | const currentID = "506" 9 | const newID = "2203" 10 | const ok = await Promise.all(Object.values(AdaptorRecordType).map(async (recordType)=>{ 11 | const dailyRecords = await getAdaptorRecord(currentID, recordType, ProtocolType.PROTOCOL) 12 | if (!(dailyRecords instanceof Array)) throw new Error("Wrong query") 13 | for (const record of dailyRecords) { 14 | record.adaptorId = newID 15 | await storeAdaptorRecord(record, eventTimestamp) 16 | } 17 | await removeAdaptorRecord(currentID, recordType, ProtocolType.PROTOCOL) 18 | })) 19 | console.log(ok) 20 | })() 21 | -------------------------------------------------------------------------------- /defi/src/adaptors/cli/runCachedRes.ts: -------------------------------------------------------------------------------- 1 | import { handler as externalEndpointsCache, cacheExternalResponseHandler } from "../../externalEndpointsCache"; 2 | 3 | 4 | (async () => { 5 | const url = "https://api.coingecko.com/api/v3/exchanges?per_page=250" 6 | const res = await externalEndpointsCache({ 7 | queryStringParameters: { 8 | url: encodeURIComponent(url) 9 | } 10 | } as any) 11 | 12 | console.log("res", res) 13 | console.log(await cacheExternalResponseHandler({ 14 | url: encodeURIComponent(url) 15 | })) 16 | })() -------------------------------------------------------------------------------- /defi/src/adaptors/cli/runGetProtocolSummary.ts: -------------------------------------------------------------------------------- 1 | import "./setup.ts" 2 | import { handler, IHandlerBodyResponse } from "../handlers/getProtocol"; 3 | import { performance } from "perf_hooks"; 4 | 5 | (async () => { 6 | const start = performance.now() 7 | const r = await handler({ 8 | pathParameters: { 9 | name: "pancakeswap", 10 | type: "dexs" 11 | }, 12 | /* queryStringParameters: { 13 | dataType: "dailyRevenue" 14 | } */ 15 | } as unknown as AWSLambda.APIGatewayEvent) 16 | const end = performance.now() 17 | const d = JSON.parse(r.body) as Partial 18 | console.log(JSON.stringify(d.totalDataChartBreakdown?.slice(-5), null, 2)) 19 | console.log(d.totalDataChart?.slice(0, 5)) 20 | console.log(d.childProtocols) 21 | console.log((end - start) / 1000) 22 | //console.log(JSON.stringify(d, null, 2)) 23 | })() -------------------------------------------------------------------------------- /defi/src/adaptors/cli/runNotifyStatus.ts: -------------------------------------------------------------------------------- 1 | import "./setup.ts" 2 | import handler from "../handlers/notifyStatus"; 3 | handler({type:'dexs'}) -------------------------------------------------------------------------------- /defi/src/adaptors/cli/runStoreDexVolume.ts: -------------------------------------------------------------------------------- 1 | import "./setup.ts" 2 | import { handler } from "../handlers/storeAdaptorData"; 3 | import { AdapterType } from "@defillama/dimension-adapters/adapters/types"; 4 | // import dexs from "../data/dexs"; 5 | 6 | handler({ 7 | protocolModules: ["paraswap"], 8 | timestamp: 1680134400+60*60*24, 9 | adaptorType: AdapterType.FEES 10 | }) -------------------------------------------------------------------------------- /defi/src/adaptors/cli/runTriggerStoreAdaptorData.ts: -------------------------------------------------------------------------------- 1 | import "./setup.ts" 2 | import { handler } from "../handlers/triggerStoreAdaptorData"; 3 | import { AdapterType } from "@defillama/dimension-adapters/adapters/types"; 4 | // import volumeAdapters from "../dexAdapters"; 5 | handler({type: AdapterType.DEXS}) -------------------------------------------------------------------------------- /defi/src/adaptors/cli/setup.ts: -------------------------------------------------------------------------------- 1 | import AWS from "aws-sdk"; 2 | 3 | // Importing env file 4 | require('dotenv').config() 5 | AWS.config.update({ region: 'eu-central-1' }); -------------------------------------------------------------------------------- /defi/src/adaptors/data/aggregator-derivatives/index.ts: -------------------------------------------------------------------------------- 1 | import aggregators_derivatives_imports from "../../../utils/imports/aggregator-derivatives_adapters" 2 | import { AdaptorRecordType, AdaptorRecordTypeMapReverse } from "../../db-utils/adaptor-record"; 3 | 4 | export const importModule = (module: string) => aggregators_derivatives_imports[module].module 5 | 6 | export const KEYS_TO_STORE = { 7 | [AdaptorRecordType.dailyVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.dailyVolume], 8 | [AdaptorRecordType.totalVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.totalVolume] 9 | } 10 | 11 | export { default as config } from "./config"; 12 | 13 | export { default as imports } from "../../../utils/imports/aggregator-derivatives_adapters" 14 | -------------------------------------------------------------------------------- /defi/src/adaptors/data/aggregators/index.test.ts: -------------------------------------------------------------------------------- 1 | import { AdapterType } from '@defillama/dimension-adapters/adapters/types'; 2 | //import { writeFile } from 'fs'; 3 | //import { config } from './protocols'; 4 | import data from '../index' 5 | //import { IJSON } from './types'; 6 | 7 | describe("Protocol adaptor list is complete", () => { 8 | it("AGGREGATORS",async () => { 9 | const d = (await data(AdapterType.AGGREGATORS)).default 10 | expect(d).toMatchSnapshot() 11 | }); 12 | }); 13 | 14 | 15 | /* const formatted = Object.entries(config).reduce((acc, [module, config]) => { 16 | const findd = d.find(sm => sm.module === module)?.id 17 | if (!findd) throw new Error(`not found! ${module}`) 18 | acc[module] = { 19 | ...config, 20 | id: findd 21 | } 22 | return acc 23 | }, {} as IJSON) 24 | writeFile(`./src/adaptors/data/${type}/new_config.ts`, ` 25 | export default 26 | ${JSON.stringify(formatted, null, 2)} 27 | 28 | `, err => { 29 | if (err) { 30 | console.error(err); 31 | } 32 | // file written successfully 33 | }); */ -------------------------------------------------------------------------------- /defi/src/adaptors/data/aggregators/index.ts: -------------------------------------------------------------------------------- 1 | import aggregators_imports from "../../../utils/imports/aggregators_adapters" 2 | import { AdaptorRecordType, AdaptorRecordTypeMapReverse } from "../../db-utils/adaptor-record"; 3 | 4 | // TODO: needs to be optimized. Currently loads to memory all adaptors 5 | export const importModule = (module: string) => aggregators_imports[module].module 6 | 7 | // KEYS USED TO MAP ATTRIBUTE -> KEY IN DYNAMO 8 | export const KEYS_TO_STORE = { 9 | [AdaptorRecordType.dailyVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.dailyVolume], 10 | [AdaptorRecordType.totalVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.totalVolume] 11 | } 12 | 13 | export { default as config } from "./config"; 14 | 15 | export { default as imports } from "../../../utils/imports/aggregators_adapters" 16 | 17 | -------------------------------------------------------------------------------- /defi/src/adaptors/data/bridge-aggregators/config.ts: -------------------------------------------------------------------------------- 1 | import { AdaptorsConfig } from "../types" 2 | 3 | export default { 4 | "jumper.exchange": { 5 | id: "3524" 6 | }, 7 | "xy-finance": { 8 | id: "1885" 9 | }, 10 | "okx": { 11 | id: "5201", 12 | }, 13 | "swing": { 14 | id: "5474", 15 | }, 16 | "bitgetwallet": { 17 | id: "3207", 18 | }, 19 | "teleswap": { 20 | id: "5532", 21 | }, 22 | "rubic": { 23 | id: "1282", 24 | }, 25 | "socket": { 26 | id: "6097" 27 | }, 28 | "bungee-bridge": { 29 | id: "6188" 30 | }, 31 | } as AdaptorsConfig 32 | -------------------------------------------------------------------------------- /defi/src/adaptors/data/bridge-aggregators/index.ts: -------------------------------------------------------------------------------- 1 | import dexs_imports from "../../../utils/imports/bridge-aggregators_adapters" 2 | import { AdaptorRecordType, AdaptorRecordTypeMapReverse } from "../../db-utils/adaptor-record"; 3 | 4 | // TODO: needs to be optimized. Currently loads to memory all adaptors 5 | export const importModule = (module: string) => dexs_imports[module].module 6 | 7 | // KEYS USED TO MAP ATTRIBUTE -> KEY IN DYNAMO 8 | export const KEYS_TO_STORE = { 9 | [AdaptorRecordType.dailyBridgeVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.dailyBridgeVolume], 10 | [AdaptorRecordType.totalBridgeVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.totalBridgeVolume] 11 | } 12 | 13 | export { default as imports } from "../../../utils/imports/bridge-aggregators_adapters" 14 | 15 | export { default as config } from "./config"; 16 | -------------------------------------------------------------------------------- /defi/src/adaptors/data/derivatives/index.test.ts: -------------------------------------------------------------------------------- 1 | import { AdapterType } from '@defillama/dimension-adapters/adapters/types'; 2 | //import { writeFile } from 'fs'; 3 | //import { config } from './protocols'; 4 | import data from '../index' 5 | //import { IJSON } from './types'; 6 | 7 | describe("Protocol adaptor list is complete", () => { 8 | it("DERIVATIVES", async () => { 9 | const d = (await data(AdapterType.DERIVATIVES)).default 10 | expect(d).toMatchSnapshot() 11 | }); 12 | }); 13 | 14 | 15 | /* const formatted = Object.entries(config).reduce((acc, [module, config]) => { 16 | const findd = d.find(sm => sm.module === module)?.id 17 | if (!findd) throw new Error(`not found! ${module}`) 18 | acc[module] = { 19 | ...config, 20 | id: findd 21 | } 22 | return acc 23 | }, {} as IJSON) 24 | writeFile(`./src/adaptors/data/${type}/new_config.ts`, ` 25 | export default 26 | ${JSON.stringify(formatted, null, 2)} 27 | 28 | `, err => { 29 | if (err) { 30 | console.error(err); 31 | } 32 | // file written successfully 33 | }); */ -------------------------------------------------------------------------------- /defi/src/adaptors/data/dexs/index.test.ts: -------------------------------------------------------------------------------- 1 | import { AdapterType } from '@defillama/dimension-adapters/adapters/types'; 2 | //import { writeFile } from 'fs'; 3 | //import { config } from './protocols'; 4 | import data from '../index' 5 | //import { IJSON } from './types'; 6 | 7 | describe("Protocol adaptor list is complete", () => { 8 | it("DEXS", async () => { 9 | const d = (await data(AdapterType.DEXS)).default 10 | expect(d).toMatchSnapshot() 11 | }); 12 | }); 13 | 14 | 15 | /* const formatted = Object.entries(config).reduce((acc, [module, config]) => { 16 | const findd = d.find(sm => sm.module === module)?.id 17 | if (!findd) throw new Error(`not found! ${module}`) 18 | acc[module] = { 19 | ...config, 20 | id: findd 21 | } 22 | return acc 23 | }, {} as IJSON) 24 | writeFile(`./src/adaptors/data/${type}/new_config.ts`, ` 25 | export default 26 | ${JSON.stringify(formatted, null, 2)} 27 | 28 | `, err => { 29 | if (err) { 30 | console.error(err); 31 | } 32 | // file written successfully 33 | }); */ -------------------------------------------------------------------------------- /defi/src/adaptors/data/dexs/index.ts: -------------------------------------------------------------------------------- 1 | import dexs_imports from "../../../utils/imports/dexs_adapters" 2 | import { AdaptorRecordType, AdaptorRecordTypeMapReverse } from "../../db-utils/adaptor-record"; 3 | 4 | // TODO: needs to be optimized. Currently loads to memory all adaptors 5 | export const importModule = (module: string) => dexs_imports[module].module 6 | 7 | // KEYS USED TO MAP ATTRIBUTE -> KEY IN DYNAMO 8 | export const KEYS_TO_STORE = { 9 | [AdaptorRecordType.dailyVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.dailyVolume], 10 | [AdaptorRecordType.totalVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.totalVolume] 11 | } 12 | 13 | export { default as imports } from "../../../utils/imports/dexs_adapters" 14 | 15 | export { default as config } from "./config"; 16 | 17 | -------------------------------------------------------------------------------- /defi/src/adaptors/data/fees/index.test.ts: -------------------------------------------------------------------------------- 1 | import { AdapterType } from '@defillama/dimension-adapters/adapters/types'; 2 | //import { writeFile } from 'fs'; 3 | //import { config } from './protocols'; 4 | import data from '../index' 5 | //import { IJSON } from './types'; 6 | 7 | describe("Protocol adaptor list is complete", () => { 8 | it("FEES", async () => { 9 | const d = (await data(AdapterType.FEES)).default 10 | expect(d).toMatchSnapshot() 11 | }); 12 | }); 13 | 14 | 15 | /* const formatted = Object.entries(config).reduce((acc, [module, config]) => { 16 | const findd = d.find(sm => sm.module === module)?.id 17 | if (!findd) throw new Error(`not found! ${module}`) 18 | acc[module] = { 19 | ...config, 20 | id: findd 21 | } 22 | return acc 23 | }, {} as IJSON) 24 | writeFile(`./src/adaptors/data/${type}/new_config.ts`, ` 25 | export default 26 | ${JSON.stringify(formatted, null, 2)} 27 | 28 | `, err => { 29 | if (err) { 30 | console.error(err); 31 | } 32 | // file written successfully 33 | }); */ -------------------------------------------------------------------------------- /defi/src/adaptors/data/helpers/categories.ts: -------------------------------------------------------------------------------- 1 | export enum CATEGORIES { 2 | DEX = 'Dexs', 3 | Lending = 'Lending', 4 | Chain = 'Chain', 5 | NFT_Marketplace = 'NFT Marketplace', 6 | Derivatives = 'Derivatives', 7 | Options = 'Options', 8 | "NFT_Lending" = 'NFT Lending', 9 | CDP = 'CDP', 10 | Liquid_Staking = 'Liquid Staking', 11 | Yield = 'Yield', 12 | Synthetics = 'Synthetics', 13 | Rollup = 'Rollup', 14 | Collection = 'Collection' 15 | } -------------------------------------------------------------------------------- /defi/src/adaptors/data/incentives/__snapshots__/index.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Protocol adaptor list is complete INCENTIVES 1`] = ` 4 | Array [ 5 | Object { 6 | "category": "Chain", 7 | "chains": Array [ 8 | "bitcoin", 9 | ], 10 | "cmcId": "1", 11 | "config": Object { 12 | "enabled": true, 13 | "id": "1", 14 | }, 15 | "disabled": false, 16 | "displayName": "Bitcoin", 17 | "enabled": true, 18 | "geckoId": "bitcoin", 19 | "gecko_id": "bitcoin", 20 | "id": "1", 21 | "logo": "https://icons.llama.fi/chains/rsz_bitcoin.jpg", 22 | "methodology": Object { 23 | "Fees": "Gas fees paid by users", 24 | "Revenue": "Burned coins", 25 | "UserFees": "Gas fees paid by users", 26 | }, 27 | "methodologyURL": "https://github.com/DefiLlama/dimension-adapters/blob/master/incentives/bitcoin", 28 | "module": "bitcoin", 29 | "name": "Bitcoin", 30 | "protocolType": "chain", 31 | "symbol": "BTC", 32 | }, 33 | ] 34 | `; 35 | -------------------------------------------------------------------------------- /defi/src/adaptors/data/incentives/config.ts: -------------------------------------------------------------------------------- 1 | import { AdaptorsConfig } from "../types" 2 | 3 | 4 | 5 | export default { 6 | "bitcoin": { 7 | "id": "1" 8 | } 9 | } as AdaptorsConfig -------------------------------------------------------------------------------- /defi/src/adaptors/data/incentives/index.test.ts: -------------------------------------------------------------------------------- 1 | import { AdapterType } from '@defillama/dimension-adapters/adapters/types'; 2 | //import { writeFile } from 'fs'; 3 | //import { config } from './protocols'; 4 | import data from '../index' 5 | //import { IJSON } from './types'; 6 | 7 | describe("Protocol adaptor list is complete", () => { 8 | it("INCENTIVES",async () => { 9 | const d = (await data(AdapterType.INCENTIVES)).default 10 | expect(d).toMatchSnapshot() 11 | }); 12 | }); 13 | 14 | 15 | /* const formatted = Object.entries(config).reduce((acc, [module, config]) => { 16 | const findd = d.find(sm => sm.module === module)?.id 17 | if (!findd) throw new Error(`not found! ${module}`) 18 | acc[module] = { 19 | ...config, 20 | id: findd 21 | } 22 | return acc 23 | }, {} as IJSON) 24 | writeFile(`./src/adaptors/data/${type}/new_config.ts`, ` 25 | export default 26 | ${JSON.stringify(formatted, null, 2)} 27 | 28 | `, err => { 29 | if (err) { 30 | console.error(err); 31 | } 32 | // file written successfully 33 | }); */ -------------------------------------------------------------------------------- /defi/src/adaptors/data/incentives/index.ts: -------------------------------------------------------------------------------- 1 | import incentives_imports from "../../../utils/imports/incentives_adapters" 2 | import { AdaptorRecordType, AdaptorRecordTypeMapReverse } from "../../db-utils/adaptor-record"; 3 | 4 | // TODO: needs to be optimized. Currently loads to memory all adaptors 5 | export const importModule = (module: string) => incentives_imports[module].module 6 | 7 | // KEYS USED TO MAP ATTRIBUTE -> KEY IN DYNAMO 8 | export const KEYS_TO_STORE = { 9 | [AdaptorRecordType.tokenIncentives]: AdaptorRecordTypeMapReverse[AdaptorRecordType.tokenIncentives] 10 | } 11 | 12 | export { default as imports } from "../../../utils/imports/incentives_adapters" 13 | 14 | export { default as config } from "./config"; 15 | 16 | -------------------------------------------------------------------------------- /defi/src/adaptors/data/options/index.test.ts: -------------------------------------------------------------------------------- 1 | import { AdapterType } from '@defillama/dimension-adapters/adapters/types'; 2 | //import { writeFile } from 'fs'; 3 | //import { config } from './protocols'; 4 | import data from '../index' 5 | //import { IJSON } from './types'; 6 | 7 | describe("Protocol adaptor list is complete", () => { 8 | it("OPTIONS", async () => { 9 | const d = (await data(AdapterType.OPTIONS)).default 10 | expect(d).toMatchSnapshot() 11 | }); 12 | }); 13 | 14 | 15 | /* const formatted = Object.entries(config).reduce((acc, [module, config]) => { 16 | const findd = d.find(sm => sm.module === module)?.id 17 | if (!findd) throw new Error(`not found! ${module}`) 18 | acc[module] = { 19 | ...config, 20 | id: findd 21 | } 22 | return acc 23 | }, {} as IJSON) 24 | writeFile(`./src/adaptors/data/${type}/new_config.ts`, ` 25 | export default 26 | ${JSON.stringify(formatted, null, 2)} 27 | 28 | `, err => { 29 | if (err) { 30 | console.error(err); 31 | } 32 | // file written successfully 33 | }); */ -------------------------------------------------------------------------------- /defi/src/adaptors/data/options/index.ts: -------------------------------------------------------------------------------- 1 | import options_imports from "../../../utils/imports/options_adapters" 2 | import { AdaptorRecordType, AdaptorRecordTypeMapReverse } from "../../db-utils/adaptor-record"; 3 | 4 | // TODO: needs to be optimized. Currently loads to memory all adaptors 5 | export const importModule = (module: string) => options_imports[module].module 6 | 7 | // KEYS USED TO MAP ATTRIBUTE -> KEY IN DYNAMO 8 | export const KEYS_TO_STORE = { 9 | [AdaptorRecordType.totalPremiumVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.totalPremiumVolume], 10 | [AdaptorRecordType.totalNotionalVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.totalNotionalVolume], 11 | [AdaptorRecordType.dailyPremiumVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.dailyPremiumVolume], 12 | [AdaptorRecordType.dailyNotionalVolume]: AdaptorRecordTypeMapReverse[AdaptorRecordType.dailyNotionalVolume] 13 | } 14 | 15 | export { default as config } from "./config"; 16 | 17 | export { default as imports } from "../../../utils/imports/options_adapters" 18 | 19 | -------------------------------------------------------------------------------- /defi/src/adaptors/data/royalties/index.test.ts: -------------------------------------------------------------------------------- 1 | import { AdapterType } from '@defillama/dimension-adapters/adapters/types'; 2 | //import { writeFile } from 'fs'; 3 | //import { config } from './protocols'; 4 | import data from '../index' 5 | //import { IJSON } from './types'; 6 | 7 | describe("Protocol adaptor list is complete", () => { 8 | it("FEES", async () => { 9 | const d = (await data(AdapterType.FEES)).default 10 | expect(d).toMatchSnapshot() 11 | }); 12 | }); 13 | 14 | 15 | /* const formatted = Object.entries(config).reduce((acc, [module, config]) => { 16 | const findd = d.find(sm => sm.module === module)?.id 17 | if (!findd) throw new Error(`not found! ${module}`) 18 | acc[module] = { 19 | ...config, 20 | id: findd 21 | } 22 | return acc 23 | }, {} as IJSON) 24 | writeFile(`./src/adaptors/data/${type}/new_config.ts`, ` 25 | export default 26 | ${JSON.stringify(formatted, null, 2)} 27 | 28 | `, err => { 29 | if (err) { 30 | console.error(err); 31 | } 32 | // file written successfully 33 | }); */ -------------------------------------------------------------------------------- /defi/src/adaptors/data/royalties/index.ts: -------------------------------------------------------------------------------- 1 | import royalties_imports from "../../../utils/imports/fees_adapters" 2 | import { KEYS_TO_STORE as KEYS_TO_STORE_fees } from "../fees" 3 | 4 | // TODO: needs to be optimized. Currently loads to memory all adaptors 5 | export const importModule = (module: string) => royalties_imports[module].module 6 | 7 | // KEYS USED TO MAP ATTRIBUTE -> KEY IN DYNAMO 8 | export const KEYS_TO_STORE = KEYS_TO_STORE_fees 9 | 10 | export { default as config } from "./config"; 11 | 12 | export { default as imports } from "../../../utils/imports/fees_adapters" 13 | 14 | -------------------------------------------------------------------------------- /defi/src/adaptors/db-utils/adaptor-record.test.ts: -------------------------------------------------------------------------------- 1 | import { AdaptorRecordType } from "./adaptor-record"; 2 | 3 | const isArrayUnique = (arr: any[]) => Array.isArray(arr) && new Set(arr).size === arr.length; 4 | test("No duplicated adapter type", async () => { 5 | const values = Object.values(AdaptorRecordType) 6 | expect(isArrayUnique(values)).toBeTruthy(); 7 | }); -------------------------------------------------------------------------------- /defi/src/adaptors/db-utils/base.ts: -------------------------------------------------------------------------------- 1 | export abstract class Item { 2 | abstract get pk(): T 3 | abstract get sk(): K 4 | 5 | public keys() { 6 | return { 7 | PK: this.pk, 8 | SK: this.sk 9 | } 10 | } 11 | 12 | abstract toItem(): Record 13 | } -------------------------------------------------------------------------------- /defi/src/adaptors/handlers/triggerNotifyStatus.ts: -------------------------------------------------------------------------------- 1 | import { wrapScheduledLambda } from "../../utils/shared/wrap"; 2 | import invokeLambda from "../../utils/shared/invokeLambda"; 3 | import { AdapterType } from "@defillama/dimension-adapters/adapters/types"; 4 | 5 | export const handler = async () => { 6 | await Promise.all([ 7 | AdapterType.FEES, 8 | AdapterType.DEXS, 9 | AdapterType.DERIVATIVES, 10 | AdapterType.AGGREGATORS, 11 | AdapterType.OPTIONS 12 | ].map(type => invokeLambda(`defillama-prod-notifyStatus`, { type }))) 13 | }; 14 | 15 | export default wrapScheduledLambda(handler); 16 | -------------------------------------------------------------------------------- /defi/src/adaptors/readme.md: -------------------------------------------------------------------------------- 1 | # DEX volumes 2 | 3 | ### Table 4 | 5 | | PK (S) | SK (N) | [chain] | 6 | | ------------ | --------------- | -------------------- | 7 | | #dv#dex#[id] | [unixTimestamp] | {[version]:[volume]} | 8 | 9 | Example: 10 | 11 | | PK (S) | SK (N) | polygon | ethereum | 12 | | ---------- | ---------- | ----------------------- | -------------------------------------------------- | 13 | | dv#dex#1 | 1658016001 | {"v3": 42732808} | {"v1": 115541.39940791792,"v3": 536833283.1319946} | 14 | | dv#dex#306 | 1658016001 | {"quickswap": 24826410} | | 15 | 16 | dv = daily volume 17 | 18 | ### DEX ids 19 | 20 | Taken from `protocols/data` matching DEX category 21 | 22 | ### Run locally DEX functions 23 | 24 | Store all DEX volumes 25 | 26 | ``` 27 | ts-node src/dexVolumes/cli/runStoreDexVolume.ts 28 | ``` 29 | -------------------------------------------------------------------------------- /defi/src/adaptors/utils.ts: -------------------------------------------------------------------------------- 1 | export interface IAdapterInfo { 2 | id: string 3 | chain: string 4 | timestamp: number 5 | version?: string 6 | } 7 | 8 | export async function handleAdapterError(e: Error, adapterInfo?: IAdapterInfo) { 9 | // TODO: handle error properly 10 | console.error(adapterInfo) 11 | console.error(e) 12 | throw new Error(`Couldn´t get volume for ${JSON.stringify(adapterInfo)}`) 13 | } -------------------------------------------------------------------------------- /defi/src/adaptors/utils/canGetBlock.ts: -------------------------------------------------------------------------------- 1 | import { Chain, providers } from "@defillama/sdk/build/general"; 2 | 3 | const blockChains = Object.keys(providers) 4 | 5 | export default (chain: Chain) => blockChains.includes(chain) -------------------------------------------------------------------------------- /defi/src/adaptors/utils/getDataPoints.ts: -------------------------------------------------------------------------------- 1 | const DAY_IN_MILISECONDS = 86400000 2 | 3 | export const getDataPoints = (from: number = Date.UTC(2019, 9, 11)) => { 4 | const monitorDate = from; 5 | const limitTime = Date.now() - DAY_IN_MILISECONDS 6 | const dataPoints = [] 7 | for (let day = monitorDate; day <= limitTime; day += DAY_IN_MILISECONDS) 8 | dataPoints.push(Math.trunc(day / 1000)) 9 | return dataPoints 10 | } 11 | 12 | export default getDataPoints -------------------------------------------------------------------------------- /defi/src/adaptors/utils/getDirectories.ts: -------------------------------------------------------------------------------- 1 | import { readdirSync } from 'fs' 2 | export default (source: string) => 3 | readdirSync(source, { withFileTypes: true }) 4 | .map(dirent => dirent.name) -------------------------------------------------------------------------------- /defi/src/adaptors/utils/handleErrors.ts: -------------------------------------------------------------------------------- 1 | export enum ERROR_TYPE { 2 | fetch_chain_failed, 3 | } 4 | 5 | export default (e: Error, _type: ERROR_TYPE, _payload?: any) => { 6 | console.error(e) 7 | } 8 | 9 | export function processFailedFetchAdapters () { 10 | 11 | } -------------------------------------------------------------------------------- /defi/src/adaptors/utils/notify.ts: -------------------------------------------------------------------------------- 1 | import { sendMessage } from "../../utils/discord"; 2 | import { IJSON } from "../data/types"; 3 | 4 | const webhooks = { 5 | dexs: process.env.VOLUMES_WEBHOOK, 6 | fees: process.env.FEES_WEBHOOK, 7 | derivatives: process.env.DERIVATIVES_WEBHOOK, 8 | aggregators: process.env.AGGREGATORS_WEBHOOK, 9 | options: process.env.OPTIONS_WEBHOOK, 10 | dimensionLogs: process.env.DIMENSION_LOGS_WEBHOOK, 11 | } as IJSON 12 | 13 | export const sendDiscordAlert = async (message: string, type: string, formatted?: boolean) => process.env.runLocal === 'true'? 14 | console.log(message) : sendMessage(message, webhooks[type] ?? webhooks.fees, formatted) -------------------------------------------------------------------------------- /defi/src/api-keys/checkApiKey.ts: -------------------------------------------------------------------------------- 1 | import AWS from "aws-sdk"; 2 | 3 | const client = new AWS.DynamoDB.DocumentClient({}); 4 | 5 | const TableName = "auth" 6 | const authPK = (key:string)=>`auth#${key}` 7 | 8 | export async function checkApiKey(apiKey: string) { 9 | const item = await client.get({ 10 | Key:{ 11 | PK: authPK(apiKey), 12 | }, 13 | TableName 14 | }).promise() 15 | if (!item.Item) { 16 | throw new Error("invalid api key") 17 | } 18 | } -------------------------------------------------------------------------------- /defi/src/api2/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use an official Node.js runtime as a parent image 2 | FROM node:20 3 | 4 | # Set the working directory in the container to /app 5 | WORKDIR /app 6 | 7 | # Clone your repo 8 | RUN git clone https://github.com/DefiLlama/defillama-server /app/repo 9 | 10 | # Change to the directory of your repo 11 | WORKDIR /app/repo/defi 12 | 13 | # RUN git checkout api-v2-dimensions 14 | 15 | # Make port 5001 available to the world outside this container 16 | EXPOSE 5001 17 | 18 | # bash command to keep the container running 19 | CMD ["bash", "-c", "bash src/api2/scripts/docker_prod_start.sh; while true; do sleep 10000; done"] -------------------------------------------------------------------------------- /defi/src/api2/constants.ts: -------------------------------------------------------------------------------- 1 | const METADATA_FILE = __dirname + '/metadata.json' 2 | 3 | const PG_CACHE_KEYS = { 4 | CACHE_DATA_ALL: 'cache-data-all', 5 | ORACLES_DATA: 'oracles-data', 6 | CATEGORIES_DATA: 'categories-data', 7 | FORKS_DATA: 'forks-data', 8 | HISTORICAL_TVL_DATA_META: 'getHistoricalTvlForAllProtocols-meta', 9 | } 10 | 11 | export { 12 | METADATA_FILE, 13 | PG_CACHE_KEYS, 14 | } -------------------------------------------------------------------------------- /defi/src/api2/ecosystem.config.js: -------------------------------------------------------------------------------- 1 | // https://pm2.keymetrics.io/docs/usage/application-declaration/ 2 | module.exports = { 3 | apps: [ 4 | { 5 | name: 'api2-rest-server', 6 | script: './src/api2/index.ts', // Path to your main TypeScript file 7 | interpreter: 'node', 8 | args: '-r ts-node/register', // Use ts-node for running TypeScript files 9 | node_args: '--max-old-space-size=5120', // Set the maximum old space size to 5 GB 10 | listen_timeout: 120_000, // Wait 120 seconds for the app to start 11 | kill_timeout: 10_000, // Wait 10 seconds for the app to start 12 | wait_ready: true, // Wait for the 'ready' signal 13 | instances: 3, 14 | exec_mode: 'cluster', // Start in cluster mode 15 | env: { 16 | TS_NODE_TRANSPILE_ONLY: 'true', // Enable ts-node's transpile-only mode, setting it via args is not working for some reason 17 | }, 18 | }, 19 | ], 20 | }; -------------------------------------------------------------------------------- /defi/src/api2/scripts/_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" 4 | ROOT_DIR=$SCRIPT_DIR/../../.. 5 | 6 | npx ts-node $ROOT_DIR/src/api2/index.ts -------------------------------------------------------------------------------- /defi/src/api2/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" 4 | 5 | ROOT_DIR=$SCRIPT_DIR/../.. 6 | cd $ROOT_DIR 7 | 8 | git submodule update --init --recursive 9 | git submodule update --remote --merge 10 | 11 | npm i -------------------------------------------------------------------------------- /defi/src/api2/scripts/rekt-rss/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rekt-rss", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "description": "", 11 | "dependencies": { 12 | "jsdom": "^26.1.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /defi/src/api2/tests/parentProtocol.test.ts: -------------------------------------------------------------------------------- 1 | import allItems from "../../protocols/parentProtocols"; 2 | import sluggify from '../../utils/sluggify'; 3 | import { getTests } from './utils'; 4 | 5 | getTests(allItems.map((i: any) => sluggify(i)), 'protocol', `[Parent Protocol]`) -------------------------------------------------------------------------------- /defi/src/api2/tests/protocol.test.ts: -------------------------------------------------------------------------------- 1 | import { getTests } from './utils'; 2 | 3 | 4 | import allItems from "../../protocols/data"; 5 | import sluggify from '../../utils/sluggify'; 6 | 7 | getTests(allItems.map(sluggify), 'protocol', `[Protocol]`) -------------------------------------------------------------------------------- /defi/src/api2/tests/treasury.test.ts: -------------------------------------------------------------------------------- 1 | 2 | import { sluggifyString } from '../../utils/sluggify'; 3 | import allItems from "../../protocols/treasury"; 4 | import { getTests } from './utils'; 5 | 6 | getTests(allItems.map((i: any) => sluggifyString(i.name.replace(/\s+\(Treasury\)$/i, ''))), 'treasury', `[Treasury]`) -------------------------------------------------------------------------------- /defi/src/api2/utils/failOnError.ts: -------------------------------------------------------------------------------- 1 | 2 | process.on('unhandledRejection', (reason, promise) => { 3 | console.error('[Global] Unhandled Rejection at:', promise, 'reason:', reason); 4 | // process.exit(1); 5 | }) 6 | 7 | process.on('uncaughtException', (error) => { 8 | console.error('[Global] Uncaught Exception thrown', error); 9 | // process.exit(1); 10 | }) -------------------------------------------------------------------------------- /defi/src/cli/backfillEmissions.ts: -------------------------------------------------------------------------------- 1 | import adapters from "../utils/imports/emissions_adapters"; 2 | import { processSingleProtocol } from "../storeEmissionsUtils"; 3 | import setEnvSecrets from "../utils/shared/setEnvSecrets"; 4 | 5 | async function main() { 6 | const protocolName = process.argv[2] ?? ""; 7 | const protocolIndex = Object.keys(adapters).indexOf(protocolName); 8 | if (protocolIndex == -1) throw new Error(`${protocolName} is not a valid adapter`); 9 | 10 | await setEnvSecrets(); 11 | const adapterCode = Object.values(adapters)[protocolIndex].default; 12 | await processSingleProtocol(adapterCode, protocolName, {}, true).catch((err: Error) => { 13 | console.log(err.message ? `${err.message}: \n storing ${protocolName}` : err); 14 | }); 15 | process.exit(); 16 | } 17 | 18 | main(); // ts-node defi/src/cli/backfillEmissions.ts across 19 | -------------------------------------------------------------------------------- /defi/src/cli/buildCoingeckoSymbols.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import requests 3 | import json 4 | 5 | # First download all.csv from defillama and then place it in the same directory as this script 6 | 7 | r = requests.get('https://api.coingecko.com/api/v3/coins/list').json() 8 | tokens = { 9 | "ethereum": "WETH" # to merge it with regular weth 10 | } 11 | unmatchedTokens = set() 12 | 13 | ll = len("coingecko:") 14 | 15 | csvfile = open("all.csv", "r") 16 | datareader = csv.reader(csvfile) 17 | for row in datareader: 18 | if row[4].startswith("coingecko:"): 19 | row[4] = row[4][ll:] 20 | if row[3] == "Tokens" and "0x" not in row[4] and row[4].lower() == row[4] and row[4] not in tokens and row[4] not in unmatchedTokens: 21 | symbol = next((x for x in r if x["id"]==row[4]), None) 22 | if symbol == None: 23 | print(row[4]) 24 | unmatchedTokens.add(row[4]) 25 | else: 26 | tokens[row[4]] = symbol["symbol"].upper() 27 | 28 | w = open('../utils/symbols/symbols.json', 'w') 29 | json.dump(tokens, w) -------------------------------------------------------------------------------- /defi/src/cli/buildCoingeckoSymbols.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | import symbolsA from "../utils/symbols/symbols.json"; 3 | 4 | type CgData = { 5 | id: string; 6 | symbol: string; 7 | }; 8 | const symbols: { [id: string]: string } = symbolsA; 9 | 10 | async function main() { 11 | console.log(`old length: ${Object.keys(symbols).length}`); 12 | const data = await fetch(`https://api.coingecko.com/api/v3/coins/list`).then((r) => r.json()); 13 | 14 | data.map((t: CgData) => { 15 | const { id, symbol } = t; 16 | if (id in symbols) return; 17 | symbols[id] = symbol.toUpperCase(); 18 | }); 19 | 20 | console.log(`new length: ${Object.keys(symbols).length}`); 21 | return symbols; // save this to symbols.json 22 | } // ts-node defi/src/cli/buildCoingeckoSymbols.ts 23 | main(); 24 | -------------------------------------------------------------------------------- /defi/src/cli/checkProtocolsToList.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs" 2 | import protocols from "../protocols/data"; 3 | 4 | const main = async () => { 5 | const files = fs.readdirSync('./DefiLlama-Adapters/projects/'); 6 | const modules = protocols.map(p=>p.module.split('/')[0]) 7 | const unlisted = files.filter(file=>!modules.includes(file)) 8 | console.log(unlisted) 9 | } 10 | main() -------------------------------------------------------------------------------- /defi/src/cli/clearProtocolCache.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | 3 | import { getProtocol, } from "./utils"; 4 | import { clearProtocolCacheById } from "./utils/clearProtocolCache"; 5 | 6 | const main = async () => { 7 | const protocolArg = process.argv[2] 8 | const protocol = getProtocol(protocolArg) 9 | return clearProtocolCacheById(protocol.id) 10 | 11 | }; 12 | main().then(() => { 13 | console.log('Done!!!') 14 | process.exit(0) 15 | }) 16 | 17 | -------------------------------------------------------------------------------- /defi/src/cli/copyListing.ts: -------------------------------------------------------------------------------- 1 | import { dailyTokensTvl, dailyTvl, dailyUsdTokensTvl } from "../utils/getLastRecord"; 2 | import dynamodb, { getHistoricalValues } from "../utils/shared/dynamodb"; 3 | import { getProtocol } from "./utils" 4 | 5 | const protocolToCopy = "spacefi" 6 | const protocolToReplace = "spacefi" 7 | 8 | async function main(){ 9 | const source = getProtocol(protocolToCopy); 10 | const dest = getProtocol(protocolToReplace) 11 | await Promise.all([dailyTvl, dailyTokensTvl, dailyUsdTokensTvl].map(async prefix=>{ 12 | const data = await getHistoricalValues(prefix(source.id)) 13 | await Promise.all(data.map(t=>{ 14 | t.PK = prefix(dest.id) 15 | return dynamodb.put(t) 16 | })) 17 | })) 18 | process.exit(0) 19 | } 20 | main() -------------------------------------------------------------------------------- /defi/src/cli/countMisrepresented.ts: -------------------------------------------------------------------------------- 1 | import { importAdapter } from "../utils/imports/importAdapter"; 2 | import protocols from "../protocols/data" 3 | 4 | const main = async () => { 5 | let misrepresented = 0 6 | for (const protocol of protocols) { 7 | const adapter = await importAdapter(protocol); 8 | if (adapter.misrepresentedTokens === true) { 9 | misrepresented++; 10 | } 11 | } 12 | console.log(misrepresented, protocols.length, 100 * misrepresented / protocols.length) 13 | }; 14 | main(); -------------------------------------------------------------------------------- /defi/src/cli/deleteLatestDayTvl.ts: -------------------------------------------------------------------------------- 1 | import { dailyTvl, getLastRecord } from "../utils/getLastRecord"; 2 | import dynamodb from "../utils/shared/dynamodb"; 3 | import { getProtocol } from "./utils"; 4 | 5 | async function main(){ 6 | const protocol = getProtocol(process.argv[2]) 7 | const last = await getLastRecord(dailyTvl(protocol.id)) 8 | console.log(`Deleting TVL for protocol ${protocol.name} at time ${new Date(last!.SK*1e3)}`) 9 | await dynamodb.delete({ 10 | Key:{ 11 | PK:last!.PK, 12 | SK: last!.SK 13 | } 14 | }) 15 | } 16 | main() -------------------------------------------------------------------------------- /defi/src/cli/deleteLatestDayTvlAllProtocols.ts: -------------------------------------------------------------------------------- 1 | import { dailyTvl, getLastRecord } from "../utils/getLastRecord"; 2 | import dynamodb from "../utils/shared/dynamodb"; 3 | import protocols from "../protocols/data"; 4 | import { getCurrentUnixTimestamp, getTimestampAtStartOfDay } from "../utils/date"; 5 | 6 | async function main() { 7 | await Promise.all(protocols.map(async protocol => { 8 | const last = await getLastRecord(dailyTvl(protocol.id)) 9 | if(last && last.SK === getTimestampAtStartOfDay(getCurrentUnixTimestamp())){ 10 | console.log(`Deleting TVL for protocol ${protocol.name} at time ${new Date(last!.SK * 1e3)}`) 11 | /* 12 | await dynamodb.delete({ 13 | Key: { 14 | PK: last!.PK, 15 | SK: last!.SK 16 | } 17 | }) 18 | */ 19 | } 20 | })) 21 | process.exit(0) 22 | } 23 | main() -------------------------------------------------------------------------------- /defi/src/cli/deleteProtocolsDate.ts: -------------------------------------------------------------------------------- 1 | import dynamodb from "../utils/shared/dynamodb"; 2 | import { dailyTokensTvl, dailyTvl, dailyUsdTokensTvl, hourlyTvl } from "../utils/getLastRecord"; 3 | 4 | 5 | async function main() { 6 | for (const id of [2595, 2596, 2597, 2598, 2599, 2600, 2601, 2602, 2603, 2604]) { 7 | for (const tvlFunc of [dailyTokensTvl, dailyTvl, dailyUsdTokensTvl, 8 | // hourlyTvl // - we retain hourly in case we want to refill using it for some reason 9 | ]) { 10 | await dynamodb.delete({ 11 | Key: { 12 | PK: tvlFunc(String(id)), 13 | SK: 1677542400, 14 | }, 15 | }); 16 | } 17 | } 18 | } 19 | 20 | main().then(() => { 21 | console.log('Done!!!') 22 | process.exit(0) 23 | }) 24 | -------------------------------------------------------------------------------- /defi/src/cli/displayItems.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefiLlama/defillama-server/2c08af5d517e7f56965ba85d372cc484dab93d8c/defi/src/cli/displayItems.ts -------------------------------------------------------------------------------- /defi/src/cli/dynamodb.ts: -------------------------------------------------------------------------------- 1 | import AWS from "aws-sdk"; 2 | 3 | AWS.config.update({ region: "eu-central-1" }); 4 | export const client = new AWS.DynamoDB.DocumentClient(); 5 | 6 | export const dateToUNIXTimestamp = (date: string) => 7 | Math.round(new Date(date).getTime() / 1000); 8 | const step = 25; 9 | export const hourlyPrefix = "hourlyTvl"; 10 | export const dailyPrefix = "dailyTvl"; 11 | 12 | export const dynamoPrefix = dailyPrefix; 13 | export const TableName = "prod-table"; 14 | export const maxProtocolId = 300; 15 | 16 | export const getDailyTxs = (protocolId: string) => 17 | client 18 | .query({ 19 | TableName, 20 | ExpressionAttributeValues: { 21 | ":pk": `${dailyPrefix}#${protocolId}`, 22 | }, 23 | KeyConditionExpression: "PK = :pk", 24 | }) 25 | .promise() 26 | .then((result) => result.Items); 27 | -------------------------------------------------------------------------------- /defi/src/cli/findDrop.ts: -------------------------------------------------------------------------------- 1 | import protocols from "../protocols/data"; 2 | import dynamodb from "../utils/shared/dynamodb"; 3 | import { dailyTvl, dailyTokensTvl, dailyUsdTokensTvl } from "../utils/getLastRecord"; 4 | import {date} from './utils' 5 | 6 | const drop = 0.25 7 | 8 | async function main() { 9 | console.log("Protocol, Timestamp, Date, Yesterday's TVL, Today's TVL") 10 | for (const tvlPrefix of [dailyTvl]) { 11 | await Promise.all( 12 | protocols.map(async (protocol) => { 13 | const historicalTvl = (await dynamodb.query({ 14 | ExpressionAttributeValues: { 15 | ":pk": tvlPrefix(protocol.id), 16 | }, 17 | KeyConditionExpression: "PK = :pk", 18 | })).Items ?? [] 19 | for(let i=1;i { 4 | const raises = await fetch(`https://api.llama.fi/raises`).then(r=>r.json()) 5 | const tagged = {} as any 6 | const unmatchedRaises = raises.raises.filter((r:any)=> { 7 | const id = `${r.name}-${r.date}` 8 | if(tagged[id] === undefined){ 9 | tagged[id] = true; 10 | return false 11 | } else { 12 | return true 13 | } 14 | }) 15 | console.table(unmatchedRaises.sort((a:any,b:any)=>a.date-b.date).map(({date, name, amount}:any)=>({date:new Date(date*1e3).toISOString().slice(0, 10), name, amount}))) 16 | } 17 | 18 | main() -------------------------------------------------------------------------------- /defi/src/cli/findUntaggedProtocolsInRaises.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | 3 | const get = (url:string) => fetch(url).then(r=>r.json()) 4 | 5 | const main = async () => { 6 | const [raises] = await Promise.all([ 7 | get(`https://api.llama.fi/raises`) 8 | ]) 9 | const protocolNames = raises.raises.reduce((all:any, p:any)=>({ 10 | ...all, 11 | [p.name.toLowerCase()]: p.defillamaId 12 | }), {}) 13 | const unmatchedRaises = raises.raises.filter((r:any)=> protocolNames[r.name.toLowerCase()] !== undefined && r.defillamaId === undefined) 14 | console.table(unmatchedRaises.sort((a:any,b:any)=>a.date-b.date).map(({date, name, amount}:any)=>({date:new Date(date*1e3).toISOString().slice(0, 10), name, amount, possibleDefillamaId: Number(protocolNames[name.toLowerCase()])}))) 15 | } 16 | 17 | main() -------------------------------------------------------------------------------- /defi/src/cli/findUntaggedRaises.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | 3 | const get = (url:string) => fetch(url).then(r=>r.json()) 4 | 5 | const main = async () => { 6 | const [protocols, raises] = await Promise.all([ 7 | get(`https://api.llama.fi/lite/protocols2`), 8 | get(`https://api.llama.fi/raises`) 9 | ]) 10 | const protocolNames = protocols.protocols.reduce((all:any, p:any)=>({ 11 | ...all, 12 | [p.name.toLowerCase()]: p.defillamaId 13 | }), {}) 14 | const unmatchedRaises = raises.raises.filter((r:any)=> protocolNames[r.name.toLowerCase()] !== undefined && r.defillamaId === undefined) 15 | console.table(unmatchedRaises.sort((a:any,b:any)=>a.date-b.date).map(({date, name, amount}:any)=>({date:new Date(date*1e3).toISOString().slice(0, 10), name, amount, possibleDefillamaId: Number(protocolNames[name.toLowerCase()])}))) 16 | } 17 | 18 | main() 19 | // Run it with 20 | // npx ts-node src/cli/findUntaggedRaises.ts > unmatched.txt -------------------------------------------------------------------------------- /defi/src/cli/findUnupdated.ts: -------------------------------------------------------------------------------- 1 | import findOutdated from '../utils/findOutdated' 2 | 3 | const maxDrift = 3 * 3600; // Max three updates missed 4 | 5 | async function main() { 6 | console.log(await findOutdated(maxDrift)) 7 | } 8 | main(); 9 | -------------------------------------------------------------------------------- /defi/src/cli/fixDecimals.ts: -------------------------------------------------------------------------------- 1 | import dynamodb, { batchGet } from "../utils/shared/dynamodb" 2 | const fs = require('fs') 3 | 4 | async function main(){ 5 | const data = fs.readFileSync(`0sk`, "utf8").split("\n") as string[] 6 | const all = {} as any 7 | data.forEach((itemRaw)=>{ 8 | try{ 9 | const item = JSON.parse(itemRaw) 10 | if(item.Item.decimals){ 11 | all[item.Item.PK.S] = Number(item.Item.decimals.N) 12 | } 13 | } catch(e){ 14 | console.log(e, itemRaw) 15 | } 16 | }) 17 | const currentInfo = await batchGet(Object.keys(all).map(i=>({ 18 | SK:0, 19 | PK:i 20 | }))) 21 | fs.writeFileSync("batchGet", JSON.stringify(currentInfo)) 22 | await Promise.all(currentInfo.map(async final=>{ 23 | if(all[final.PK] !== final.decimals){ 24 | console.log(final.PK, all[final.PK], final.decimals) 25 | final.decimals = all[final.PK] 26 | await dynamodb.put(final) 27 | } 28 | })) 29 | } 30 | main() -------------------------------------------------------------------------------- /defi/src/cli/getItem.ts: -------------------------------------------------------------------------------- 1 | import { getLastRecord, hourlyUsdTokensTvl } from "../utils/getLastRecord"; 2 | import { getProtocol } from "./utils"; 3 | 4 | async function main(){ 5 | getLastRecord(hourlyUsdTokensTvl(getProtocol("aave (treasury)").id)).then((b:any)=>console.log(b)) 6 | } 7 | main() -------------------------------------------------------------------------------- /defi/src/cli/liquidity/findDiffChainsInYields.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | 3 | async function main(){ 4 | const pools:any = await fetch(`https://yields.llama.fi/pools`).then(r => r.json()) 5 | console.log(new Set(pools.data.map((p:any)=>p.chain))) 6 | } 7 | main() -------------------------------------------------------------------------------- /defi/src/cli/liquidity/findDuplicateSymbols.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | 3 | async function main(){ 4 | const protocols = ((await fetch(`https://api.llama.fi/protocols`).then(r => r.json())) as any[]).filter(p => p.symbol !== "-") 5 | const repeatedSymbols = new Set(protocols 6 | .filter((item, index, arr) => { 7 | const dupIndex = arr.findIndex(itm => itm.symbol === item.symbol && (item.parentProtocol !== itm.parentProtocol || item.parentProtocol === undefined)) 8 | return dupIndex !== -1 && dupIndex !== index 9 | }) 10 | .map(p => p.symbol)) 11 | const badProtocols = Array.from(repeatedSymbols).map(symbol=>{ 12 | const pp = protocols.filter(p=>p.symbol === symbol).sort((a,b)=>a.tvl-b.tvl) 13 | return [pp[0].name, symbol, pp[1].name] 14 | }) 15 | console.table(badProtocols) 16 | } 17 | main() -------------------------------------------------------------------------------- /defi/src/cli/moveTreasuries.ts: -------------------------------------------------------------------------------- 1 | import { dailyTvl } from "../utils/getLastRecord"; 2 | import dynamodb, { getHistoricalValues } from "../utils/shared/dynamodb"; 3 | import { getProtocol } from "./utils" 4 | 5 | const protocolsToMove = ["Olympus DAO"] 6 | async function main(){ 7 | await Promise.all(protocolsToMove.map(async protocolName=>{ 8 | const protocol = getProtocol(protocolName); 9 | const treasuryData = await getHistoricalValues(dailyTvl(protocol.id)) // TODO do the same for dailyTokensTvl, dailyUsdTokensTvl... 10 | await Promise.all(treasuryData.map(async t=>{ 11 | t.PK = `${protocol.id}-treasury` 12 | await dynamodb.put(t) 13 | })) 14 | })) 15 | process.exit(0) 16 | } 17 | main() -------------------------------------------------------------------------------- /defi/src/cli/refillNpmData.ts: -------------------------------------------------------------------------------- 1 | import {storeNpmDayData} from "../storeNpmData" 2 | 3 | // will start here and then go backwards in time 4 | let date = new Date("2021-04-13") 5 | 6 | // date format is 2014-02-01 7 | const formatNpmDate = (d:Date)=>d.toISOString().slice(0, '2022-12-10'.length) 8 | 9 | async function main(){ 10 | while(true){ 11 | await storeNpmDayData(formatNpmDate(date)) 12 | console.log(`${formatNpmDate(date)} done`) 13 | date = new Date(date.getTime() - 24*3600*1e3) 14 | } 15 | } 16 | main() -------------------------------------------------------------------------------- /defi/src/cli/refreshProtocolsCache.ts: -------------------------------------------------------------------------------- 1 | import invokeLambda from "../utils/shared/invokeLambda"; 2 | import aws from "aws-sdk"; 3 | 4 | async function main() { 5 | const protocolToInvalidate = process.argv[2] 6 | const items = ['/lite/protocols2'] 7 | if(protocolToInvalidate !== undefined){ 8 | items.push(`/protocol/${protocolToInvalidate}`) 9 | items.push(`/updatedProtocol/${protocolToInvalidate}`) 10 | } 11 | 12 | const uniqueId = "cli-" + Date.now() 13 | await invokeLambda(`defillama-prod-storeProtocols`, {}); 14 | await new aws.CloudFront().createInvalidation({ 15 | DistributionId: 'E1WAA6CH5260VO', /* required */ 16 | InvalidationBatch: { /* required */ 17 | CallerReference: uniqueId, /* required */ 18 | Paths: { /* required */ 19 | Quantity: items.length, /* required */ 20 | Items: items 21 | } 22 | } 23 | }).promise(); 24 | } 25 | main() -------------------------------------------------------------------------------- /defi/src/cli/removeCorrupted.ts: -------------------------------------------------------------------------------- 1 | import dynamodb from "../utils/shared/dynamodb"; 2 | import { dailyTokensTvl } from "../utils/getLastRecord"; 3 | import protocols from "../protocols/data"; 4 | 5 | async function main() { 6 | for (const protocol of protocols) { 7 | const data = await dynamodb.query({ 8 | ExpressionAttributeValues: { 9 | ":pk": dailyTokensTvl(protocol.id), 10 | }, 11 | KeyConditionExpression: "PK = :pk", 12 | }); 13 | for (const d of data.Items ?? []) { 14 | if (d.tvl === undefined) { 15 | await dynamodb.delete({ 16 | Key: { 17 | PK: d.PK, 18 | SK: d.SK, 19 | }, 20 | }); 21 | console.log(protocol.name); 22 | } 23 | } 24 | } 25 | } 26 | main(); 27 | -------------------------------------------------------------------------------- /defi/src/cli/search/setup.sh: -------------------------------------------------------------------------------- 1 | # Replace MASTER_KEY for the master key from meilisearch 2 | MASTER_KEY="" 3 | 4 | curl \ 5 | -X POST 'https://search.defillama.com/keys' \ 6 | -H 'Content-Type: application/json' \ 7 | -H "Authorization: Bearer $MASTER_KEY" \ 8 | --data-binary '{ 9 | "description": "Search for frontend", 10 | "actions": ["search"], 11 | "indexes": ["protocols"], 12 | "expiresAt": null 13 | }' 14 | 15 | curl \ 16 | -X POST 'https://search.defillama.com/indexes/protocols/documents'\ 17 | -H 'Content-Type: application/json' \ 18 | -H "Authorization: Bearer $MASTER_KEY" \ 19 | --data-binary @searchProtocols.json 20 | 21 | curl -X GET 'https://search.defillama.com/tasks/0' -H "Authorization: Bearer $MASTER_KEY" 22 | 23 | curl \ 24 | -X PUT 'https://search.defillama.com/indexes/protocols/settings/ranking-rules' \ 25 | -H "Authorization: Bearer $MASTER_KEY" \ 26 | -H 'Content-Type: application/json' \ 27 | --data-binary '[ 28 | "words", 29 | "tvl:desc", 30 | "typo", 31 | "proximity", 32 | "attribute", 33 | "sort", 34 | "exactness" 35 | ]' 36 | -------------------------------------------------------------------------------- /defi/src/cli/users/README.md: -------------------------------------------------------------------------------- 1 | ## Refill all protocols 2 | 1. Make sure that the env variable ACCOUNTS_DB is set in your .env file 3 | 2. Modify defi/dimension-adapters/users/routers/routerAddresses.ts and filter it so only the protocols you want to refill are left 4 | 3. Run the following commands: 5 | 6 | ``` 7 | npx ts-node src/cli/users/refillChainGas.ts 8 | npx ts-node src/cli/users/refillChainTxs.ts 9 | npx ts-node src/cli/users/refillChainUsers.ts 10 | npx ts-node src/cli/users/refillUsers.ts 11 | ``` 12 | 13 | ## Refill a single protocol 14 | This will destroy all info of the protocol before refilling it, so be cautious. 15 | 16 | ``` 17 | npx ts-node src/cli/users/refillSingleProtocol.ts velodrome 18 | ``` -------------------------------------------------------------------------------- /defi/src/cli/users/findMostUsedChainsForUsers.ts: -------------------------------------------------------------------------------- 1 | import { addressList } from "../../../dimension-adapters/users/list"; 2 | 3 | const count = {} as any 4 | addressList.forEach((c:any)=>{ 5 | Object.keys(c.addresses??{}).forEach(chain=>count[chain]=1+(count[chain]??0)) 6 | }) 7 | console.log(count) -------------------------------------------------------------------------------- /defi/src/cli/users/refilChainTxs.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | import protocolAddresses from "../../../dimension-adapters/users/routers/routerAddresses"; 3 | import { isAcceptedChain } from "../../../dimension-adapters/users/utils/convertChain"; 4 | import { PromisePool } from "@supercharge/promise-pool"; 5 | import { storeChainTxs } from "./queries/txs"; 6 | 7 | async function main() { 8 | const filtered = protocolAddresses.filter((addresses) => { 9 | return Object.entries(addresses.addresses).some(([chain, addys]) => isAcceptedChain(chain) && addys.length > 0); 10 | }); 11 | await PromisePool.withConcurrency(5).for(filtered).process(storeChainTxs); 12 | } 13 | main(); 14 | -------------------------------------------------------------------------------- /defi/src/cli/users/refillChainGas.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | import protocolAddresses from "../../../dimension-adapters/users/routers/routerAddresses"; 3 | import { isAcceptedChain } from "../../../dimension-adapters/users/utils/convertChain"; 4 | import { PromisePool } from '@supercharge/promise-pool' 5 | import { storeChainGas } from "./queries/gas"; 6 | 7 | async function main() { 8 | const filtered = protocolAddresses.filter(addresses => { 9 | return Object.entries(addresses.addresses).some(([chain, addys]) => isAcceptedChain(chain) && addys.length > 0) 10 | }) 11 | await PromisePool 12 | .withConcurrency(5) 13 | .for(filtered).process(storeChainGas) 14 | } 15 | main() -------------------------------------------------------------------------------- /defi/src/cli/users/refillChainUsers.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | import protocolAddresses from "../../../dimension-adapters/users/routers/routerAddresses"; 3 | import { isAcceptedChain } from "../../../dimension-adapters/users/utils/convertChain"; 4 | import { PromisePool } from '@supercharge/promise-pool' 5 | import { storeChainUsers } from "./queries/users"; 6 | 7 | async function main() { 8 | const filtered = protocolAddresses.filter(addresses => { 9 | return Object.entries(addresses.addresses).some(([chain, addys]) => isAcceptedChain(chain) && addys.length > 0) 10 | }) 11 | await PromisePool 12 | .withConcurrency(5) 13 | .for(filtered).process(storeChainUsers) 14 | } 15 | main() -------------------------------------------------------------------------------- /defi/src/cli/users/refillNewUsers.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | import protocolAddresses from "../../../dimension-adapters/users/routers/routerAddresses"; 3 | import { isAcceptedChain } from "../../../dimension-adapters/users/utils/convertChain"; 4 | import { PromisePool } from '@supercharge/promise-pool' 5 | import { storeAllNewUsers } from "./queries/newUsers"; 6 | 7 | async function main() { 8 | const filtered = protocolAddresses.filter(addresses => { 9 | return Object.entries(addresses.addresses).some(([chain, addys]) => isAcceptedChain(chain) && addys.length > 0) 10 | }) 11 | await PromisePool 12 | .withConcurrency(5) 13 | .for(filtered).process(storeAllNewUsers) 14 | } 15 | main() -------------------------------------------------------------------------------- /defi/src/cli/users/refillUsers.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | import protocolAddresses from "../../../dimension-adapters/users/routers/routerAddresses"; 3 | import { isAcceptedChain } from "../../../dimension-adapters/users/utils/convertChain"; 4 | import { PromisePool } from '@supercharge/promise-pool' 5 | import { storeAllUsers } from "./queries/users"; 6 | 7 | async function main() { 8 | const filtered = protocolAddresses.filter(addresses => { 9 | return Object.entries(addresses.addresses).some(([chain, addys]) => isAcceptedChain(chain) && addys.length > 0) 10 | }) 11 | await PromisePool 12 | .withConcurrency(5) 13 | .for(filtered).process(storeAllUsers) 14 | } 15 | main() -------------------------------------------------------------------------------- /defi/src/cli/users/single/deleteProtocolUserData.ts: -------------------------------------------------------------------------------- 1 | import { getProtocol } from "../../utils"; 2 | import { deleteUserDataForProtocol } from "./utils/deleteUserData"; 3 | 4 | async function main() { 5 | const protocolName = process.argv[2].toLowerCase() 6 | const protocol = getProtocol(protocolName) 7 | if(protocol === undefined){ 8 | console.error(`No protocol with name "${protocolName}"`) 9 | return 10 | } 11 | console.log(`Deleting data for protocol with id ${protocol.id}`) 12 | await deleteUserDataForProtocol(protocol.id) 13 | console.log(`Finished!`) 14 | process.exit(0); 15 | } 16 | main() -------------------------------------------------------------------------------- /defi/src/cli/users/single/utils/deleteUserData.ts: -------------------------------------------------------------------------------- 1 | import { getAccountsDBConnection } from "../../../../utils/shared/getDBConnection" 2 | 3 | export async function deleteUserDataForProtocol(protocolId:string){ 4 | const sql = getAccountsDBConnection() 5 | await Promise.all([ 6 | sql`DELETE FROM dailyUsers WHERE protocolId = ${protocolId};`, 7 | sql`DELETE FROM hourlyUsers WHERE protocolId = ${protocolId};`, 8 | sql`DELETE FROM dailyTxs WHERE protocolId = ${protocolId};`, 9 | sql`DELETE FROM hourlyTxs WHERE protocolId = ${protocolId};`, 10 | sql`DELETE FROM dailyGas WHERE protocolId = ${protocolId};`, 11 | sql`DELETE FROM hourlyGas WHERE protocolId = ${protocolId};`, 12 | sql`DELETE FROM dailyNewUsers WHERE protocolId = ${protocolId};`, 13 | sql`DELETE FROM hourlyNewUsers WHERE protocolId = ${protocolId};`, 14 | ]) 15 | } 16 | -------------------------------------------------------------------------------- /defi/src/cli/utils.ts: -------------------------------------------------------------------------------- 1 | import protocols from "../protocols/data"; 2 | import treasuries from "../protocols/treasury"; 3 | import entities from "../protocols/entities"; 4 | 5 | export function getProtocol(name: string) { 6 | let protocol = protocols.find( 7 | (p) => p.name.toLowerCase() === name.toLowerCase() 8 | ); 9 | if (!protocol) { 10 | protocol = treasuries.find( 11 | (p) => p.name.toLowerCase() === name.toLowerCase() 12 | ); 13 | } 14 | if (!protocol) { 15 | protocol = entities.find( 16 | (p) => p.name.toLowerCase() === name.toLowerCase() 17 | ); 18 | } 19 | if (protocol === undefined) { 20 | throw new Error("No protocol with that name"); 21 | } 22 | return protocol; 23 | } 24 | 25 | export const date = (timestamp: number) => 26 | "\t" + new Date(timestamp * 1000).toDateString(); 27 | -------------------------------------------------------------------------------- /defi/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const baseIconsUrl = "https://icons.llama.fi"; 2 | -------------------------------------------------------------------------------- /defi/src/corsPreflight.ts: -------------------------------------------------------------------------------- 1 | import { IResponse, wrap } from "./utils/shared"; 2 | 3 | const handler = async ( 4 | _event: AWSLambda.APIGatewayEvent 5 | ): Promise => { 6 | return { 7 | statusCode: 200, 8 | body: "", 9 | headers: { 10 | "cache-control": "max-age=31536000, s-maxage=31536000", // Caches preflight req on browser and proxy for 1 year 11 | "access-control-allow-methods": "OPTIONS,GET", 12 | "access-control-allow-headers": 13 | "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent", 14 | }, 15 | }; 16 | }; 17 | 18 | export default wrap(handler); 19 | -------------------------------------------------------------------------------- /defi/src/depositedContracts/constants.ts: -------------------------------------------------------------------------------- 1 | export const explorers: { [id: number]: string } = { 2 | 1: "https://etherscan.io/tx/", 3 | 10: "https://optimistic.etherscan.io/tx/", 4 | }; 5 | -------------------------------------------------------------------------------- /defi/src/depositedContracts/types.ts: -------------------------------------------------------------------------------- 1 | export type RawDeposits = { 2 | [from: string]: { 3 | timestamp: string; 4 | token: string; 5 | chain: number; 6 | value: number; 7 | transaction_hash: string; 8 | }; 9 | }; 10 | export type ReadableDeposit = { 11 | timestamp: string; 12 | symbol: string; 13 | chain: string; 14 | usdValue: string; 15 | url: string; 16 | }; 17 | export type CoinData = { 18 | price: number; 19 | decimals: number; 20 | symbol: string; 21 | }; 22 | -------------------------------------------------------------------------------- /defi/src/developers/npm.ts: -------------------------------------------------------------------------------- 1 | export const ecosystem = { 2 | "EVM": ["ethers", "web3", "@openzeppelin/contracts", "ganache", "hardhat", "truffle"], // missing web3py and brownie through pypi 3 | "Solana": ["@solana/web3.js"], 4 | "Stellar": ["js-stellar-sdk"], 5 | "Cardano": ["@emurgo/cardano-serialization-lib-nodejs", "@emurgo/cardano-serialization-lib-browser", "@emurgo/cardano-serialization-lib-asmjs"], 6 | "Polkadot": ["@polkadot/api"], 7 | "Waves": ["@waves/waves-transactions"], 8 | "Tron": ["tronweb"], 9 | "EOS": ["eosjs"], 10 | } 11 | -------------------------------------------------------------------------------- /defi/src/developers/utils.ts: -------------------------------------------------------------------------------- 1 | export const npmPK = (pkg:string)=>`npm#${pkg}` -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/Models/PermitBlackList.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn } from "typeorm"; 2 | 3 | @Entity() 4 | export class PermitBlackList { 5 | @PrimaryGeneratedColumn() 6 | id?: number; 7 | 8 | @Column("text") 9 | chain: string; 10 | 11 | @Column("text") 12 | address: string; 13 | } 14 | -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/getHistory.ts: -------------------------------------------------------------------------------- 1 | import { SwapEvent } from "./Models/SwapEvent"; 2 | import { getConnection } from "."; 3 | 4 | export async function getHistory(userId: string, chain: string): Promise { 5 | const swapEventRepository = (await getConnection()).getRepository(SwapEvent); 6 | const transactionHistory = await swapEventRepository 7 | .createQueryBuilder("swapEvent") 8 | .select([ 9 | "swapEvent.id", 10 | "swapEvent.createdAt", 11 | "swapEvent.user", 12 | "swapEvent.aggregator", 13 | "swapEvent.isError", 14 | "swapEvent.chain", 15 | "swapEvent.from", 16 | "swapEvent.to", 17 | "swapEvent.txUrl", 18 | "swapEvent.amount", 19 | "swapEvent.amountUsd", 20 | "swapEvent.slippage", 21 | "swapEvent.route", 22 | ]) 23 | .where("swapEvent.user = :userId", { userId }) 24 | .andWhere("swapEvent.chain = :chain", { chain }) 25 | .andWhere("swapEvent.isError = false") 26 | .orderBy("swapEvent.id", "DESC") 27 | .take(30) 28 | .getMany(); 29 | 30 | return transactionHistory; 31 | } 32 | -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/getLatestSwap.ts: -------------------------------------------------------------------------------- 1 | import { SwapEvent } from "./Models/SwapEvent"; 2 | import { getConnection } from "."; 3 | import { ILike } from "typeorm"; 4 | 5 | export async function getLatestSwap(tokenA: string, tokenB: string) { 6 | const swapEventRepository = (await getConnection()).getRepository(SwapEvent); 7 | const trade = await swapEventRepository.findOne({ 8 | where: { 9 | aggregator: "1inch", 10 | chain: "ethereum", 11 | isError: false, 12 | from: ILike(tokenA), 13 | to: ILike(tokenB), 14 | }, 15 | order: { 16 | createdAt: "DESC", 17 | }, 18 | }); 19 | 20 | return trade; 21 | } 22 | -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/getPermitBlackList.ts: -------------------------------------------------------------------------------- 1 | import { getConnection } from "."; 2 | import { PermitBlackList } from "./Models/PermitBlackList"; 3 | 4 | export async function getPermitBlackList(chain: string): Promise { 5 | const permitBlacklistRepository = (await getConnection()).getRepository(PermitBlackList); 6 | const blacklistedTokens = await permitBlacklistRepository 7 | .createQueryBuilder() 8 | .select("permitBlackList") 9 | .from(PermitBlackList, "permitBlackList") 10 | .where("permitBlackList.chain = :chain", { chain }) 11 | .getMany(); 12 | 13 | return blacklistedTokens; 14 | } 15 | -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/getSwapDailyVolume.ts: -------------------------------------------------------------------------------- 1 | import { SwapEvent } from "./Models/SwapEvent"; 2 | import { getConnection } from "."; 3 | 4 | export async function getSwapDailyVolume(date: string, chain: string): Promise { 5 | const swapEventRepository = (await getConnection()).getRepository(SwapEvent); 6 | const startOfDay = new Date(+date * 1000); 7 | startOfDay.setHours(0, 0, 0, 0); 8 | 9 | const endOfDay = new Date(+date * 1000); 10 | endOfDay.setHours(23, 59, 59, 999); 11 | 12 | const result = await swapEventRepository 13 | .createQueryBuilder("swapEvent") 14 | .select("SUM(swapEvent.amountUsd)", "totalUsdVolume") 15 | .where("swapEvent.createdAt BETWEEN :startOfDay AND :endOfDay", { 16 | startOfDay, 17 | endOfDay, 18 | }) 19 | .andWhere("swapEvent.isError = false") 20 | .andWhere(`swapEvent.chain = '${chain}'`) 21 | .getRawOne(); 22 | 23 | return result ? result.totalUsdVolume : "0"; 24 | } 25 | -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/getSwapTotalVolume.ts: -------------------------------------------------------------------------------- 1 | import { SwapEvent } from "./Models/SwapEvent"; 2 | import { getConnection } from "."; 3 | 4 | export async function getSwapTotalVolume(date: string, chain: string): Promise { 5 | const swapEventRepository = (await getConnection()).getRepository(SwapEvent); 6 | 7 | const result = await swapEventRepository 8 | .createQueryBuilder("swapEvent") 9 | .select("SUM(swapEvent.amountUsd)", "totalUsdVolume") 10 | .where("swapEvent.isError = false") 11 | .andWhere("swapEvent.createdAt <= TO_TIMESTAMP(:date)", { date }) 12 | .andWhere(`swapEvent.chain = '${chain}'`) 13 | .getRawOne(); 14 | 15 | return result ? result.totalUsdVolume : "0"; 16 | } 17 | -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/index.ts: -------------------------------------------------------------------------------- 1 | import "reflect-metadata"; 2 | 3 | import { DataSource } from "typeorm"; 4 | import { PermitBlackList } from "./Models/PermitBlackList"; 5 | import { SwapEvent } from "./Models/SwapEvent"; 6 | 7 | let AppDataSource: DataSource; 8 | let connection: Promise; 9 | 10 | function getAppDataSource() { 11 | if (!AppDataSource) 12 | AppDataSource = new DataSource({ 13 | type: "postgres", 14 | database: "content", 15 | entities: [SwapEvent, PermitBlackList], 16 | logging: false, 17 | synchronize: true, 18 | migrationsRun: true, 19 | url: process.env.AGGREGATOR_DB_URL, 20 | }); 21 | return AppDataSource; 22 | } 23 | 24 | async function getConnection() { 25 | if (!connection) { 26 | connection = getAppDataSource().initialize(); 27 | } 28 | return connection; 29 | } 30 | 31 | 32 | export { getConnection, getAppDataSource, }; 33 | -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/saveBlacklistPemrit.ts: -------------------------------------------------------------------------------- 1 | import { getConnection } from "."; 2 | import { PermitBlackList } from "./Models/PermitBlackList"; 3 | 4 | export const saveBlacklistPemrit = async ({ address, chain }: PermitBlackList) => { 5 | const blacklistedToken = new PermitBlackList(); 6 | blacklistedToken.address = address; 7 | blacklistedToken.chain = chain; 8 | 9 | const res = await (await getConnection()).manager.save(blacklistedToken); 10 | return res; 11 | }; 12 | -------------------------------------------------------------------------------- /defi/src/dexAggregators/db/saveEvent.ts: -------------------------------------------------------------------------------- 1 | import { getConnection } from "."; 2 | import { SwapEvent } from "./Models/SwapEvent"; 3 | 4 | export const saveEvent = async ({ 5 | user, 6 | aggregator, 7 | isError, 8 | chain, 9 | from, 10 | to, 11 | quote, 12 | txUrl, 13 | amount, 14 | errorData, 15 | amountUsd, 16 | slippage, 17 | routePlace, 18 | route, 19 | realOutput, 20 | reportedOutput, 21 | }: SwapEvent) => { 22 | const event = new SwapEvent(); 23 | event.aggregator = aggregator; 24 | event.user = user; 25 | event.isError = isError; 26 | event.chain = chain; 27 | event.from = from; 28 | event.to = to; 29 | event.quote = quote; 30 | event.txUrl = txUrl; 31 | event.amount = amount; 32 | event.errorData = errorData; 33 | event.amountUsd = amountUsd; 34 | event.slippage = slippage; 35 | event.routePlace = routePlace; 36 | event.route = route; 37 | event.realOutput = realOutput; 38 | event.reportedOutput = reportedOutput; 39 | 40 | const res = await (await getConnection()).manager.save(event); 41 | return res; 42 | }; 43 | -------------------------------------------------------------------------------- /defi/src/fallback.test.ts: -------------------------------------------------------------------------------- 1 | import fallback from "./fallback"; 2 | 3 | describe("snapshot of error provided", () => { 4 | it("executes as expected", async () => { 5 | const response = await fallback({ 6 | headers: {}, 7 | } as any); 8 | expect(response).toMatchSnapshot(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /defi/src/fallback.ts: -------------------------------------------------------------------------------- 1 | import { IResponse, wrap, errorResponse } from "./utils/shared"; 2 | 3 | const handler = async ( 4 | _event: AWSLambda.APIGatewayEvent 5 | ): Promise => { 6 | const response = errorResponse({ 7 | message: "This endpoint doesn't exist", 8 | } as any); 9 | if(response.headers===undefined){ 10 | response.headers={} 11 | } 12 | response.headers["Cache-Control"] = `max-age=${3600}`; // 1hr 13 | 14 | return response; 15 | }; 16 | 17 | export default wrap(handler); 18 | -------------------------------------------------------------------------------- /defi/src/fetchLiquidations.ts: -------------------------------------------------------------------------------- 1 | import adaptersModules from "./utils/imports/adapters_liquidations"; 2 | import { performance } from "perf_hooks"; 3 | import { storeCachedLiqsR2 } from "./utils/r2"; 4 | 5 | const handler = async (event: any, _context: AWSLambda.Context) => { 6 | const protocol = event.protocol as keyof typeof adaptersModules; 7 | const module = adaptersModules[protocol]; 8 | await Promise.all( 9 | Object.entries(module).map(async ([chain, liquidationsFunc]: [string, any]) => { 10 | try { 11 | const _start = performance.now(); 12 | console.log(`Fetching ${protocol} data for ${chain}`); 13 | const liquidations = await liquidationsFunc.liquidations(); 14 | await storeCachedLiqsR2(protocol, chain, JSON.stringify(liquidations)); 15 | const _end = performance.now(); 16 | console.log(`Fetched ${protocol} data for ${chain} in ${((_end - _start) / 1000).toLocaleString()}s`); 17 | } catch (e) { 18 | console.error(e); 19 | } 20 | }) 21 | ); 22 | }; 23 | 24 | export default handler; 25 | -------------------------------------------------------------------------------- /defi/src/getBlackListedTokens.ts: -------------------------------------------------------------------------------- 1 | import { getPermitBlackList } from "./dexAggregators/db/getPermitBlackList"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 5 | try { 6 | const chain = event.queryStringParameters?.chain; 7 | 8 | if (!chain) return successResponse({}, 10); 9 | 10 | const blacklist = await getPermitBlackList(chain); 11 | return successResponse(blacklist, 10); 12 | } catch (e) { 13 | console.log(e); 14 | return errorResponse({ message: "Something went wrong." }); 15 | } 16 | }; 17 | 18 | export default wrap(handler); 19 | -------------------------------------------------------------------------------- /defi/src/getChainAssetFlows.ts: -------------------------------------------------------------------------------- 1 | import { fetchFlows } from "../l2/storeToDb"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | import { quantisePeriod } from "../l2/utils"; 4 | import { secondsInDay } from "./utils/date"; 5 | import setEnvSecrets from "./utils/shared/setEnvSecrets"; 6 | 7 | const handler = async (event: any): Promise => { 8 | try { 9 | const period = event.pathParameters?.period 10 | ? quantisePeriod(event.pathParameters.period.toLowerCase()) 11 | : secondsInDay; 12 | await setEnvSecrets(); 13 | const percs = await fetchFlows(period); 14 | return successResponse(percs, 10 * 60); // 10 min cache 15 | } catch (e: any) { 16 | return errorResponse({ message: e.message }); 17 | } 18 | }; 19 | 20 | export default wrap(handler); 21 | -------------------------------------------------------------------------------- /defi/src/getChainAssetHistoricalFlows.ts: -------------------------------------------------------------------------------- 1 | import { fetchHistoricalFlows } from "../l2/storeToDb"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | import { quantisePeriod } from "../l2/utils"; 4 | import { secondsInDay } from "./utils/date"; 5 | import setEnvSecrets from "./utils/shared/setEnvSecrets"; 6 | 7 | const handler = async (event: any): Promise => { 8 | try { 9 | const period = event.pathParameters?.period 10 | ? quantisePeriod(event.pathParameters.period.toLowerCase()) 11 | : secondsInDay; 12 | const chain = event.pathParameters?.chain; 13 | if (!chain) throw new Error(`chain path param required`); 14 | await setEnvSecrets() 15 | const flows = await fetchHistoricalFlows(period, chain); 16 | return successResponse(flows, 10 * 60); // 10 min cache 17 | } catch (e: any) { 18 | return errorResponse({ message: e.message }); 19 | } 20 | }; 21 | 22 | export default wrap(handler); 23 | -------------------------------------------------------------------------------- /defi/src/getChainAssets.ts: -------------------------------------------------------------------------------- 1 | import { getR2 } from "./utils/r2"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (_event: any): Promise => { 5 | try { 6 | const chains = await getR2(`chainAssets`).then((res) => JSON.parse(res.body!)); 7 | return successResponse(chains, 10 * 60); // 10 min cache 8 | } catch (e: any) { 9 | return errorResponse({ message: e.message }); 10 | } 11 | }; 12 | 13 | export default wrap(handler); 14 | // handler({}); // ts-node defi/src/getChainAssets.ts 15 | -------------------------------------------------------------------------------- /defi/src/getChainAssetsChart.ts: -------------------------------------------------------------------------------- 1 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 2 | import { fetchHistoricalFromDB } from "../l2/storeToDb"; 3 | import setEnvSecrets from "./utils/shared/setEnvSecrets"; 4 | 5 | const handler = async (event: any): Promise => { 6 | try { 7 | const chainParam = event.pathParameters?.chain; 8 | const chain = chainParam.replace("%20", " "); 9 | await setEnvSecrets(); 10 | const chains = await fetchHistoricalFromDB(chain); 11 | return successResponse(chains, 10 * 60); // 10 min cache 12 | } catch (e: any) { 13 | return errorResponse({ message: e.message }); 14 | } 15 | }; 16 | 17 | export default wrap(handler); 18 | -------------------------------------------------------------------------------- /defi/src/getCoins.ts: -------------------------------------------------------------------------------- 1 | import { successResponse, wrap, IResponse } from "./utils/shared"; 2 | import dynamodb, {TableName} from "./utils/shared/dynamodb"; 3 | 4 | const step = 100; // Max 100 items per batchGet 5 | const handler = async ( 6 | event: AWSLambda.APIGatewayEvent 7 | ): Promise => { 8 | const requestedCoins = JSON.parse(event.body!).coins 9 | const requests = [] 10 | for (let i = 0; i < requestedCoins.length; i += step) { 11 | requests.push(dynamodb.batchGet( 12 | requestedCoins.slice(i, i+step).map((coin:string)=>({ 13 | PK: `asset#${coin}`, 14 | SK: 0 15 | })) 16 | ).then(items=>items.Responses![TableName])) 17 | } 18 | const returnedCoins = (await Promise.all(requests)).reduce((acc, coins)=>acc.concat(coins.map(coin=>({ 19 | "decimals": coin.decimals, 20 | coin: coin.PK.substr("asset#".length), 21 | "price": coin.price, 22 | "symbol": coin.symbol, 23 | "timestamp": coin.timestamp 24 | }))), []) 25 | return successResponse(returnedCoins); 26 | }; 27 | 28 | export default wrap(handler); 29 | -------------------------------------------------------------------------------- /defi/src/getConfig.ts: -------------------------------------------------------------------------------- 1 | import { successResponse, wrap, IResponse } from "./utils/shared"; 2 | import protocols from "./protocols/data"; 3 | import {chainCoingeckoIds} from "./utils/normalizeChain"; 4 | 5 | const handler = async ( 6 | _event: AWSLambda.APIGatewayEvent 7 | ): Promise => { 8 | return successResponse({ 9 | protocols, 10 | chainCoingeckoIds 11 | }, 30*60); 12 | }; 13 | 14 | export default wrap(handler); 15 | -------------------------------------------------------------------------------- /defi/src/getEmissionProtocol.ts: -------------------------------------------------------------------------------- 1 | import { getR2 } from "./utils/r2"; 2 | import { wrap, IResponse, notFoundResponse, successResponse } from "./utils/shared"; 3 | 4 | const handler = async (event: any): Promise => { 5 | const protocolName: string = event.pathParameters?.protocol; 6 | 7 | try { 8 | const data = await getR2(`emissions/${protocolName}`); 9 | return successResponse(data, 3600); 10 | } catch (e) { 11 | return notFoundResponse({ 12 | message: `protocol '${protocolName}' has no chart to fetch`, 13 | }); 14 | } 15 | }; 16 | 17 | export default wrap(handler); 18 | -------------------------------------------------------------------------------- /defi/src/getEmissions.ts: -------------------------------------------------------------------------------- 1 | import { getR2 } from "./utils/r2"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (_event: any): Promise => { 5 | const data = await getR2(`emissionsIndex`); 6 | if (data && data.body) return successResponse(JSON.parse(data.body).data, 3600); 7 | else return errorResponse({ message: "could not get/parse emissionsIndex" }); 8 | }; 9 | 10 | export default wrap(handler); 11 | //handler({}); // ts-node defi/src/getEmissions.ts 12 | -------------------------------------------------------------------------------- /defi/src/getEmissionsBreakdown.ts: -------------------------------------------------------------------------------- 1 | import { getR2 } from "./utils/r2"; 2 | import { wrap, IResponse, successResponse } from "./utils/shared"; 3 | 4 | const handler = async (_event: any): Promise => { 5 | const breakdown = await getR2("emissionsBreakdown").then((r) => JSON.parse(r?.body!)); 6 | const result = { 7 | protocols: Object.values(breakdown), 8 | emission24h: 0, 9 | emission7d: 0, 10 | emission30d: 0 11 | }; 12 | result.protocols.forEach((protocol: any) => { 13 | result.emission24h += protocol.emission24h; 14 | result.emission7d += protocol.emission7d; 15 | result.emission30d += protocol.emission30d; 16 | }); 17 | 18 | return successResponse(result, 10 * 60); // 10 min cache 19 | }; 20 | 21 | export default wrap(handler); 22 | -------------------------------------------------------------------------------- /defi/src/getEmissionsList.ts: -------------------------------------------------------------------------------- 1 | import { getR2 } from "./utils/r2"; 2 | import { wrap, IResponse, successResponse } from "./utils/shared"; 3 | 4 | const handler = async (_event: any): Promise => { 5 | const allProtocols = await getR2(`emissionsProtocolsList`).then((res) => 6 | JSON.parse(res.body!), 7 | ); 8 | return successResponse(allProtocols, 10 * 60); // 10 min cache 9 | }; 10 | 11 | export default wrap(handler); 12 | -------------------------------------------------------------------------------- /defi/src/getHourlyData.ts: -------------------------------------------------------------------------------- 1 | import { wrap, IResponse } from "./utils/shared"; 2 | import { craftProtocolResponse, wrapResponseOrRedirect } from "./getProtocol"; 3 | 4 | // undocumented and likely to change whenever I want 5 | // data returned will be wrong, requires cleaning 6 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 7 | const response = await craftProtocolResponse({ 8 | rawProtocolName: event.pathParameters?.protocol, 9 | useNewChainNames: true, 10 | useHourlyData: true, 11 | skipAggregatedTvl: false, 12 | }); 13 | return wrapResponseOrRedirect(response, "hourly/"); 14 | }; 15 | 16 | export default wrap(handler); 17 | -------------------------------------------------------------------------------- /defi/src/getLatestSwap.ts: -------------------------------------------------------------------------------- 1 | import { getLatestSwap } from "./dexAggregators/db/getLatestSwap"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 5 | try { 6 | const tokenA = event.queryStringParameters?.tokenA; 7 | const tokenB = event.queryStringParameters?.tokenB; 8 | if (!tokenA || !tokenB) return errorResponse({ message: "Invalid request." }); 9 | 10 | const swap = await getLatestSwap(tokenA!, tokenB!); 11 | 12 | if (swap) return successResponse(swap, 10); 13 | else return successResponse({}, 10); 14 | } catch (e) { 15 | console.log(e); 16 | return errorResponse({ message: "Something went wrong." }); 17 | } 18 | }; 19 | 20 | export default wrap(handler); 21 | -------------------------------------------------------------------------------- /defi/src/getNpmData.ts: -------------------------------------------------------------------------------- 1 | import { ecosystem } from "./developers/npm"; 2 | import { npmPK } from "./developers/utils"; 3 | import { successResponse, wrap, IResponse } from "./utils/shared"; 4 | import dynamodb from "./utils/shared/dynamodb"; 5 | 6 | const handler = async ( 7 | event: AWSLambda.APIGatewayEvent 8 | ): Promise => { 9 | const start = event.pathParameters!.start 10 | const packages = await Promise.all(Object.entries(ecosystem).map(([eco, pkgs])=>pkgs.map(pkg=>({eco, pkg}))).flat().map(async ({eco, pkg})=>{ 11 | const data = await dynamodb.query({ 12 | ExpressionAttributeValues: { 13 | ":pk": npmPK(pkg), 14 | ":begin": start, 15 | }, 16 | KeyConditionExpression: "PK = :pk AND SK > :begin" 17 | }) 18 | return ({ 19 | eco, 20 | pkg, 21 | downloads: data.Items!.map(({SK, downloads})=>[SK, downloads]) 22 | }) 23 | })) 24 | return successResponse(packages, 30*60); 25 | }; 26 | 27 | export default wrap(handler); 28 | -------------------------------------------------------------------------------- /defi/src/getProtocol.test.ts: -------------------------------------------------------------------------------- 1 | import protocols from './protocols/data' 2 | import getProtocol from './getProtocol' 3 | import sluggify from "./utils/sluggify"; 4 | import fetch from 'node-fetch'; 5 | 6 | jest.setTimeout(20e3) 7 | test("snapshots of responses", async () => { 8 | const filteredProtocols = protocols.slice(12,15).filter(protocol=>!protocol.name.startsWith('Karura ') && protocol.name !== "Genshiro") 9 | expect(await Promise.all(filteredProtocols.map(p => getProtocol({ 10 | pathParameters: { 11 | protocol: sluggify(p) 12 | } 13 | } as any)!.then((r:any)=>JSON.parse(r.body)) as Promise))) 14 | .toEqual(await Promise.all(filteredProtocols.map(p=>fetch(`https://api.llama.fi/protocol/${sluggify(p)}`).then(data=>data.json())))) 15 | }) -------------------------------------------------------------------------------- /defi/src/getSmolConfig.ts: -------------------------------------------------------------------------------- 1 | import { successResponse, wrap, IResponse, errorResponse } from "./utils/shared"; 2 | import protocols from "./protocols/data"; 3 | import parentProtocols from "./protocols/parentProtocols"; 4 | import sluggify from "./utils/sluggify"; 5 | 6 | const handler = async ( 7 | event: AWSLambda.APIGatewayEvent 8 | ): Promise => { 9 | const protocolName = event.pathParameters?.protocol?.toLowerCase(); 10 | const findFn = (prot: any) => sluggify(prot) === protocolName 11 | let protocolData: any = protocols.find(findFn); 12 | if (!protocolData) protocolData = parentProtocols.find(findFn); 13 | if (protocolData === undefined) { 14 | return errorResponse({ 15 | message: "Protocol is not in our database", 16 | }); 17 | } 18 | 19 | return successResponse(protocolData, 10 * 60); // 10 mins cache 20 | }; 21 | 22 | export default wrap(handler); -------------------------------------------------------------------------------- /defi/src/getSwapDailyVolume.ts: -------------------------------------------------------------------------------- 1 | import { getSwapDailyVolume } from "./dexAggregators/db/getSwapDailyVolume"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 5 | try { 6 | const timestamp = event.queryStringParameters?.timestamp; 7 | const chain = event.queryStringParameters?.chain; 8 | 9 | if (!timestamp || !chain) return successResponse({}, 10); 10 | 11 | const volume = await getSwapDailyVolume(timestamp, chain); 12 | return successResponse({ volume }, 10); 13 | } catch (e) { 14 | console.log(e); 15 | return errorResponse({ message: "Something went wrong." }); 16 | } 17 | }; 18 | 19 | export default wrap(handler); 20 | -------------------------------------------------------------------------------- /defi/src/getSwapTotalVolume.ts: -------------------------------------------------------------------------------- 1 | import { getSwapTotalVolume } from "./dexAggregators/db/getSwapTotalVolume"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 5 | try { 6 | const timestamp = event.queryStringParameters?.timestamp; 7 | const chain = event.queryStringParameters?.chain; 8 | 9 | if (!timestamp || !chain) return successResponse({}, 10); 10 | 11 | const volume = await getSwapTotalVolume(timestamp, chain); 12 | return successResponse({ volume }, 10); 13 | } catch (e) { 14 | console.log(e); 15 | return errorResponse({ message: "Something went wrong." }); 16 | } 17 | }; 18 | 19 | export default wrap(handler); 20 | -------------------------------------------------------------------------------- /defi/src/getSwapsHistory.ts: -------------------------------------------------------------------------------- 1 | import { getHistory } from "./dexAggregators/db/getHistory"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 5 | try { 6 | const userId = event.queryStringParameters?.userId; 7 | const chain = event.queryStringParameters?.chain; 8 | 9 | if (!userId || !chain) return successResponse({}, 10); 10 | 11 | const history = await getHistory(userId, chain); 12 | return successResponse(history, 10); 13 | } catch (e) { 14 | console.log(e); 15 | return errorResponse({ message: "Something went wrong." }); 16 | } 17 | }; 18 | 19 | export default wrap(handler); 20 | -------------------------------------------------------------------------------- /defi/src/getTotalProtocolUsersData.ts: -------------------------------------------------------------------------------- 1 | import { cache20MinResponse, wrap, IResponse } from "./utils/shared"; 2 | import { getTotalProtocolUsersData } from "./users/storeUsers"; 3 | 4 | async function handler(): Promise { 5 | return cache20MinResponse(await getTotalProtocolUsersData()) 6 | } 7 | 8 | export default wrap(handler); -------------------------------------------------------------------------------- /defi/src/getUpdatedProtocol.ts: -------------------------------------------------------------------------------- 1 | import { wrap, IResponse } from "./utils/shared"; 2 | import { craftProtocolResponse, wrapResponseOrRedirect } from "./getProtocol"; 3 | 4 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 5 | const includeAggregatedTvl = event.queryStringParameters?.includeAggregatedTvl?.toLowerCase(); 6 | 7 | const response = await craftProtocolResponse({ 8 | rawProtocolName: event.pathParameters?.protocol, 9 | useNewChainNames: true, 10 | useHourlyData: false, 11 | skipAggregatedTvl: includeAggregatedTvl && includeAggregatedTvl === "true" ? false : true, 12 | }); 13 | 14 | return wrapResponseOrRedirect(response, "updated/"); 15 | }; 16 | 17 | export default wrap(handler); 18 | -------------------------------------------------------------------------------- /defi/src/getYieldsConfig.ts: -------------------------------------------------------------------------------- 1 | import { cache20MinResponse, wrap, IResponse } from "./utils/shared"; 2 | import protocols from "./protocols/data"; 3 | import sluggify from "./utils/sluggify"; 4 | 5 | export function getYieldsConfig() { 6 | const final = {} as any 7 | protocols.forEach((p) => { 8 | final[sluggify(p)] = { 9 | name: p.name, 10 | audits: p.audits, 11 | audit_links: p.audit_links, 12 | url: p.url, 13 | twitter: p.twitter, 14 | category: p.category, 15 | symbol: p.symbol, 16 | } 17 | }) 18 | return { 19 | protocols: final 20 | } 21 | } 22 | 23 | const handler = async ( 24 | _event: AWSLambda.APIGatewayEvent 25 | ): Promise => { 26 | return cache20MinResponse(getYieldsConfig()); 27 | }; 28 | 29 | export default wrap(handler); 30 | -------------------------------------------------------------------------------- /defi/src/governance/test.ts: -------------------------------------------------------------------------------- 1 | import '../api2/utils/failOnError' 2 | 3 | 4 | import { updateSnapshots, } from './snapshot' 5 | import { updateTallys, } from './tally' 6 | import { updateCompounds, } from './compound' 7 | 8 | main().then(() => { 9 | console.log('done!') 10 | process.exit(0) 11 | }) 12 | 13 | async function main() { 14 | const funcs = { 15 | updateTallys, 16 | updateSnapshots, 17 | updateCompounds, 18 | } 19 | 20 | const promises = Object.entries(funcs).map(async ([key, fun]) => { 21 | const timeKey = 'Runtime_type_' + key 22 | console.time(timeKey) 23 | try { 24 | await fun() 25 | } catch (e) { 26 | console.error('Error fetching data for', key) 27 | console.error((e as any)?.message ?? e) 28 | } 29 | console.timeEnd(timeKey) 30 | }) 31 | await Promise.all(promises) 32 | } -------------------------------------------------------------------------------- /defi/src/governance/types.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface GovCache { 3 | id: string; 4 | metadata: { [key: string]: any }; 5 | proposals: { [key: string]: Proposal }; 6 | stats?: { [key: string]: any }; 7 | } 8 | export interface CompoundCache extends GovCache { 9 | } 10 | export interface Proposal { 11 | id: string; 12 | title?: string; 13 | state: string; 14 | app: string; 15 | author?: string; 16 | description?: string; 17 | space: any; 18 | choices?: any[]; 19 | network?: string; 20 | scores: number[]; 21 | scores_total: number; 22 | quorum: number; 23 | votes: number; 24 | score_skew: number; 25 | score_curve: number; 26 | score_curve2: number; 27 | start: number; 28 | end: number; 29 | month?: string; 30 | strategies?: any; 31 | executed?: boolean; 32 | link?:string; 33 | } 34 | export interface CompoundProposal extends Proposal { 35 | canceled: boolean; 36 | eta?: number; 37 | startBlock?: number; 38 | endBlock?: number; 39 | isInvalid?: boolean; 40 | } -------------------------------------------------------------------------------- /defi/src/growthReport.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 3 | 4 | export const daily = wrapScheduledLambda(async () => { 5 | await fetch("https://born-to-llama.herokuapp.com/send-daily-report") 6 | }); 7 | -------------------------------------------------------------------------------- /defi/src/jest-dynalite-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "tables": [ 3 | { 4 | "TableName": "test-table", 5 | "KeySchema": [ 6 | { "AttributeName": "PK", "KeyType": "HASH" }, 7 | { "AttributeName": "SK", "KeyType": "RANGE" } 8 | ], 9 | "AttributeDefinitions": [ 10 | { "AttributeName": "PK", "AttributeType": "S" }, 11 | { "AttributeName": "SK", "AttributeType": "S" } 12 | ], 13 | "ProvisionedThroughput": { 14 | "ReadCapacityUnits": 1, 15 | "WriteCapacityUnits": 1 16 | } 17 | } 18 | ], 19 | "basePort": 8000 20 | } 21 | -------------------------------------------------------------------------------- /defi/src/nfts/generateJson.ts: -------------------------------------------------------------------------------- 1 | import { writeFileSync } from "fs" 2 | import {nftParentCompanies} from "./parentCompanies" 3 | 4 | writeFileSync(__dirname+"/output/parentCompanies.json", JSON.stringify( 5 | nftParentCompanies.map(c=>({...c, nftCollections:c.nftCollections.map(cc=>[cc[0].toLowerCase(), cc[1]])})) 6 | , undefined, 2)); 7 | // npx ts-node src/nfts/generateJson.ts -------------------------------------------------------------------------------- /defi/src/notifyStaleCoins.ts: -------------------------------------------------------------------------------- 1 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 2 | import { 3 | notifyStaleCoins, 4 | notifyChangedAdapter, 5 | } from "./storeTvlInterval/staleCoins"; 6 | import setEnvSecrets from "./utils/shared/setEnvSecrets"; 7 | 8 | const handler = async (_event: any) => { 9 | await setEnvSecrets() 10 | await Promise.all([notifyStaleCoins(), notifyChangedAdapter()]); 11 | }; 12 | 13 | export default wrapScheduledLambda(handler); 14 | -------------------------------------------------------------------------------- /defi/src/operationalCosts/README.md: -------------------------------------------------------------------------------- 1 | Do not modify `output/expenses.json` directly! Instead modify `daos.ts` and then run `npx ts-node src/operationalCosts/generateOutput.ts` -------------------------------------------------------------------------------- /defi/src/operationalCosts/generateOutput.ts: -------------------------------------------------------------------------------- 1 | import { writeFileSync } from "fs" 2 | import daos from "./daos" 3 | 4 | writeFileSync(__dirname+"/output/expenses.json", JSON.stringify(daos)); -------------------------------------------------------------------------------- /defi/src/overrideChainAssets.ts: -------------------------------------------------------------------------------- 1 | import storeChainAssets from "../l2"; 2 | import { sendMessage } from "./utils/discord"; 3 | import { withTimeout } from "./utils/shared/withTimeout"; 4 | 5 | export async function handler() { 6 | try { 7 | await withTimeout(8400000, storeChainAssets(true)); // 140 mins 8 | } catch (e) { 9 | process.env.CHAIN_ASSET_WEBHOOK ? await sendMessage(`${e}`, process.env.CHAIN_ASSET_WEBHOOK!) : console.log(e); 10 | process.exit(); 11 | } 12 | } 13 | 14 | handler(); // ts-node defi/src/overrideChainAssets.ts 15 | -------------------------------------------------------------------------------- /defi/src/protocols/dexVolumes.ts: -------------------------------------------------------------------------------- 1 | export interface Dex { 2 | id: string; 3 | name: string; 4 | module: string; 5 | } 6 | 7 | export default [ 8 | { 9 | id: 1, 10 | name: "Uniswap", 11 | module: "uniswap", 12 | }, 13 | ]; 14 | -------------------------------------------------------------------------------- /defi/src/protocols/import.test.ts: -------------------------------------------------------------------------------- 1 | const { importAdapterDynamic } = require("../utils/imports/importAdapter"); 2 | const protocols = require("./data"); 3 | 4 | for (const protocol of Object.values(protocols.default)) { 5 | importAdapterDynamic(protocol) 6 | } 7 | process.exit(0); -------------------------------------------------------------------------------- /defi/src/protocols/treasury.ts: -------------------------------------------------------------------------------- 1 | import protocols, { Protocol } from './data' 2 | import type { IParentProtocol } from "./types"; 3 | import parentProtocols from "./parentProtocols"; 4 | 5 | export const treasuries: Protocol[] = [...protocols, ...parentProtocols].filter(i => i.treasury).map((i: Protocol | IParentProtocol) => { 6 | const clone: Protocol = JSON.parse(JSON.stringify(i)) 7 | clone.id = `${i.id}-treasury` 8 | clone.module = `treasury/${i.treasury}` 9 | clone.name = `${i.name} (treasury)` 10 | return clone 11 | }) 12 | 13 | export default treasuries -------------------------------------------------------------------------------- /defi/src/server-scripts/notifyOutdated.ts: -------------------------------------------------------------------------------- 1 | import { notifyOutdatedPG } from "../notifyOutdated"; 2 | 3 | notifyOutdatedPG().catch(console.error).then(() => process.exit(0)) -------------------------------------------------------------------------------- /defi/src/setupTestEnv.js: -------------------------------------------------------------------------------- 1 | process.env.tableName = `test-table` -------------------------------------------------------------------------------- /defi/src/storeAggregatorEvent.ts: -------------------------------------------------------------------------------- 1 | import { saveEvent } from "./dexAggregators/db/saveEvent"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 5 | try { 6 | const body = JSON.parse(event.body!); 7 | 8 | const swapEvent = await saveEvent(body); 9 | return successResponse(swapEvent, 10); 10 | } catch (e) { 11 | console.log(e); 12 | return errorResponse({ message: "Something went wrong." }); 13 | } 14 | }; 15 | 16 | export default wrap(handler); 17 | -------------------------------------------------------------------------------- /defi/src/storeBlacklistPermit.ts: -------------------------------------------------------------------------------- 1 | import { saveBlacklistPemrit } from "./dexAggregators/db/saveBlacklistPemrit"; 2 | import { wrap, IResponse, successResponse, errorResponse } from "./utils/shared"; 3 | 4 | const handler = async (event: AWSLambda.APIGatewayEvent): Promise => { 5 | try { 6 | const body = JSON.parse(event.body!); 7 | 8 | const blacklistedToken = await saveBlacklistPemrit(body); 9 | return successResponse(blacklistedToken, 10); 10 | } catch (e) { 11 | console.log(e); 12 | return errorResponse({ message: "Something went wrong." }); 13 | } 14 | }; 15 | 16 | export default wrap(handler); 17 | -------------------------------------------------------------------------------- /defi/src/storeChainAssets.ts: -------------------------------------------------------------------------------- 1 | import storeChainAssets from "../l2"; 2 | import { sendMessage } from "./utils/discord"; 3 | import { withTimeout } from "./utils/shared/withTimeout"; 4 | 5 | export async function handler() { 6 | try { 7 | await withTimeout(8400000, storeChainAssets(false)); // 140 mins 8 | } catch (e) { 9 | process.env.CHAIN_ASSET_WEBHOOK ? await sendMessage(`${e}`, process.env.CHAIN_ASSET_WEBHOOK!) : console.log(e); 10 | process.exit(); 11 | } 12 | } 13 | 14 | handler(); // ts-node defi/src/storeChainAssets.ts 15 | -------------------------------------------------------------------------------- /defi/src/storeCsvDataset.ts: -------------------------------------------------------------------------------- 1 | import allProtocols from "./protocols/data"; 2 | import craftCsvDataset from './storeTvlUtils/craftCsvDataset' 3 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 4 | import { store } from "./utils/s3"; 5 | import { storeR2 } from "./utils/r2"; 6 | 7 | const handler = async (_event: any) => { 8 | const csv = await craftCsvDataset(allProtocols, false, true); 9 | await storeR2('all.csv', csv); 10 | await store('all.csv', csv); 11 | }; 12 | 13 | export default wrapScheduledLambda(handler); 14 | -------------------------------------------------------------------------------- /defi/src/storeGovernance.ts: -------------------------------------------------------------------------------- 1 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 2 | import { updateSnapshots } from "./governance/snapshot"; 3 | import { updateCompounds } from "./governance/compound"; 4 | 5 | async function handler() { 6 | await Promise.all([ 7 | updateSnapshots(), 8 | updateCompounds() 9 | ]) 10 | } 11 | 12 | export default wrapScheduledLambda(handler); 13 | -------------------------------------------------------------------------------- /defi/src/storeNpmData.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | import { ecosystem } from "./developers/npm" 3 | import { npmPK } from "./developers/utils" 4 | import dynamodb from "./utils/shared/dynamodb" 5 | import { wrapScheduledLambda } from "./utils/shared/wrap" 6 | 7 | export async function storeNpmDayData(day: string) { 8 | await Promise.all(Object.values(ecosystem).flat().map(async pkg => { 9 | const api = `https://api.npmjs.org/downloads/point/${day}/${pkg}` 10 | const data = await fetch(api).then(r => r.json()) 11 | if(data.error !== undefined){ 12 | throw new Error(`Can't find data for ${pkg} on date ${day}`) 13 | } 14 | await dynamodb.put({ 15 | PK: npmPK(pkg), 16 | SK: Math.round(new Date(data.start).getTime()/1000), 17 | downloads: data.downloads, 18 | }) 19 | })) 20 | } 21 | 22 | const handler = async () => { 23 | await storeNpmDayData("last-day"); 24 | }; 25 | 26 | export default wrapScheduledLambda(handler); -------------------------------------------------------------------------------- /defi/src/storeTvlInterval.ts: -------------------------------------------------------------------------------- 1 | import storeTvls from "./storeTvlInterval/storeTvls"; 2 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 3 | 4 | const handler = async (event: any, context:AWSLambda.Context) => { 5 | await storeTvls(event.protocolIndexes, context.getRemainingTimeInMillis); 6 | }; 7 | 8 | export default wrapScheduledLambda(handler); 9 | -------------------------------------------------------------------------------- /defi/src/storeTvlInterval/storeTvls.test.ts: -------------------------------------------------------------------------------- 1 | import storeTvls from "./storeTvls"; 2 | import ddb from "../utils/shared/dynamodb"; 3 | 4 | describe("storeRates", () => { 5 | test("works properly", async () => { 6 | await storeTvls(Array.from(Array(100).keys())); 7 | }); 8 | 9 | test("snapshot db state", async () => { 10 | Date.now = jest.fn(() => 1487076708000); // 14.02.2017 11 | await storeTvls(Array.from(Array(100).keys())); 12 | expect(await ddb.scan()).toMatchSnapshot(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /defi/src/triggerFetchLiquidations.ts: -------------------------------------------------------------------------------- 1 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 2 | import invokeLambda from "./utils/shared/invokeLambda"; 3 | 4 | export const standaloneProtocols: string[] = ["venus"]; 5 | 6 | const handler = async () => { 7 | for (let protocol of standaloneProtocols) { 8 | const event = { 9 | protocol, 10 | }; 11 | await invokeLambda(`defillama-prod-fetchLiquidations`, event); 12 | } 13 | }; 14 | 15 | export default wrapScheduledLambda(handler); 16 | -------------------------------------------------------------------------------- /defi/src/triggerStoreTreasuries.ts: -------------------------------------------------------------------------------- 1 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 2 | import invokeLambda from "./utils/shared/invokeLambda"; 3 | import { treasuriesAndEntities } from "./protocols/entities"; 4 | import { shuffleArray } from "./utils/shared/shuffleArray"; 5 | 6 | const step = 40; 7 | const handler = async () => { 8 | const protocolIndexes = Array.from(Array(treasuriesAndEntities.length).keys()); 9 | shuffleArray(protocolIndexes); 10 | for (let i = 0; i < treasuriesAndEntities.length; i += step) { 11 | const event = { 12 | protocolIndexes: protocolIndexes.slice(i, i+step) 13 | }; 14 | await invokeLambda(`defillama-prod-storeTreasuryInterval`, event); 15 | } 16 | }; 17 | 18 | export default wrapScheduledLambda(handler); 19 | -------------------------------------------------------------------------------- /defi/src/triggerStoreTvls.ts: -------------------------------------------------------------------------------- 1 | import { wrapScheduledLambda } from "./utils/shared/wrap"; 2 | import protocols from "./protocols/data"; 3 | import invokeLambda from "./utils/shared/invokeLambda"; 4 | import { shuffleArray } from "./utils/shared/shuffleArray"; 5 | 6 | const step = 40; 7 | const handler = async () => { 8 | const protocolIndexes = Array.from(Array(protocols.length).keys()); 9 | shuffleArray(protocolIndexes); 10 | for (let i = 0; i < protocols.length; i += step) { 11 | const event = { 12 | protocolIndexes: protocolIndexes.slice(i, i+step) 13 | }; 14 | await invokeLambda(`defillama-prod-storeTvlInterval2`, event); 15 | } 16 | }; 17 | 18 | export default wrapScheduledLambda(handler); 19 | -------------------------------------------------------------------------------- /defi/src/twitter/setLastTweet.ts: -------------------------------------------------------------------------------- 1 | import { init, close, getAllUsers, getLastTweet, updateUser, } from './db' 2 | import { transformHandleV2 } from './utils' 3 | 4 | 5 | async function run() { 6 | await init() 7 | const users = await getAllUsers() 8 | console.log('users: ', users.length) 9 | let i = 0 10 | 11 | for (let userData of users) { 12 | i++ 13 | try { 14 | if (userData.lastTweet?.text) continue; 15 | const handle = userData.handle 16 | const lastTweet = await getLastTweet(handle) 17 | if (!lastTweet) { 18 | console.log('no tweet found for: ', handle) 19 | continue; 20 | } 21 | userData = transformHandleV2({ handleData: userData, lastTweet, }) 22 | console.log(i, '/', users.length, 'updating user: ', handle, userData.lastTweet) 23 | await updateUser(userData) 24 | } catch (e) { 25 | console.log('error while updating tweets: ', userData.handle) 26 | console.error(e) 27 | } 28 | } 29 | } 30 | 31 | run().catch(console.error).then(async () => { 32 | await close() 33 | process.exit(0) 34 | }) 35 | -------------------------------------------------------------------------------- /defi/src/users/data-adapters.test.ts: -------------------------------------------------------------------------------- 1 | import userAdapters from "@defillama/dimension-adapters/users/list"; 2 | 3 | test("no id is repeated in user adapters", async () => { 4 | const ids = []; 5 | for (const protocol of userAdapters) { 6 | expect(ids).not.toContain(protocol.id); 7 | ids.push(protocol.id); 8 | } 9 | }); -------------------------------------------------------------------------------- /defi/src/utils/airtable.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export async function getAllAirtableRecords(sheet: string) { 4 | let offset; 5 | let allRecords = [] as any[]; 6 | if (!process.env.AIRTABLE_API_KEY) throw new Error("Missing AIRTABLE_API_KEY"); 7 | do { 8 | const { data }: any = await axios.get( 9 | `https://api.airtable.com/v0/${sheet}${offset ? `?offset=${offset}` : ""}`, 10 | { 11 | headers: { 12 | Authorization: (process.env.AIRTABLE_API_KEY!).replace(/("|')/g, ''), 13 | }, 14 | } 15 | ) 16 | if (!data.records){ 17 | console.log("airtable error", data) 18 | throw new Error('error fetching data from Airtable') 19 | } 20 | offset = data.offset; 21 | allRecords = allRecords.concat(data.records); 22 | } while (offset !== undefined); 23 | return allRecords 24 | } -------------------------------------------------------------------------------- /defi/src/utils/coingeckoPlatforms.test.ts: -------------------------------------------------------------------------------- 1 | import chainToCoingeckoId from "../../../common/chainToCoingeckoId"; 2 | import {platformMap} from "./coingeckoPlatforms" 3 | 4 | test("platformMap", () => { 5 | const sdkPlatforms = Object.entries(chainToCoingeckoId).reduce((o: any, i) => { o[i[1]] = i[0]; return o }, {}) 6 | expect(platformMap).toEqual(sdkPlatforms) 7 | console.log(platformMap) 8 | }) -------------------------------------------------------------------------------- /defi/src/utils/date.test.ts: -------------------------------------------------------------------------------- 1 | import {getTimestampAtStartOfDay,getDay, getClosestDayStartTimestamp} from "./date" 2 | 3 | test("getTimestampAtStartOfDay", ()=>{ 4 | expect(getTimestampAtStartOfDay(1631772242)).toBe(1631750400) 5 | }) 6 | 7 | test("getDay", ()=>{ 8 | const start = 1631750400 9 | for(let ts = start; ts{ 16 | expect(getClosestDayStartTimestamp(1631750400-1)).toBe(1631750400) 17 | expect(getClosestDayStartTimestamp(1631750400+1)).toBe(1631750400) 18 | expect(getClosestDayStartTimestamp(1631793104)).toBe(1631750400) 19 | }) -------------------------------------------------------------------------------- /defi/src/utils/error.ts: -------------------------------------------------------------------------------- 1 | export function reportError(message: string, protocolName: string) { 2 | console.error(protocolName, message); 3 | } 4 | 5 | /* 6 | export const PUT_DAILY_VOLUME_ERROR = "PUT_DAILY_VOLUME"; 7 | 8 | export function reportDexVolumeError({ 9 | id, 10 | timestamp, 11 | category, 12 | message, 13 | }: { 14 | id: number; 15 | timestamp: number; 16 | category: string; 17 | message: string; 18 | }) { 19 | const scope = new Sentry.Scope(); 20 | const errorName = `${id}-${timestamp}-${category}`; 21 | scope.setTag("dexvolume", id); 22 | const error = new Error(message); 23 | error.name = errorName; 24 | Sentry.AWSLambda.captureException(error, scope); 25 | throw error; 26 | } 27 | */ -------------------------------------------------------------------------------- /defi/src/utils/excludeProtocols.ts: -------------------------------------------------------------------------------- 1 | import { Protocol } from "../protocols/data"; 2 | 3 | export function excludeProtocolInCharts(protocol: Protocol, includeBridge?: boolean) { 4 | let exclude = false; 5 | const excludedCategories = ['Chain', 'CEX', 'Infrastructure', 'Staking Pool'] 6 | 7 | if (excludedCategories.includes(protocol.category!)) { 8 | return true; 9 | } 10 | 11 | if (!includeBridge) { 12 | exclude = protocol.name === "AnySwap" || protocol.category === "Bridge"; 13 | } 14 | 15 | return exclude; 16 | } 17 | 18 | export function isExcludedFromChainTvl(category?: string) { 19 | return category === "RWA" || category === "Basis Trading" || category === "CeDeFi"; 20 | } 21 | 22 | export const includeCategoryIntoChainTvl = (category?:string)=>{ 23 | if(category === undefined) return true 24 | return !["Bridge", "RWA", "Basis Trading", "CeDeFi"].includes(category) 25 | } -------------------------------------------------------------------------------- /defi/src/utils/imports/importDexAdapters.ts: -------------------------------------------------------------------------------- 1 | import { Dex } from "../../dexVolumes/dexAdapters"; 2 | import adapters from "./adapters_volumes" 3 | 4 | // TODO: needs to be optimized 5 | export function importVolumeAdapter(dex: Dex) { 6 | return (adapters as any)[dex.volumeAdapter] 7 | } -------------------------------------------------------------------------------- /defi/src/utils/shared/coingeckoLocks.ts: -------------------------------------------------------------------------------- 1 | const locks = [] as ((value: unknown) => void)[]; 2 | export function getCoingeckoLock() { 3 | return new Promise((resolve) => { 4 | locks.push(resolve); 5 | }); 6 | } 7 | export function releaseCoingeckoLock() { 8 | const firstLock = locks.shift(); 9 | if (firstLock !== undefined) { 10 | firstLock(null); 11 | } 12 | } 13 | // Rate limit is 500 calls/min for coingecko's API 14 | // So we'll release one every 0.2 seconds to match it 15 | export function setTimer(timeBetweenTicks: number = 200) { 16 | const timer = setInterval(() => { 17 | releaseCoingeckoLock(); 18 | }, timeBetweenTicks); 19 | return timer; 20 | } -------------------------------------------------------------------------------- /defi/src/utils/shared/constants.ts: -------------------------------------------------------------------------------- 1 | const DAY = 3600 * 24; 2 | 3 | export const searchWidth = DAY; 4 | 5 | export const chainsThatShouldNotBeLowerCased = ["solana", "bitcoin", "eclipse"]; 6 | 7 | export const bridgedTvlMixedCaseChains: string[] = ["solana", "tron", "sui", "aptos", "eclipse"]; 8 | 9 | export const chainsWithCaseSensitiveDataProviders = ['aptos', 'stacks', 'sui'] 10 | 11 | export const nullAddress = "0x0000000000000000000000000000000000000000"; 12 | -------------------------------------------------------------------------------- /defi/src/utils/shared/getRecordClosestToTimestamp.ts: -------------------------------------------------------------------------------- 1 | import dynamodb from "./dynamodb"; 2 | 3 | export default async function getTVLOfRecordClosestToTimestamp( 4 | PK: string, 5 | timestamp: number, 6 | searchWidth: number 7 | ) { 8 | return dynamodb 9 | .query({ 10 | ExpressionAttributeValues: { 11 | ":pk": PK, 12 | ":begin": timestamp - searchWidth, 13 | ":end": timestamp + searchWidth 14 | }, 15 | KeyConditionExpression: "PK = :pk AND SK BETWEEN :begin AND :end" 16 | }) 17 | .then((records) => { 18 | if (records.Items == undefined || records.Items.length == 0) { 19 | return { 20 | SK: undefined 21 | }; 22 | } 23 | let closest = records.Items[0]; 24 | for (const item of records.Items.slice(1)) { 25 | if (Math.abs(item.SK - timestamp) < Math.abs(closest.SK - timestamp)) { 26 | closest = item; 27 | } 28 | } 29 | return closest; 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /defi/src/utils/shared/getRecordEarliestTimestamp.ts: -------------------------------------------------------------------------------- 1 | import dynamodb from "./dynamodb"; 2 | 3 | export default async function getRecordEarliestTimestamp(PK: string) { 4 | return dynamodb 5 | .query({ 6 | ExpressionAttributeValues: { 7 | ":pk": PK, 8 | ":sk": 0 9 | }, 10 | KeyConditionExpression: "PK = :pk AND SK > :sk", 11 | Limit: 1, 12 | ScanIndexForward: true 13 | }) 14 | .then((res) => res.Items?.[0]); 15 | } 16 | -------------------------------------------------------------------------------- /defi/src/utils/shared/index.ts: -------------------------------------------------------------------------------- 1 | export { default as wrap } from "./wrap"; 2 | export * from "./lambda-response"; 3 | -------------------------------------------------------------------------------- /defi/src/utils/shared/invokeLambda.ts: -------------------------------------------------------------------------------- 1 | import aws from "aws-sdk"; 2 | 3 | export default async function invokeLambda(functioName: string, event: any) { 4 | return new Promise((resolve, _reject) => { 5 | new aws.Lambda().invoke( 6 | { 7 | FunctionName: functioName, 8 | InvocationType: "Event", 9 | Payload: JSON.stringify(event, null, 2), // pass params 10 | }, 11 | function (error, data) { 12 | console.log(error, data); 13 | resolve(data); 14 | } 15 | ); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /defi/src/utils/shared/lambda-response.test.ts: -------------------------------------------------------------------------------- 1 | import { errorResponse } from "./lambda-response"; 2 | 3 | test("errorResponse works with both field and without", () => { 4 | expect(errorResponse({ message: "supp" })) 5 | .toMatchInlineSnapshot(` 6 | Object { 7 | "body": "{\\"message\\":\\"supp\\",\\"field\\":\\"email\\"}", 8 | "headers": Object { 9 | "Access-Control-Allow-Origin": "*", 10 | "Content-Type": "application/json", 11 | }, 12 | "statusCode": 400, 13 | } 14 | `); 15 | expect(errorResponse({ message: "supp" }).body).toEqual( 16 | JSON.stringify({ 17 | message: "supp", 18 | }) 19 | ); 20 | }); 21 | -------------------------------------------------------------------------------- /defi/src/utils/shared/parseRequestBody.test.ts: -------------------------------------------------------------------------------- 1 | import parseRequestBody from "./parseRequestBody"; 2 | 3 | test("invalid json body is rejected", () => { 4 | expect(() => { 5 | parseRequestBody("fake"); 6 | }).toThrowErrorMatchingInlineSnapshot( 7 | `"Message body is not a valid JSON object"` 8 | ); 9 | }); 10 | 11 | test("parsed JSON object is returned", () => { 12 | expect(parseRequestBody('{"a":"b"}')).toEqual({ 13 | a: "b", 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /defi/src/utils/shared/parseRequestBody.ts: -------------------------------------------------------------------------------- 1 | export default function (rawBody: null | string): any { 2 | if (rawBody === null) { 3 | throw new Error("No message body was provided"); 4 | } 5 | let body; 6 | try { 7 | body = JSON.parse(rawBody); 8 | } catch (e) { 9 | throw new Error("Message body is not a valid JSON object"); 10 | } 11 | return body; 12 | } 13 | -------------------------------------------------------------------------------- /defi/src/utils/shared/setEnvSecrets.ts: -------------------------------------------------------------------------------- 1 | import dynamodb from './dynamodb' 2 | let envSecretsRes: any 3 | 4 | async function setEnvSecrets() { 5 | try { 6 | if (!envSecretsRes) envSecretsRes = dynamodb.getEnvSecrets() 7 | const { Item } = await envSecretsRes 8 | Object.entries((Item as any)).forEach(([key, value]: any) => { 9 | if (key !== 'PK' && key !== 'SK') process.env[key] = value 10 | }) 11 | } catch (e) { 12 | console.log('Unable to get env secrets: ', e) 13 | } 14 | } 15 | 16 | export default setEnvSecrets; -------------------------------------------------------------------------------- /defi/src/utils/shared/shuffleArray.ts: -------------------------------------------------------------------------------- 1 | export function shuffleArray(array: any[]) { 2 | for (let i = array.length - 1; i > 0; i--) { 3 | const j = Math.floor(Math.random() * (i + 1)); 4 | [array[i], array[j]] = [array[j], array[i]]; 5 | } 6 | return array 7 | } -------------------------------------------------------------------------------- /defi/src/utils/shared/sleep.ts: -------------------------------------------------------------------------------- 1 | export default function sleep(ms: number) { 2 | return new Promise((resolve) => setTimeout(resolve, ms)); 3 | } 4 | -------------------------------------------------------------------------------- /defi/src/utils/shared/withTimeout.ts: -------------------------------------------------------------------------------- 1 | export const withTimeout = (millis: number, promise: any, id: string = "") => { 2 | const timeout = new Promise((resolve, reject) => 3 | setTimeout(() => { 4 | reject(`${id} timed out after ${millis / 1000} s.`); 5 | resolve; 6 | }, millis) 7 | ); 8 | return Promise.race([promise, timeout]); 9 | }; 10 | -------------------------------------------------------------------------------- /defi/src/utils/sluggify.ts: -------------------------------------------------------------------------------- 1 | import type { Protocol } from "../protocols/data"; 2 | 3 | export const sluggifyString = (name: string) => name.toLowerCase().split(" ").join("-").split("'").join(""); 4 | export default (prot: Protocol) => sluggifyString(prot.name) -------------------------------------------------------------------------------- /defi/src/utils/standardizeProtocolName.ts: -------------------------------------------------------------------------------- 1 | const standardizeProtocolName = (tokenName = '') => 2 | tokenName.toLowerCase().split('-').join(' ') 3 | 4 | 5 | export default standardizeProtocolName -------------------------------------------------------------------------------- /defi/src/utils/symbols/convert.ts: -------------------------------------------------------------------------------- 1 | import cgSymbols from "./symbols.json" 2 | 3 | export function convertSymbols(balances: { 4 | [symbol:string]: number 5 | }){ 6 | Object.entries(balances).forEach(([symbol, amount])=>{ 7 | const properSymbol = normalizeCgIds(symbol) 8 | if(properSymbol!==undefined){ 9 | balances[properSymbol] = (balances[properSymbol] ?? 0) + amount 10 | delete balances[symbol] 11 | } 12 | }) 13 | } 14 | 15 | export function normalizeCgIds(token: string): string | undefined { 16 | const suffix = token.startsWith('coingecko:') ? token.substring(10) : token 17 | const properSymbol = (cgSymbols as {[s:string]:string|undefined})[suffix] 18 | return properSymbol 19 | } -------------------------------------------------------------------------------- /defi/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "ts-node": { 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | }, 7 | "compilerOptions": { 8 | "target": "es2019", 9 | "skipLibCheck": false, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "emitDecoratorMetadata": true, 13 | "experimentalDecorators": true, 14 | "strictPropertyInitialization": false, 15 | "strict": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "noEmit": false, 21 | "jsx": "preserve", 22 | "allowJs": true, 23 | "noImplicitThis": false, 24 | "noUnusedLocals": false, 25 | "noUnusedParameters": true, 26 | "lib": [ 27 | "ES2019", 28 | "DOM" 29 | ] 30 | }, 31 | "include": [ 32 | "src", 33 | "/**/*.ts" 34 | ], 35 | "exclude": [ 36 | "src/setupTestEnv.js", 37 | "DefiLlama-Adapters/**/*.js", 38 | "src/**/*js", 39 | "src/cli/backfillDexVolumes" 40 | ] 41 | } -------------------------------------------------------------------------------- /defi/ui-tool/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /defi/ui-tool/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-tool", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@ant-design/icons": "^6.0.0", 7 | "@ant-design/plots": "^2.4.0", 8 | "antd": "^5.24.7", 9 | "react": "^19.1.0", 10 | "react-dom": "^19.1.0", 11 | "react-scripts": "5.0.1", 12 | "ws": "^8.18.1" 13 | }, 14 | "scripts": { 15 | "start-react": "react-scripts start", 16 | "start-server": "npx ts-node --transpile-only --logError src/server.ts", 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": [ 23 | "react-app", 24 | "react-app/jest" 25 | ] 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /defi/ui-tool/public/gib.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefiLlama/defillama-server/2c08af5d517e7f56965ba85d372cc484dab93d8c/defi/ui-tool/public/gib.webp -------------------------------------------------------------------------------- /defi/ui-tool/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | UI Tool 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /defi/ui-tool/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /defi/ui-tool/src/App.css: -------------------------------------------------------------------------------- 1 | .layout { 2 | min-height: 100vh; 3 | } 4 | 5 | .content { 6 | padding: 24px; 7 | max-width: 500px; 8 | margin: 24px auto; 9 | border-radius: 8px; 10 | } 11 | 12 | .footer { 13 | text-align: center; 14 | } 15 | 16 | .output-container { 17 | /* background-color: #f0f0f0; */ 18 | border-radius: 4px; 19 | padding: 16px; 20 | max-height: 60vh; 21 | overflow-y: auto; 22 | font-family: 'Courier New', Courier, monospace; 23 | } 24 | 25 | .output-container pre { 26 | margin: 0; 27 | white-space: pre-wrap; 28 | } -------------------------------------------------------------------------------- /defi/ui-tool/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /defi/ui-tool/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | const root = ReactDOM.createRoot(document.getElementById('root')); 7 | root.render( 8 | 9 | 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /defi/webpack.config.js: -------------------------------------------------------------------------------- 1 | const slsw = require('serverless-webpack-fixed'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | entry: slsw.lib.entries, 6 | target: 'node', 7 | mode: slsw.lib.webpack.isLocal ? 'development' : 'production', 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.ts$/, 12 | use: 'ts-loader', 13 | include: path.resolve(__dirname, "src"), 14 | exclude: /node_modules/, 15 | }, 16 | { 17 | test: /\.js$/, 18 | include: __dirname, 19 | exclude: /node_modules/, 20 | use: { 21 | loader: 'babel-loader', 22 | }, 23 | }, 24 | { 25 | test: /\.mjs$/, 26 | resolve: { mainFields: ["default"] } 27 | } 28 | ], 29 | }, 30 | resolve: { 31 | extensions: ['.ts', '.js', '.json'], 32 | alias: { 33 | 'bignumber.js$': 'bignumber.js/bignumber.js', 34 | 'node-fetch$': 'node-fetch/lib/index.js' 35 | } 36 | } 37 | }; 38 | --------------------------------------------------------------------------------