Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Strategies API #107

Merged
merged 5 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/app/api/strategies/route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,67 @@
import { NextResponse } from 'next/server';
import { atom } from 'jotai';
import ZkLendAtoms from '@/store/zklend.store';
import { PoolInfo } from '@/store/pools';
import NostraLendingAtoms from '@/store/nostralending.store';
import { RpcProvider } from 'starknet';
import { getStrategies } from '@/store/strategies.atoms';
import { MY_STORE } from '@/store';
import MyNumber from '@/utils/MyNumber';
import { NFTInfo, TokenInfo } from '@/strategies/IStrategy';

export const revalidate = 3600; // 1 hr

const allPoolsAtom = atom<PoolInfo[]>((get) => {
const pools: PoolInfo[] = [];
const poolAtoms = [ZkLendAtoms, NostraLendingAtoms];
return poolAtoms.reduce((_pools, p) => _pools.concat(get(p.pools)), pools);
return [];
});

async function getPools(store: any, retry = 0) {
const allPools = store.get(allPoolsAtom);
if (!allPools.length && retry < 10) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return getPools(store, retry + 1);
}
if (retry >= 10) {
throw new Error('Failed to fetch pools');
}
return allPools;
}

const provider = new RpcProvider({
nodeUrl: process.env.RPC_URL || 'https://starknet-mainnet.public.blastapi.io',
});

export async function GET(req: Request) {

Check warning on line 37 in src/app/api/strategies/route.ts

View workflow job for this annotation

GitHub Actions / Performs linting, formatting on the application

'req' is defined but never used. Allowed unused args must match /^_/u
const allPools = await getPools(MY_STORE);
const strategies = getStrategies();
strategies.forEach((strategy) => {
strategy.solve(allPools, '1000');
});

try {
return NextResponse.json({
status: true,
strategies: strategies.map((s) => {
return {
name: s.name,
id: s.id,
apy: s.netYield,
depositToken: s
.depositMethods(MyNumber.fromZero(), '', provider)
.map((t) => t.tokenInfo.token),
leverage: s.leverage,
contract: s.holdingTokens.map((t) => ({
name: t.name,
address: (<any>t).token
? (<TokenInfo>t).token
: (<NFTInfo>t).address,
})),
status: s.liveStatus,
};
}),
});
} catch (err) {
console.error('Error /api/strategies', err);
Expand Down
3 changes: 2 additions & 1 deletion src/app/slinks/template.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import Navbar from '@/components/Navbar';
import { MY_STORE } from '@/store';
import {
Center,
ChakraBaseProvider,
Expand Down Expand Up @@ -99,7 +100,7 @@ export default function Template({ children }: { children: React.ReactNode }) {
}

return (
<JotaiProvider>
<JotaiProvider store={MY_STORE}>
<StarknetConfig
chains={chains}
provider={provider}
Expand Down
3 changes: 2 additions & 1 deletion src/app/template.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import Navbar from '@/components/Navbar';
import { MY_STORE } from '@/store';
import {
Center,
ChakraBaseProvider,
Expand Down Expand Up @@ -99,7 +100,7 @@ export default function Template({ children }: { children: React.ReactNode }) {
}

return (
<JotaiProvider>
<JotaiProvider store={MY_STORE}>
<StarknetConfig
chains={chains}
provider={provider}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Filters.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';
import Select, { StylesConfig } from 'react-select';
import { ALL_FILTER, filters, updateFiltersAtom } from '@/store/pools';
import * as chroma from 'chroma.ts';
import { useSetAtom } from 'jotai';
import {
Expand All @@ -13,6 +12,7 @@ import {
Text,
} from '@chakra-ui/react';
import { HamburgerIcon } from '@chakra-ui/icons';
import { ALL_FILTER, filters, updateFiltersAtom } from '@/store/protocols';

export interface Option {
readonly value: string;
Expand Down
12 changes: 6 additions & 6 deletions src/components/Pools.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
'use client';

import {
PoolInfo,
allPoolsAtomUnSorted,
filteredPools,
sortPoolsAtom,
} from '@/store/pools';
import { PoolInfo } from '@/store/pools';
import {
Avatar,
AvatarGroup,
Expand Down Expand Up @@ -38,6 +33,11 @@ import {
import CONSTANTS from '@/constants';
import Filters from '@/components/Filters';
import mixpanel from 'mixpanel-browser';
import {
allPoolsAtomUnSorted,
filteredPools,
sortPoolsAtom,
} from '@/store/protocols';

export default function Pools() {
const allPools = useAtomValue(allPoolsAtomUnSorted);
Expand Down
2 changes: 1 addition & 1 deletion src/components/Strategies.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import CONSTANTS from '@/constants';
import { allPoolsAtomUnSorted } from '@/store/pools';
import { StrategyInfo, strategiesAtom } from '@/store/strategies.atoms';
import { IStrategyProps, StrategyLiveStatus } from '@/strategies/IStrategy';
import { getUniqueById } from '@/utils';
Expand Down Expand Up @@ -36,6 +35,7 @@ import { useAtomValue } from 'jotai';
import mixpanel from 'mixpanel-browser';
import React from 'react';
import TVL from './TVL';
import { allPoolsAtomUnSorted } from '@/store/protocols';

const Strategies: React.FC = () => {
const allPools = useAtomValue(allPoolsAtomUnSorted);
Expand Down
8 changes: 5 additions & 3 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@ const LOGOS = {
export type TokenName = 'USDT' | 'USDC' | 'ETH' | 'STRK' | 'WBTC' | 'DAI';

const CONSTANTS = {
DEX_INCENTIVE_URL: '/strk-incentives/fetchFile?file=strk_grant.json',
DEX_INCENTIVE_URL:
'https://kx58j6x5me.execute-api.us-east-1.amazonaws.com/starknet/fetchFile?file=strk_grant.json',
NOSTRA_DEGEN_INCENTIVE_URL: 'https://api.nostra.finance/query/pool_aprs',
CARMINE_INCENTIVES_URL: '/carmine/api/v1/mainnet/defispring',
CARMINE_URL: '/carmine/api/v2/mainnet',
LENDING_INCENTIVES_URL:
'/strk-incentives/fetchFile?file=prod-api/lending/lending_strk_grant.json',
'https://kx58j6x5me.execute-api.us-east-1.amazonaws.com/starknet/fetchFile?file=prod-api/lending/lending_strk_grant.json',
LOGOS,
COMMUNITY_TG: 'https://t.me/+HQ_eHaXmF-1lZDc1',
NOSTRA: {
LENDING_GRAPH_URL: '/nostra/app/data-yqlpb/endpoint/data/v1/action/find',
LENDING_GRAPH_URL:
'https://us-east-2.aws.data.mongodb-api.com/app/data-yqlpb/endpoint/data/v1/action/find',
},
ZKLEND: {
BASE_APR_API: '/zklend/api/pools',
Expand Down
3 changes: 2 additions & 1 deletion src/store/IDapp.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AtomWithQueryResult } from 'jotai-tanstack-query';
import { APRSplit, PoolInfo, PoolMetadata } from './pools';
import { TokenName } from '@/constants';
import { StrategyAction } from '@/strategies/IStrategy';
import { CustomAtomWithQueryResult } from '@/utils/customAtomWithQuery';

export interface APRInfo {
asset: TokenName;
Expand All @@ -20,7 +21,7 @@ export class IDapp<BaseAPYT> {

addBaseAPYs<BaseAPYT>(
pools: PoolInfo[],
data: AtomWithQueryResult<BaseAPYT, Error>,
data: CustomAtomWithQueryResult<BaseAPYT, Error>,
): PoolInfo[] {
console.log(`lending: ${this.name}`, data);
if (data.isError) {
Expand Down
2 changes: 0 additions & 2 deletions src/store/ekobu.store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client';

import CONSTANTS, { TokenName } from '@/constants';
import { atom } from 'jotai';
import { AtomWithQueryResult, atomWithQuery } from 'jotai-tanstack-query';
Expand Down
2 changes: 0 additions & 2 deletions src/store/haiko.store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client';

import CONSTANTS, { TokenName } from '@/constants';
import {
APRSplit,
Expand Down
3 changes: 3 additions & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { createStore } from 'jotai';

export const MY_STORE = createStore();
2 changes: 0 additions & 2 deletions src/store/myswap.store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client';

import {
APRSplit,
Category,
Expand Down
43 changes: 21 additions & 22 deletions src/store/nostralending.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import {
APRSplit,
PoolInfo,
PoolMetadata,
ProtocolAtoms,
ProtocolAtoms2,
StrkLendingIncentivesAtom,
} from './pools';
import { atom } from 'jotai';
import { AtomWithQueryResult, atomWithQuery } from 'jotai-tanstack-query';
import { AtomWithQueryResult } from 'jotai-tanstack-query';
import { LendingSpace } from './lending.base';
import { IDapp } from './IDapp.store';
import { customAtomWithFetch } from '@/utils/customAtomWithFetch';

interface MyBaseAprDoc {
_id: string;
Expand Down Expand Up @@ -119,27 +120,25 @@ export class NostraLending extends IDapp<LendingSpace.MyBaseAprDoc[]> {
}

export const nostraLending = new NostraLending();
const NostraLendingAtoms: ProtocolAtoms = {
baseAPRs: atomWithQuery((get) => ({
queryKey: ['nostra_lending_base_aprs'],
queryFn: async ({ queryKey }) => {
const res = await fetch(CONSTANTS.NOSTRA.LENDING_GRAPH_URL, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
dataSource: 'nostra-production',
database: 'prod-a-nostra-db',
collection: 'apyStats',
filter: { timestamp: { $gte: 1697500800 } },
sort: { timestamp: -1 },
}),
});
return res.json();
const NostraLendingAtoms: ProtocolAtoms2 = {
baseAPRs: customAtomWithFetch({
queryKey: 'nostra_lending_base_aprs',
url: CONSTANTS.NOSTRA.LENDING_GRAPH_URL,
fetchOptions: {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
dataSource: 'nostra-production',
database: 'prod-a-nostra-db',
collection: 'apyStats',
filter: { timestamp: { $gte: 1697500800 } },
sort: { timestamp: -1 },
}),
},
})),
}),
pools: atom((get) => {
const poolsInfo = get(StrkLendingIncentivesAtom);
const empty: PoolInfo[] = [];
Expand Down
Loading
Loading