From ca65f234e975fef9ffd5bdfa6b7b563845d4f9ae Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Sun, 3 Nov 2024 17:52:18 +0530
Subject: [PATCH 01/22] raffle page text fixes
---
src/app/raffle/page.tsx | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/app/raffle/page.tsx b/src/app/raffle/page.tsx
index 0b23bf9..a98e41e 100644
--- a/src/app/raffle/page.tsx
+++ b/src/app/raffle/page.tsx
@@ -87,17 +87,18 @@ const Raffle: NextPage = () => {
3. You have to register if you want to participate. This mean you or
- anyone on your behalf will be available t to collect the merch.{' '}
+ anyone on your behalf will be available to collect the merch.{' '}
4. The rewards will be in the form of exclusive merch reserved for you
5. Selected winners can collect their merch on 13th Nov, from The Fig
- lobby, Bangkok
+ Lobby, Bangkok
- 6. Winners will be announced on our socials everyday
+ 6. Winners will be announced on our socials (i.e. X, TG, etc.)
+ everyday
From 400722e0b80e491306feff36cf9b0cb4221d978e Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Sun, 3 Nov 2024 18:35:15 +0530
Subject: [PATCH 02/22] enable mobile actions
---
src/app/strategy/[strategyId]/_components/Strategy.tsx | 8 +-------
src/components/TxButton.tsx | 2 --
2 files changed, 1 insertion(+), 9 deletions(-)
diff --git a/src/app/strategy/[strategyId]/_components/Strategy.tsx b/src/app/strategy/[strategyId]/_components/Strategy.tsx
index 25de2ad..be36926 100755
--- a/src/app/strategy/[strategyId]/_components/Strategy.tsx
+++ b/src/app/strategy/[strategyId]/_components/Strategy.tsx
@@ -46,8 +46,6 @@ import {
import { StrategyParams } from '../page';
import MyNumber from '@/utils/MyNumber';
import { ExternalLinkIcon } from '@chakra-ui/icons';
-import { isMobile } from 'react-device-detect';
-import CONSTANTS from '@/constants';
const Strategy = ({ params }: StrategyParams) => {
const { address } = useAccount();
@@ -247,9 +245,7 @@ const Strategy = ({ params }: StrategyParams) => {
) == 0
? '-'
: `${balData.data.amount.toEtherToFixedDecimals(balData.data.tokenInfo?.displayDecimals || 2)} ${balData.data.tokenInfo?.name}`
- : isMobile
- ? CONSTANTS.MOBILE_MSG
- : 'Connect wallet'}
+ : 'Connect wallet'}
@@ -276,8 +272,6 @@ const Strategy = ({ params }: StrategyParams) => {
Your Holdings:
{address ? (
- ) : isMobile ? (
- CONSTANTS.MOBILE_MSG
) : (
'Connect wallet'
)}
diff --git a/src/components/TxButton.tsx b/src/components/TxButton.tsx
index 643de9e..e38eb54 100755
--- a/src/components/TxButton.tsx
+++ b/src/components/TxButton.tsx
@@ -1,4 +1,3 @@
-import CONSTANTS from '@/constants';
import { referralCodeAtom } from '@/store/referral.store';
import { StrategyTxProps, monitorNewTxAtom } from '@/store/transactions.atom';
import { IStrategyProps, TokenInfo } from '@/strategies/IStrategy';
@@ -101,7 +100,6 @@ export default function TxButton(props: TxButtonProps) {
if (!address) return props.text;
return '';
}
- if (isMobile) return CONSTANTS.MOBILE_MSG;
if (!address) return 'Wallet not connected';
return '';
}, [isMobile, address, props]);
From 0665bba0a8009be43b240cf711407d539a0171c3 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Mon, 4 Nov 2024 14:43:57 +0530
Subject: [PATCH 03/22] raffle::select winners:: add debug logs
---
src/app/api/raffle/luckyWinner/route.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/app/api/raffle/luckyWinner/route.ts b/src/app/api/raffle/luckyWinner/route.ts
index e908b19..16f6004 100644
--- a/src/app/api/raffle/luckyWinner/route.ts
+++ b/src/app/api/raffle/luckyWinner/route.ts
@@ -6,7 +6,9 @@ export const dynamic = 'force-dynamic'; // static by default, unless reading the
export async function GET(request: Request) {
const authHeader = request.headers.get('authorization');
+ console.log('Authorization header:', authHeader);
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
+ console.error('Unauthorized request');
return new Response('Unauthorized', {
status: 401,
});
From 7ce7fc3a3f6ffa0e783801317303ca03e9b67dff Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Mon, 4 Nov 2024 14:55:38 +0530
Subject: [PATCH 04/22] raffle: add rt post link
---
src/app/raffle/_components/share-on-x.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/raffle/_components/share-on-x.tsx b/src/app/raffle/_components/share-on-x.tsx
index ce18fd4..5723796 100644
--- a/src/app/raffle/_components/share-on-x.tsx
+++ b/src/app/raffle/_components/share-on-x.tsx
@@ -81,7 +81,7 @@ const ShareOnX = () => {
{}}
From 3573b10330ec308b5ab6040eb3d78544268c42c4 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Wed, 6 Nov 2024 20:35:59 +0700
Subject: [PATCH 05/22] add raffle know more link
---
src/app/raffle/page.tsx | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/app/raffle/page.tsx b/src/app/raffle/page.tsx
index a98e41e..15eca74 100644
--- a/src/app/raffle/page.tsx
+++ b/src/app/raffle/page.tsx
@@ -1,6 +1,7 @@
import { NextPage } from 'next';
import Image from 'next/image';
import React from 'react';
+import { Button } from '@chakra-ui/react';
import ActiveDeposits from './_components/active-deposits';
import RaffleTimer from './_components/raffle-timer';
@@ -21,9 +22,14 @@ const Raffle: NextPage = () => {
during Starkspace (Devcon, Bangkok)
-
+
Know More
-
+
Date: Wed, 6 Nov 2024 20:16:12 +0530
Subject: [PATCH 06/22] Add dnmm reverse (#101)
* temp remove tnc signing validation
* add fetchWithRetry for external endpoints
* fix haiko api bug
* disable sithswap, 10kswap and starkdefi
* build fix
* re-add fee
* add dnmm2
* Add mainnet ETH Sensei XL contracts
---
src/constants.ts | 21 +++++++++
src/store/strategies.atoms.ts | 17 ++++++-
src/strategies/IStrategy.ts | 8 +++-
src/strategies/auto_strk.strat.ts | 5 +-
src/strategies/delta_neutral_mm.ts | 26 +++++++----
src/strategies/delta_neutral_mm_2.ts | 68 ++++++++++++++++++++++++++++
6 files changed, 131 insertions(+), 14 deletions(-)
create mode 100644 src/strategies/delta_neutral_mm_2.ts
diff --git a/src/constants.ts b/src/constants.ts
index 7d645b3..3984b52 100755
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -62,6 +62,8 @@ const CONSTANTS = {
'0x20d5fc4c9df4f943ebb36078e703369c04176ed00accf290e8295b659d2cea6',
DeltaNeutralMMETHUSDC:
'0x9d23d9b1fa0db8c9d75a1df924c3820e594fc4ab1475695889286f3f6df250',
+ DeltaNeutralMMETHUSDCXL:
+ '0x5852a2fa5f3fa08fc8b0b95096792a954009da28e1fa08430bde9e91bf395fe',
},
MOBILE_MSG: 'Desktop/Tablet only',
};
@@ -100,6 +102,17 @@ export const TOKENS: TokenInfo[] = [
stepAmount: MyNumber.fromEther('10', 18),
isERC4626: false,
},
+ {
+ token: '0x057146f6409deb4c9fa12866915dd952aa07c1eb2752e451d7f3b042086bdeb8',
+ name: 'iETH-c', // nostra eth collateral
+ decimals: 18,
+ displayDecimals: 2,
+ logo: CONSTANTS.LOGOS.ETH,
+ minAmount: MyNumber.fromEther('10', 18),
+ maxAmount: MyNumber.fromEther('10000', 18),
+ stepAmount: MyNumber.fromEther('10', 18),
+ isERC4626: false,
+ },
{
token: '0x1b5bd713e72fdc5d63ffd83762f81297f6175a5e0a4771cdadbc1dd5fe72cb1',
name: 'zETH',
@@ -193,6 +206,14 @@ export const NFTS: NFTInfo[] = [
mainTokenName: 'ETH',
},
},
+ {
+ name: 'frmDNMMETHUSDC2',
+ address: CONSTANTS.CONTRACTS.DeltaNeutralMMETHUSDCXL,
+ logo: CONSTANTS.LOGOS.ETH,
+ config: {
+ mainTokenName: 'ETH',
+ },
+ },
];
// ? When updating this, ensure there is redirect available for this route
diff --git a/src/store/strategies.atoms.ts b/src/store/strategies.atoms.ts
index 0cf8488..db032d5 100755
--- a/src/store/strategies.atoms.ts
+++ b/src/store/strategies.atoms.ts
@@ -10,6 +10,7 @@ import { DeltaNeutralMM } from '@/strategies/delta_neutral_mm';
import Mustache from 'mustache';
import { getTokenInfoFromName } from '@/utils';
import { allPoolsAtomUnSorted } from './protocols';
+import { DeltaNeutralMM2 } from '@/strategies/delta_neutral_mm_2';
export interface StrategyInfo extends IStrategyProps {
name: string;
@@ -68,7 +69,7 @@ export function getStrategies() {
'USDC',
CONSTANTS.CONTRACTS.DeltaNeutralMMETHUSDC,
[1, 0.609886, 1, 0.920975, 0.510078], // precomputed factors based on strategy math
- StrategyLiveStatus.NEW,
+ StrategyLiveStatus.ACTIVE,
{
maxTVL: 1000,
},
@@ -87,12 +88,26 @@ export function getStrategies() {
},
);
+ const deltaNeutralMMETHUSDCReverse = new DeltaNeutralMM2(
+ getTokenInfoFromName('ETH'),
+ 'ETH Sensei XL',
+ Mustache.render(DNMMDescription, { token1: 'ETH', token2: 'USDC' }),
+ 'USDC',
+ CONSTANTS.CONTRACTS.DeltaNeutralMMETHUSDCXL,
+ [1, 0.5846153846, 1, 0.920975, 0.552509], // precomputed factors based on strategy math
+ StrategyLiveStatus.NEW,
+ {
+ maxTVL: 2000,
+ },
+ );
+
const strategies: IStrategy[] = [
autoStrkStrategy,
autoUSDCStrategy,
deltaNeutralMMUSDCETH,
deltaNeutralMMETHUSDC,
deltaNeutralMMSTRKETH,
+ deltaNeutralMMETHUSDCReverse,
];
return strategies;
diff --git a/src/strategies/IStrategy.ts b/src/strategies/IStrategy.ts
index da89d23..2854896 100755
--- a/src/strategies/IStrategy.ts
+++ b/src/strategies/IStrategy.ts
@@ -1,5 +1,6 @@
import { IDapp } from '@/store/IDapp.store';
import { BalanceResult, getBalanceAtom } from '@/store/balance.atoms';
+import { LendingSpace } from '@/store/lending.base';
import { Category, PoolInfo } from '@/store/pools';
import { zkLend } from '@/store/zklend.store';
import MyNumber from '@/utils/MyNumber';
@@ -254,14 +255,17 @@ export class IStrategy extends IStrategyProps {
return eligiblePools;
}
- filterZkLend(tokenName: string) {
+ filterTokenByProtocol(
+ tokenName: string,
+ protocol: IDapp = zkLend,
+ ) {
return (
pools: PoolInfo[],
amount: string,
prevActions: StrategyAction[],
) => {
return pools.filter(
- (p) => p.pool.name == tokenName && p.protocol.name == zkLend.name,
+ (p) => p.pool.name == tokenName && p.protocol.name == protocol.name,
);
};
}
diff --git a/src/strategies/auto_strk.strat.ts b/src/strategies/auto_strk.strat.ts
index f4aa5eb..48018a7 100755
--- a/src/strategies/auto_strk.strat.ts
+++ b/src/strategies/auto_strk.strat.ts
@@ -23,6 +23,7 @@ import {
getERC20BalanceAtom,
} from '@/store/balance.atoms';
import { getPrice, getTokenInfoFromName } from '@/utils';
+import { zkLend } from '@/store/zklend.store';
interface Step {
name: string;
@@ -73,12 +74,12 @@ export class AutoTokenStrategy extends IStrategy {
{
name: `Supplies your ${token} to zkLend`,
optimizer: this.optimizer,
- filter: [this.filterZkLend(this.token.name)],
+ filter: [this.filterTokenByProtocol(this.token.name, zkLend)],
},
{
name: `Re-invest your STRK Rewards every 7 days`,
optimizer: this.compounder,
- filter: [this.filterZkLend('STRK')],
+ filter: [this.filterTokenByProtocol('STRK', zkLend)],
},
];
const _risks = [...this.risks];
diff --git a/src/strategies/delta_neutral_mm.ts b/src/strategies/delta_neutral_mm.ts
index b52d01b..304d46b 100755
--- a/src/strategies/delta_neutral_mm.ts
+++ b/src/strategies/delta_neutral_mm.ts
@@ -24,6 +24,8 @@ import {
getERC20Balance,
} from '@/store/balance.atoms';
import { atom } from 'jotai';
+import { IDapp } from '@/store/IDapp.store';
+import { LendingSpace } from '@/store/lending.base';
export class DeltaNeutralMM extends IStrategy {
riskFactor = 0.75;
@@ -34,6 +36,8 @@ export class DeltaNeutralMM extends IStrategy {
readonly stepAmountFactors: number[];
fee_factor = 0.1; // 10% fee
+ protocol1: IDapp;
+ protocol2: IDapp;
constructor(
token: TokenInfo,
name: string,
@@ -43,6 +47,8 @@ export class DeltaNeutralMM extends IStrategy {
stepAmountFactors: number[],
liveStatus: StrategyLiveStatus,
settings: IStrategySettings,
+ protocol1: IDapp = zkLend,
+ protocol2: IDapp = nostraLending,
) {
const rewardTokens = [{ logo: CONSTANTS.LOGOS.STRK }];
const nftInfo = NFTS.find(
@@ -54,7 +60,7 @@ export class DeltaNeutralMM extends IStrategy {
}
const holdingTokens: (TokenInfo | NFTInfo)[] = [nftInfo];
super(
- `${token.name.toLowerCase()}_sensei`,
+ name.toLowerCase().replaceAll(' ', '_'),
'DeltaNeutralMM',
name,
description,
@@ -64,25 +70,27 @@ export class DeltaNeutralMM extends IStrategy {
settings,
);
this.token = token;
+ this.protocol1 = protocol1;
+ this.protocol2 = protocol2;
this.steps = [
{
- name: `Supply's your ${token.name} to zkLend`,
+ name: `Supply's your ${token.name} to ${protocol1.name}`,
optimizer: this.optimizer,
filter: [this.filterMainToken],
},
{
- name: `Borrow ${secondaryTokenName} from zkLend`,
+ name: `Borrow ${secondaryTokenName} from ${protocol1.name}`,
optimizer: this.optimizer,
filter: [this.filterSecondaryToken],
},
{
- name: `Deposit ${secondaryTokenName} to Nostra`,
+ name: `Deposit ${secondaryTokenName} to ${protocol2.name}`,
optimizer: this.optimizer,
filter: [this.filterSecondaryToken],
},
{
- name: `Borrow ${token.name} from Nostra`,
+ name: `Borrow ${token.name} from ${protocol2.name}`,
optimizer: this.optimizer,
filter: [this.filterMainToken],
},
@@ -94,7 +102,7 @@ export class DeltaNeutralMM extends IStrategy {
{
name: `Re-invest your STRK Rewards every 7 days (Compound)`,
optimizer: this.compounder,
- filter: [this.filterZkLend('STRK')],
+ filter: [this.filterTokenByProtocol('STRK', this.protocol1)],
},
];
@@ -124,8 +132,8 @@ export class DeltaNeutralMM extends IStrategy {
) {
const dapp =
prevActions.length == 0 || prevActions.length == 4
- ? zkLend
- : nostraLending;
+ ? this.protocol1
+ : this.protocol2;
return pools.filter(
(p) => p.pool.name == this.token.name && p.protocol.name == dapp.name,
);
@@ -136,7 +144,7 @@ export class DeltaNeutralMM extends IStrategy {
amount: string,
prevActions: StrategyAction[],
) {
- const dapp = prevActions.length == 1 ? zkLend : nostraLending;
+ const dapp = prevActions.length == 1 ? this.protocol1 : this.protocol2;
return pools.filter(
(p) => p.pool.name == this.secondaryToken && p.protocol.name == dapp.name,
);
diff --git a/src/strategies/delta_neutral_mm_2.ts b/src/strategies/delta_neutral_mm_2.ts
new file mode 100644
index 0000000..4f1bcc1
--- /dev/null
+++ b/src/strategies/delta_neutral_mm_2.ts
@@ -0,0 +1,68 @@
+import { TokenName } from '@/constants';
+import { DeltaNeutralMM } from './delta_neutral_mm';
+import { IStrategySettings, StrategyLiveStatus, TokenInfo } from './IStrategy';
+import { nostraLending } from '@/store/nostralending.store';
+import { zkLend } from '@/store/zklend.store';
+import MyNumber from '@/utils/MyNumber';
+import { getPrice, getTokenInfoFromName } from '@/utils';
+import { getERC20Balance } from '@/store/balance.atoms';
+
+export class DeltaNeutralMM2 extends DeltaNeutralMM {
+ constructor(
+ token: TokenInfo,
+ name: string,
+ description: string,
+ secondaryTokenName: TokenName,
+ strategyAddress: string,
+ stepAmountFactors: number[],
+ liveStatus: StrategyLiveStatus,
+ settings: IStrategySettings,
+ ) {
+ super(
+ token,
+ name,
+ description,
+ secondaryTokenName,
+ strategyAddress,
+ stepAmountFactors,
+ liveStatus,
+ settings,
+ nostraLending,
+ zkLend,
+ );
+ }
+
+ getTVL = async () => {
+ if (!this.isLive())
+ return {
+ amount: MyNumber.fromEther('0', this.token.decimals),
+ usdValue: 0,
+ tokenInfo: this.token,
+ };
+
+ try {
+ const mainTokenName = this.token.name;
+ const colToken = getTokenInfoFromName(`i${mainTokenName}-c`);
+
+ const bal = await getERC20Balance(colToken, this.strategyAddress);
+ console.log('getTVL222', bal.amount.toString());
+ // This reduces the zToken TVL to near actual deposits made by users wihout looping
+ const discountFactor = this.stepAmountFactors[4];
+ const amount = bal.amount.operate('div', 1 + discountFactor);
+ console.log('getTVL1', amount.toString());
+ const price = await getPrice(this.token);
+ return {
+ amount,
+ usdValue: Number(amount.toEtherStr()) * price,
+ tokenInfo: this.token,
+ };
+ } catch (error) {
+ console.error('Error fetching TVL:', error);
+ return {
+ amount: MyNumber.fromEther('0', this.token.decimals),
+ usdValue: 0,
+ tokenInfo: this.token,
+ };
+ }
+ };
+}
From dd7a83388be616af9532da01e1dca701ae4a76e0 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Wed, 6 Nov 2024 22:16:42 +0700
Subject: [PATCH 07/22] fix haiko api bug
---
src/constants.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/constants.ts b/src/constants.ts
index 3984b52..3b7e589 100755
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -41,7 +41,7 @@ const CONSTANTS = {
BASE_API: '/ekubo',
},
HAIKO: {
- BASE_APR_API: 'haiko/markets?network=mainnet',
+ BASE_APR_API: '/haiko/markets?network=mainnet',
},
STRKFarm: {
BASE_APR_API: '/api/strategies',
From 96ef905506e13c30dc81000bcf3d780d689e99b1 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Tue, 12 Nov 2024 20:15:18 +0700
Subject: [PATCH 08/22] update eth xl address
---
src/constants.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/constants.ts b/src/constants.ts
index 3b7e589..049567d 100755
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -63,7 +63,7 @@ const CONSTANTS = {
DeltaNeutralMMETHUSDC:
'0x9d23d9b1fa0db8c9d75a1df924c3820e594fc4ab1475695889286f3f6df250',
DeltaNeutralMMETHUSDCXL:
- '0x5852a2fa5f3fa08fc8b0b95096792a954009da28e1fa08430bde9e91bf395fe',
+ '0x9140757f8fb5748379be582be39d6daf704cc3a0408882c0d57981a885eed9',
},
MOBILE_MSG: 'Desktop/Tablet only',
};
From 73919e344633a7df3ef634db4109ce5402c63c7e Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Tue, 12 Nov 2024 23:55:05 +0700
Subject: [PATCH 09/22] update audit info on XL pool
---
src/components/Navbar.tsx | 4 ++--
src/store/protocols.ts | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index 0071425..fe7bcc5 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -213,7 +213,7 @@ export default function Navbar(props: NavbarProps) {
top="0"
>
-
+ {/*
-
+ */}
Date: Wed, 20 Nov 2024 20:57:28 +0700
Subject: [PATCH 10/22] fix mobile wallet issue
---
src/components/Navbar.tsx | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index fe7bcc5..c486530 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -55,14 +55,15 @@ import {
} from 'starknetkit/argentMobile';
import { WebWalletConnector } from 'starknetkit/webwallet';
import TncModal from './TncModal';
+import { constants } from 'starknet';
export const MYCONNECTORS: any[] = isInArgentMobileAppBrowser()
? [
ArgentMobileConnector.init({
options: {
dappName: 'STRKFarm',
- projectId: 'strkfarm',
- url: 'https://app.strkfarm.xyz',
+ url: window.location.hostname,
+ chainId: constants.NetworkName.SN_MAIN,
},
inAppBrowserOptions: {},
}),
@@ -74,8 +75,8 @@ export const MYCONNECTORS: any[] = isInArgentMobileAppBrowser()
ArgentMobileConnector.init({
options: {
dappName: 'STRKFarm',
- projectId: 'strkfarm',
- url: 'https://app.strkfarm.xyz',
+ url: window.location.hostname,
+ chainId: constants.NetworkName.SN_MAIN,
},
}),
];
From 765513f861e690e1aa0c3527db6b1eaea4a8616b Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Wed, 20 Nov 2024 21:05:30 +0700
Subject: [PATCH 11/22] fix mobile wallet issue [2]
---
src/components/Navbar.tsx | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index c486530..9a261ab 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -31,6 +31,7 @@ import { getERC20Balance } from '@/store/balance.atoms';
import { addressAtom } from '@/store/claims.atoms';
import { lastWalletAtom } from '@/store/utils.atoms';
import {
+ getEndpoint,
getTokenInfoFromName,
MyMenuItemProps,
MyMenuListProps,
@@ -62,7 +63,7 @@ export const MYCONNECTORS: any[] = isInArgentMobileAppBrowser()
ArgentMobileConnector.init({
options: {
dappName: 'STRKFarm',
- url: window.location.hostname,
+ url: getEndpoint(),
chainId: constants.NetworkName.SN_MAIN,
},
inAppBrowserOptions: {},
@@ -75,7 +76,7 @@ export const MYCONNECTORS: any[] = isInArgentMobileAppBrowser()
ArgentMobileConnector.init({
options: {
dappName: 'STRKFarm',
- url: window.location.hostname,
+ url: getEndpoint(),
chainId: constants.NetworkName.SN_MAIN,
},
}),
From 1922eb3abff69677063fb0ed5994f30f4bae3963 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Thu, 21 Nov 2024 15:50:48 +0530
Subject: [PATCH 12/22] fix mobile connect issues
---
src/app/api/tnc/signUser/route.ts | 112 +++++++++++++-----------------
src/components/TncModal.tsx | 81 ++++++++++++++-------
src/components/YieldCard.tsx | 3 +-
src/store/strkfarm.atoms.ts | 2 +-
4 files changed, 106 insertions(+), 92 deletions(-)
diff --git a/src/app/api/tnc/signUser/route.ts b/src/app/api/tnc/signUser/route.ts
index dd777d3..c127aca 100644
--- a/src/app/api/tnc/signUser/route.ts
+++ b/src/app/api/tnc/signUser/route.ts
@@ -9,16 +9,9 @@ import Mixpanel from 'mixpanel';
const mixpanel = Mixpanel.init('118f29da6a372f0ccb6f541079cad56b');
export async function POST(req: Request) {
- const { address, signature, _signature } = await req.json();
-
- console.debug(
- 'address',
- address,
- 'signature',
- signature,
- '_signature',
- _signature,
- );
+ const { address, signature } = await req.json();
+
+ console.debug('address', address, 'signature', signature);
if (!address || !signature) {
return NextResponse.json({
success: false,
@@ -57,64 +50,64 @@ export async function POST(req: Request) {
console.debug(`Verifying signature for address: ${parsedAddress}`);
console.debug(`SIGNING_DATA`, SIGNING_DATA);
const hash = await myAccount.hashMessage(SIGNING_DATA);
- try {
- // await debug();
- isValid = await verifyMessageHash(myAccount, hash, parsedSignature);
- console.debug('isValid', isValid);
- mixpanel.track('TnC signed', {
- address,
- signature,
- _signature,
- step: 1,
- hash,
- });
- } catch (error) {
- console.error('verification failed [1]:', error);
- if (_signature) {
+ console.debug('hash', hash);
+
+ const function_sigs = ['is_valid_signature', 'isValidSignature'];
+ const signatures = [
+ parsedSignature,
+ parsedSignature.slice(parsedSignature.length - 2, parsedSignature.length),
+ ];
+
+ for (const fn_sig of function_sigs) {
+ for (const sig of signatures) {
try {
- const parsedSignature2 = JSON.parse(_signature) as string[];
- isValid = await verifyMessageHash(myAccount, hash, parsedSignature2);
+ console.log(`Checking: ${fn_sig}`);
+ console.log(`Signature: ${JSON.stringify(sig)}`);
+ isValid = await verifyMessageHash(myAccount, hash, sig, fn_sig);
console.debug('isValid', isValid);
mixpanel.track('TnC signed', {
address,
signature,
- _signature,
+ step: 1,
hash,
- step: 2,
- });
- } catch (err) {
- console.error('verification failed [2]:', err);
-
- // temporarily accepting all signtures
- isValid = true;
- mixpanel.track('TnC signing failed', {
- address,
- signature,
- hash,
- isValid,
- _signature,
+ fn_sig,
});
+ break;
+ } catch (error) {
+ console.warn(`verification failed [${fn_sig}]:`, error);
}
}
+ if (isValid) {
+ break;
+ }
}
- if (!isValid) {
- mixpanel.track('TnC signing failed', {
- address,
- signature,
- _signature,
- hash,
- isValid,
- });
- isValid = true; // temporarily accepting all signtures
- }
+ // if (!isValid) {
+ // mixpanel.track('TnC signing failed', {
+ // address,
+ // signature,
+ // hash,
+ // isValid,
+ // });
+ // isValid = true; // temporarily accepting all signtures
+ // }
if (!isValid) {
- return NextResponse.json({
- success: false,
- message: 'Invalid signature. Ensure account is deployed.',
- user: null,
- });
+ try {
+ const cls = await provider.getClassAt(address, 'pending');
+ // means account is deployed
+ return NextResponse.json({
+ success: false,
+ message: 'Invalid signature. Please contact us if issue persists.',
+ user: null,
+ });
+ } catch (error) {
+ return NextResponse.json({
+ success: false,
+ message: 'Invalid signature. Ensure account is deployed.',
+ user: null,
+ });
+ }
}
const user = await db.user.findFirst({
@@ -186,18 +179,11 @@ async function verifyMessageHash(
});
console.debug('verifyMessageHash resp', resp);
if (Number(resp[0]) == 0) {
- return false;
+ throw new Error('Invalid signature');
}
return true;
} catch (err: any) {
console.error('Error verifying signature:', err);
- if (entrypoint === 'isValidSignature') {
- console.debug(
- 'could be Invalid message selector, trying with is_valid_signature',
- );
- return verifyMessageHash(account, hash, signature, 'is_valid_signature');
- }
-
if (
[
'argent/invalid-signature',
diff --git a/src/components/TncModal.tsx b/src/components/TncModal.tsx
index ea8c9cb..d585dcc 100644
--- a/src/components/TncModal.tsx
+++ b/src/components/TncModal.tsx
@@ -13,7 +13,11 @@ import {
Text,
useDisclosure,
} from '@chakra-ui/react';
-import { useAccount, useDisconnect } from '@starknet-react/core';
+import {
+ useAccount,
+ useDisconnect,
+ useSignTypedData,
+} from '@starknet-react/core';
import axios from 'axios';
import { atomWithQuery } from 'jotai-tanstack-query';
import React, { useEffect, useMemo, useState } from 'react';
@@ -55,6 +59,14 @@ const TncModal: React.FC = (props) => {
const [isSigningPending, setIsSigningPending] = useState(false);
const { disconnectAsync } = useDisconnect();
+ const {
+ signTypedData,
+ error: signingError,
+ data: sigData,
+ } = useSignTypedData({
+ params: SIGNING_DATA,
+ });
+
// set ref code of the user if it exists
useEffect(() => {
if (!userTncInfo) return;
@@ -97,39 +109,54 @@ const TncModal: React.FC = (props) => {
})();
}, [userTncInfo]);
- const handleSign = async () => {
- if (!address || !account) {
+ useEffect(() => {
+ console.log('signature', sigData);
+ if (signingError) {
+ toast.error(signingError.message, {
+ position: 'bottom-right',
+ });
+ setIsSigningPending(false);
+ }
+ if (!address || !account || !sigData) {
return;
}
- mixpanel.track('TnC agreed', { address });
- setIsSigningPending(true);
+ async function processSign() {
+ try {
+ if (!sigData) {
+ return;
+ }
- try {
- const _signature = (await account.signMessage(SIGNING_DATA)) as string[];
-
- console.log('signature', _signature);
- const sig_len = _signature.length;
- const signature =
- sig_len > 2 ? _signature.slice(sig_len - 2, sig_len) : _signature;
- if (signature && signature.length > 0) {
- const res2 = await axios.post('/api/tnc/signUser', {
- address,
- signature: JSON.stringify(signature),
- _signature: JSON.stringify(_signature),
- });
-
- if (res2.data?.success) {
- onClose();
- } else {
- toast.error(res2.data?.message || 'Error verifying T&C');
+ const signature = sigData;
+ if (signature && signature.length > 0) {
+ const res2 = await axios.post('/api/tnc/signUser', {
+ address,
+ signature: JSON.stringify(signature),
+ });
+
+ if (res2.data?.success) {
+ onClose();
+ } else {
+ toast.error(res2.data?.message || 'Error verifying T&C');
+ }
}
+ } catch (error) {
+ console.error('signature', error);
+ mixpanel.track('TnC signing failed', { address });
}
- } catch (error) {
- console.error('signature', error);
- mixpanel.track('TnC signing failed', { address });
+ setIsSigningPending(false);
}
- setIsSigningPending(false);
+ processSign();
+ }, [sigData, signingError]);
+
+ const handleSign = async () => {
+ if (!address || !account) {
+ return;
+ }
+ mixpanel.track('TnC agreed', { address });
+
+ setIsSigningPending(true);
+ signTypedData();
};
return (
diff --git a/src/components/YieldCard.tsx b/src/components/YieldCard.tsx
index ea10b20..4dfecd8 100644
--- a/src/components/YieldCard.tsx
+++ b/src/components/YieldCard.tsx
@@ -32,6 +32,7 @@ import { getPoolInfoFromStrategy, sortAtom } from '@/store/protocols';
import { TriangleDownIcon, TriangleUpIcon } from '@chakra-ui/icons';
import mixpanel from 'mixpanel-browser';
import { STRKFarmStrategyAPIResult } from '@/store/strkfarm.atoms';
+import { isMobile } from 'react-device-detect';
interface YieldCardProps {
pool: PoolInfo;
@@ -468,7 +469,7 @@ function StrategyMobileCard(props: YieldCardProps) {
function getLinkProps(pool: PoolInfo, showProtocolName?: boolean) {
return {
href: pool.protocol.link,
- target: '_blank',
+ target: isMobile ? '_self' : '_blank',
onClick: () => {
mixpanel.track('Pool clicked', {
pool: pool.pool.name,
diff --git a/src/store/strkfarm.atoms.ts b/src/store/strkfarm.atoms.ts
index 1733dee..b0b0aa5 100644
--- a/src/store/strkfarm.atoms.ts
+++ b/src/store/strkfarm.atoms.ts
@@ -87,7 +87,7 @@ export class STRKFarm extends IDapp {
additional: {
riskFactor,
tags: [getLiveStatusEnum(rawPool.status.number)],
- isAudited: true,
+ isAudited: poolName.includes('XL') ? false : true,
},
};
return poolInfo;
From f0d502c657cb99102f666895ee0c96270e220a18 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Thu, 21 Nov 2024 19:36:59 +0530
Subject: [PATCH 13/22] auto connect bug
---
src/app/slinks/template.tsx | 5 +-
src/app/template.tsx | 5 +-
src/components/Navbar.tsx | 180 ++++++++++++++++++------------------
3 files changed, 95 insertions(+), 95 deletions(-)
diff --git a/src/app/slinks/template.tsx b/src/app/slinks/template.tsx
index 679d6d2..55454e2 100755
--- a/src/app/slinks/template.tsx
+++ b/src/app/slinks/template.tsx
@@ -1,6 +1,6 @@
'use client';
-import Navbar, { MYCONNECTORS } from '@/components/Navbar';
+import Navbar, { getConnectors } from '@/components/Navbar';
import { MY_STORE } from '@/store';
import {
Center,
@@ -16,6 +16,7 @@ import mixpanel from 'mixpanel-browser';
import Image from 'next/image';
import { usePathname } from 'next/navigation';
import * as React from 'react';
+import { isMobile } from 'react-device-detect';
import { Toaster } from 'react-hot-toast';
import { RpcProviderOptions, constants } from 'starknet';
@@ -96,7 +97,7 @@ export default function Template({ children }: { children: React.ReactNode }) {
diff --git a/src/app/template.tsx b/src/app/template.tsx
index acd3d80..2b8664d 100755
--- a/src/app/template.tsx
+++ b/src/app/template.tsx
@@ -1,6 +1,6 @@
'use client';
-import Navbar, { MYCONNECTORS } from '@/components/Navbar';
+import Navbar, { getConnectors } from '@/components/Navbar';
import { MY_STORE } from '@/store';
import {
Center,
@@ -20,6 +20,7 @@ import { Toaster } from 'react-hot-toast';
import { RpcProviderOptions, constants } from 'starknet';
import { Inter } from 'next/font/google';
+import { isMobile } from 'react-device-detect';
const inter = Inter({ subsets: ['latin'] });
mixpanel.init('118f29da6a372f0ccb6f541079cad56b');
@@ -108,7 +109,7 @@ export default function Template({ children }: { children: React.ReactNode }) {
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index 9a261ab..21969fb 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -22,9 +22,12 @@ import {
useDisclosure,
} from '@chakra-ui/react';
import { useAtom, useSetAtom } from 'jotai';
-import { useStarknetkitConnectModal } from 'starknetkit';
+import {
+ connect,
+ ConnectOptionsWithConnectors,
+ StarknetkitConnector,
+} from 'starknetkit';
-import { CONNECTOR_NAMES } from '@/app/template';
import tg from '@/assets/tg.svg';
import CONSTANTS from '@/constants';
import { getERC20Balance } from '@/store/balance.atoms';
@@ -48,7 +51,7 @@ import {
useStarkProfile,
} from '@starknet-react/core';
import mixpanel from 'mixpanel-browser';
-import { useEffect } from 'react';
+import { useEffect, useMemo } from 'react';
import { isMobile } from 'react-device-detect';
import {
ArgentMobileConnector,
@@ -58,29 +61,46 @@ import { WebWalletConnector } from 'starknetkit/webwallet';
import TncModal from './TncModal';
import { constants } from 'starknet';
-export const MYCONNECTORS: any[] = isInArgentMobileAppBrowser()
- ? [
- ArgentMobileConnector.init({
- options: {
- dappName: 'STRKFarm',
- url: getEndpoint(),
- chainId: constants.NetworkName.SN_MAIN,
- },
- inAppBrowserOptions: {},
- }),
- ]
- : [
- new InjectedConnector({ options: { id: 'braavos', name: 'Braavos' } }),
- new InjectedConnector({ options: { id: 'argentX', name: 'Argent X' } }),
- new WebWalletConnector({ url: 'https://web.argent.xyz' }),
- ArgentMobileConnector.init({
- options: {
- dappName: 'STRKFarm',
- url: getEndpoint(),
- chainId: constants.NetworkName.SN_MAIN,
- },
- }),
- ];
+export function getConnectors(isMobile: boolean) {
+ const mobileConnector = ArgentMobileConnector.init({
+ options: {
+ dappName: 'STRKFarm',
+ url: getEndpoint(),
+ chainId: constants.NetworkName.SN_MAIN,
+ },
+ inAppBrowserOptions: {},
+ }) as StarknetkitConnector;
+
+ const argentXConnector = new InjectedConnector({
+ options: {
+ id: 'argentX',
+ name: 'Argent X',
+ },
+ });
+
+ const braavosConnector = new InjectedConnector({
+ options: {
+ id: 'braavos',
+ name: 'Braavos',
+ },
+ });
+
+ const webWalletConnector = new WebWalletConnector({
+ url: 'https://web.argent.xyz',
+ }) as StarknetkitConnector;
+
+ if (isInArgentMobileAppBrowser()) {
+ return [mobileConnector];
+ } else if (isMobile) {
+ return [braavosConnector, mobileConnector, webWalletConnector];
+ }
+ return [
+ argentXConnector,
+ braavosConnector,
+ mobileConnector,
+ webWalletConnector,
+ ];
+}
interface NavbarProps {
hideTg?: boolean;
@@ -89,29 +109,15 @@ interface NavbarProps {
export default function Navbar(props: NavbarProps) {
const { address, connector, account } = useAccount();
- const { connect, connectors } = useConnect();
const { disconnectAsync } = useDisconnect();
const setAddress = useSetAtom(addressAtom);
const { data: starkProfile } = useStarkProfile({
address,
useDefaultPfp: true,
});
+ const { connect: connectSnReact } = useConnect();
const [lastWallet, setLastWallet] = useAtom(lastWalletAtom);
- const { starknetkitConnectModal: starknetkitConnectModal1 } =
- useStarknetkitConnectModal({
- modalMode: 'canAsk',
- modalTheme: 'dark',
- connectors: MYCONNECTORS,
- });
-
- // backup
- const { starknetkitConnectModal: starknetkitConnectModal2 } =
- useStarknetkitConnectModal({
- modalMode: 'alwaysAsk',
- modalTheme: 'dark',
- connectors: MYCONNECTORS,
- });
const getTokenBalance = async (token: string, address: string) => {
const tokenInfo = getTokenInfoFromName(token);
@@ -122,6 +128,41 @@ export default function Navbar(props: NavbarProps) {
console.log(account, 'account');
+ const connectorConfig: ConnectOptionsWithConnectors = useMemo(() => {
+ return {
+ modalMode: 'canAsk',
+ modalTheme: 'dark',
+ webWalletUrl: 'https://web.argent.xyz',
+ argentMobileOptions: {
+ dappName: 'STRKFarm',
+ chainId: constants.NetworkName.SN_MAIN,
+ url: window.location.hostname,
+ },
+ dappName: 'Endur.fi',
+ connectors: getConnectors(isMobile) as StarknetkitConnector[],
+ };
+ }, [isMobile]);
+
+ async function connectWallet(config = connectorConfig) {
+ try {
+ const { connector } = await connect(config);
+
+ if (connector) {
+ connectSnReact({ connector: connector as any });
+ }
+ } catch (error) {
+ console.error('connectWallet error', error);
+ }
+ }
+
+ useEffect(() => {
+ const config = connectorConfig;
+ connectWallet({
+ ...config,
+ modalMode: 'neverAsk',
+ });
+ }, []);
+
useEffect(() => {
(async () => {
if (address) {
@@ -139,55 +180,6 @@ export default function Navbar(props: NavbarProps) {
})();
}, [address]);
- // Connect wallet using starknetkit
- const connectWallet = async () => {
- try {
- const result = await starknetkitConnectModal1();
- if (!result.connector) {
- throw new Error('No connector found');
- }
-
- connect({ connector: result.connector });
- } catch (error) {
- console.warn('connectWallet error', error);
- try {
- const result = await starknetkitConnectModal2();
- if (!result.connector) {
- throw new Error('No connector found');
- }
- connect({ connector: result.connector });
- } catch (error) {
- console.error('connectWallet error', error);
- alert('Error connecting wallet');
- }
- }
- };
-
- function autoConnect(retry = 0) {
- console.log('lastWallet', lastWallet, connectors);
- try {
- if (!address && lastWallet) {
- const connectorIndex = CONNECTOR_NAMES.findIndex(
- (name) => name === lastWallet,
- );
- if (connectorIndex >= 0) {
- connect({ connector: MYCONNECTORS[connectorIndex] });
- }
- }
- } catch (error) {
- console.error('lastWallet error', error);
- if (retry < 10) {
- setTimeout(() => {
- autoConnect(retry + 1);
- }, 1000);
- }
- }
- }
- // Auto-connects to last wallet
- useEffect(() => {
- autoConnect();
- }, [lastWallet]);
-
// Set last wallet when a new wallet is connected
useEffect(() => {
console.log('lastWallet connector', connector?.name);
@@ -402,7 +394,13 @@ export default function Navbar(props: NavbarProps) {
my={{ base: 'auto', sm: 'initial' }}
paddingX={{ base: '0.5rem', sm: '1rem' }}
fontSize={{ base: '0.8rem', sm: '1rem' }}
- onClick={address ? undefined : connectWallet}
+ onClick={
+ address
+ ? undefined
+ : () => {
+ connectWallet();
+ }
+ }
size="xs"
>
From 9d34cc24dfff172b776bdf4c464a7d15baf06b16 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Thu, 21 Nov 2024 19:40:54 +0530
Subject: [PATCH 14/22] fix build issue
---
src/components/Navbar.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index 21969fb..4c27ea2 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -136,7 +136,7 @@ export default function Navbar(props: NavbarProps) {
argentMobileOptions: {
dappName: 'STRKFarm',
chainId: constants.NetworkName.SN_MAIN,
- url: window.location.hostname,
+ url: getEndpoint(),
},
dappName: 'Endur.fi',
connectors: getConnectors(isMobile) as StarknetkitConnector[],
From 5e4c07aaa801b0456feb282e724566249aa4139a Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Thu, 21 Nov 2024 19:46:51 +0530
Subject: [PATCH 15/22] remove raffle
---
src/components/Navbar.tsx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index 4c27ea2..c70c8f5 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -285,7 +285,7 @@ export default function Navbar(props: NavbarProps) {
Home
-
+ {/*
🕹 {' '}Raffle
-
+ */}
Home
-
+ {/*
🕹 {' '}Raffle
-
+ */}
Date: Sun, 24 Nov 2024 01:07:28 +0530
Subject: [PATCH 16/22] disable fetch err toast
---
src/app/slinks/page.tsx | 13 +++++++++++++
src/utils/fetchWithRetry.ts | 8 +++-----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/src/app/slinks/page.tsx b/src/app/slinks/page.tsx
index b79e51f..c092c72 100755
--- a/src/app/slinks/page.tsx
+++ b/src/app/slinks/page.tsx
@@ -133,6 +133,19 @@ export default function Slinks() {
const strategies = useAtomValue(strategiesAtom);
return (
+ {/*
+
+ */}
+
Choose a strategy and invest
{strategies
.filter((s) => s.isLive())
diff --git a/src/utils/fetchWithRetry.ts b/src/utils/fetchWithRetry.ts
index d5ca810..f2898db 100644
--- a/src/utils/fetchWithRetry.ts
+++ b/src/utils/fetchWithRetry.ts
@@ -1,5 +1,3 @@
-import toast from 'react-hot-toast';
-
async function fetchWithRetry(
url: string,
options: any = {},
@@ -20,9 +18,9 @@ async function fetchWithRetry(
} catch (error) {
if (i === maxRetries - 1) {
console.error(`Error fetching ${url} : `, error);
- toast.error(errorToast, {
- position: 'bottom-right',
- });
+ // toast.error(errorToast, {
+ // position: 'bottom-right',
+ // });
return null;
}
await new Promise((resolve) => setTimeout(resolve, delay));
From 807f68b8e4f6a16acbb8d881d3387fa64872ec44 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Sun, 24 Nov 2024 01:09:46 +0530
Subject: [PATCH 17/22] fix dappname
---
src/components/Navbar.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index c70c8f5..fa75633 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -138,7 +138,7 @@ export default function Navbar(props: NavbarProps) {
chainId: constants.NetworkName.SN_MAIN,
url: getEndpoint(),
},
- dappName: 'Endur.fi',
+ dappName: 'STRKFarm',
connectors: getConnectors(isMobile) as StarknetkitConnector[],
};
}, [isMobile]);
From f97a20e83e7c04e4451b81f831e37a5a3b125840 Mon Sep 17 00:00:00 2001
From: Akira <156126180+akiraonstarknet@users.noreply.github.com>
Date: Mon, 25 Nov 2024 20:56:27 +0530
Subject: [PATCH 18/22] add Xstrk (#108)
* chore: formatted tvl data
* fix: added dollar sign before tvl data
* fix: removed dollar sign : )
* fix: undefined tvl formatting issue
* fix: compile error in TVL
* chore: raffle implementation
* chore: deploy trigger
* chore: updated cron expression
* chore: updated cron expression
* chore: updated cron expression
* chore: update route method
* chore: update route logic
* chore: updated cron expression
* chore: updated cron expression
* chore: code refactor
* chore: updated lucky winner route
* fix: added cron secret
* chore: updated lucky winner route.ts
* chore: ui updates on raffle page
* fix: bugs and ui tweaks
* chore: text update
* fix: ekubo logo
* chore: update home page banner
* add endur
---------
Co-authored-by: Hemant
---
.env.sample | 5 +
next.config.mjs | 6 +-
public/banners/endur.svg | 62 +++
public/banners/endur_mobile.svg | 60 +++
src/abi/master.abi.json | 213 ++++++++---
src/abi/rewards.abi.json | 187 +++++++++
src/app/api/strategies/route.ts | 14 +-
src/app/page.tsx | 6 +-
.../[strategyId]/_components/Strategy.tsx | 50 ++-
src/components/HarvestTime.tsx | 62 +--
src/components/Strategies.tsx | 9 +-
src/components/YieldCard.tsx | 33 +-
src/constants.ts | 47 ++-
src/store/endur.store.ts | 121 ++++++
src/store/pools.ts | 34 ++
src/store/protocols.ts | 45 ++-
src/store/strategies.atoms.ts | 59 ++-
src/store/strkfarm.atoms.ts | 1 +
src/strategies/IStrategy.ts | 25 +-
src/strategies/auto_xstrk.strat.ts | 356 ++++++++++++++++++
src/utils/MyNumber.ts | 2 +-
21 files changed, 1252 insertions(+), 145 deletions(-)
create mode 100644 public/banners/endur.svg
create mode 100644 public/banners/endur_mobile.svg
create mode 100644 src/abi/rewards.abi.json
create mode 100644 src/store/endur.store.ts
create mode 100644 src/strategies/auto_xstrk.strat.ts
diff --git a/.env.sample b/.env.sample
index 34aa4b7..f5e2a70 100644
--- a/.env.sample
+++ b/.env.sample
@@ -12,3 +12,8 @@ NEXT_PUBLIC_OG_NFT_CONTRACT=0x3cb654f2f557a7f71a0c16d97c05a2dec62a0b744979d11afc
CRON_SECRET=
+
+# mainnet or sepolia
+# Note: Not everything is supported on sepolia
+# Default: mainnet
+NEXT_PUBLIC_NETWORK=mainnet
\ No newline at end of file
diff --git a/next.config.mjs b/next.config.mjs
index 9b833cd..ce4ebb7 100755
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -2,9 +2,9 @@
const nextConfig = {
// output: 'export',
compiler: {
- // removeConsole: {
- // exclude: ['error', 'debug'],
- // },
+ removeConsole: {
+ exclude: ['error'],
+ },
},
async rewrites() {
return [
diff --git a/public/banners/endur.svg b/public/banners/endur.svg
new file mode 100644
index 0000000..20e2109
--- /dev/null
+++ b/public/banners/endur.svg
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/banners/endur_mobile.svg b/public/banners/endur_mobile.svg
new file mode 100644
index 0000000..d9c328d
--- /dev/null
+++ b/public/banners/endur_mobile.svg
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/abi/master.abi.json b/src/abi/master.abi.json
index 051ee7c..4b405f9 100755
--- a/src/abi/master.abi.json
+++ b/src/abi/master.abi.json
@@ -1,12 +1,12 @@
[
{
- "name": "ExternalImpl",
"type": "impl",
+ "name": "ExternalImpl",
"interface_name": "strkfarm::strats::master::IMaster"
},
{
- "name": "core::integer::u256",
"type": "struct",
+ "name": "core::integer::u256",
"members": [
{
"name": "low",
@@ -19,12 +19,85 @@
]
},
{
- "name": "strkfarm::strats::master::IMaster",
+ "type": "struct",
+ "name": "strkfarm::strats::master::Settings",
+ "members": [
+ {
+ "name": "nimbora_referral",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ]
+ },
+ {
"type": "interface",
+ "name": "strkfarm::strats::master::IMaster",
"items": [
{
+ "type": "function",
"name": "invest_auto_strk",
+ "inputs": [
+ {
+ "name": "strategy",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "amount",
+ "type": "core::integer::u256"
+ },
+ {
+ "name": "receiver",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::integer::u256"
+ }
+ ],
+ "state_mutability": "external"
+ },
+ {
"type": "function",
+ "name": "deposit_nimbora",
+ "inputs": [
+ {
+ "name": "nimbora_strategy_address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "harvest_invest_strategy",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "token_address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "assets",
+ "type": "core::integer::u256"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::integer::u256"
+ }
+ ],
+ "state_mutability": "external"
+ },
+ {
+ "type": "function",
+ "name": "get_settings",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "strkfarm::strats::master::Settings"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "type": "function",
+ "name": "invest_to_xstrk_auto",
"inputs": [
{
"name": "strategy",
@@ -47,8 +120,8 @@
"state_mutability": "external"
},
{
- "name": "upgrade",
"type": "function",
+ "name": "upgrade",
"inputs": [
{
"name": "class_hash",
@@ -61,17 +134,17 @@
]
},
{
- "name": "OwnableTwoStepImpl",
"type": "impl",
- "interface_name": "openzeppelin::access::ownable::interface::IOwnableTwoStep"
+ "name": "OwnableTwoStepImpl",
+ "interface_name": "openzeppelin_access::ownable::interface::IOwnableTwoStep"
},
{
- "name": "openzeppelin::access::ownable::interface::IOwnableTwoStep",
"type": "interface",
+ "name": "openzeppelin_access::ownable::interface::IOwnableTwoStep",
"items": [
{
- "name": "owner",
"type": "function",
+ "name": "owner",
"inputs": [],
"outputs": [
{
@@ -81,8 +154,8 @@
"state_mutability": "view"
},
{
- "name": "pending_owner",
"type": "function",
+ "name": "pending_owner",
"inputs": [],
"outputs": [
{
@@ -92,15 +165,15 @@
"state_mutability": "view"
},
{
- "name": "accept_ownership",
"type": "function",
+ "name": "accept_ownership",
"inputs": [],
"outputs": [],
"state_mutability": "external"
},
{
- "name": "transfer_ownership",
"type": "function",
+ "name": "transfer_ownership",
"inputs": [
{
"name": "new_owner",
@@ -111,8 +184,8 @@
"state_mutability": "external"
},
{
- "name": "renounce_ownership",
"type": "function",
+ "name": "renounce_ownership",
"inputs": [],
"outputs": [],
"state_mutability": "external"
@@ -120,115 +193,157 @@
]
},
{
- "name": "constructor",
+ "type": "struct",
+ "name": "strkfarm::interfaces::zkLend::IZkLendMarketDispatcher",
+ "members": [
+ {
+ "name": "contract_address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ]
+ },
+ {
+ "type": "struct",
+ "name": "strkfarm::interfaces::oracle::IPriceOracleDispatcher",
+ "members": [
+ {
+ "name": "contract_address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ]
+ },
+ {
+ "type": "struct",
+ "name": "strkfarm::components::zkLend::zkLendStruct",
+ "members": [
+ {
+ "name": "zkLendRouter",
+ "type": "strkfarm::interfaces::zkLend::IZkLendMarketDispatcher"
+ },
+ {
+ "name": "oracle",
+ "type": "strkfarm::interfaces::oracle::IPriceOracleDispatcher"
+ }
+ ]
+ },
+ {
"type": "constructor",
+ "name": "constructor",
"inputs": [
{
"name": "owner",
"type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "lend_settings",
+ "type": "strkfarm::components::zkLend::zkLendStruct"
+ },
+ {
+ "name": "nimbora_referral",
+ "type": "core::starknet::contract_address::ContractAddress"
}
]
},
{
- "kind": "enum",
- "name": "openzeppelin::security::reentrancyguard::ReentrancyGuardComponent::Event",
"type": "event",
+ "name": "openzeppelin_security::reentrancyguard::ReentrancyGuardComponent::Event",
+ "kind": "enum",
"variants": []
},
{
- "kind": "struct",
- "name": "openzeppelin::access::ownable::ownable::OwnableComponent::OwnershipTransferred",
"type": "event",
+ "name": "openzeppelin_access::ownable::ownable::OwnableComponent::OwnershipTransferred",
+ "kind": "struct",
"members": [
{
- "kind": "key",
"name": "previous_owner",
- "type": "core::starknet::contract_address::ContractAddress"
+ "type": "core::starknet::contract_address::ContractAddress",
+ "kind": "key"
},
{
- "kind": "key",
"name": "new_owner",
- "type": "core::starknet::contract_address::ContractAddress"
+ "type": "core::starknet::contract_address::ContractAddress",
+ "kind": "key"
}
]
},
{
- "kind": "struct",
- "name": "openzeppelin::access::ownable::ownable::OwnableComponent::OwnershipTransferStarted",
"type": "event",
+ "name": "openzeppelin_access::ownable::ownable::OwnableComponent::OwnershipTransferStarted",
+ "kind": "struct",
"members": [
{
- "kind": "key",
"name": "previous_owner",
- "type": "core::starknet::contract_address::ContractAddress"
+ "type": "core::starknet::contract_address::ContractAddress",
+ "kind": "key"
},
{
- "kind": "key",
"name": "new_owner",
- "type": "core::starknet::contract_address::ContractAddress"
+ "type": "core::starknet::contract_address::ContractAddress",
+ "kind": "key"
}
]
},
{
- "kind": "enum",
- "name": "openzeppelin::access::ownable::ownable::OwnableComponent::Event",
"type": "event",
+ "name": "openzeppelin_access::ownable::ownable::OwnableComponent::Event",
+ "kind": "enum",
"variants": [
{
- "kind": "nested",
"name": "OwnershipTransferred",
- "type": "openzeppelin::access::ownable::ownable::OwnableComponent::OwnershipTransferred"
+ "type": "openzeppelin_access::ownable::ownable::OwnableComponent::OwnershipTransferred",
+ "kind": "nested"
},
{
- "kind": "nested",
"name": "OwnershipTransferStarted",
- "type": "openzeppelin::access::ownable::ownable::OwnableComponent::OwnershipTransferStarted"
+ "type": "openzeppelin_access::ownable::ownable::OwnableComponent::OwnershipTransferStarted",
+ "kind": "nested"
}
]
},
{
- "kind": "struct",
- "name": "openzeppelin::upgrades::upgradeable::UpgradeableComponent::Upgraded",
"type": "event",
+ "name": "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
+ "kind": "struct",
"members": [
{
- "kind": "data",
"name": "class_hash",
- "type": "core::starknet::class_hash::ClassHash"
+ "type": "core::starknet::class_hash::ClassHash",
+ "kind": "data"
}
]
},
{
- "kind": "enum",
- "name": "openzeppelin::upgrades::upgradeable::UpgradeableComponent::Event",
"type": "event",
+ "name": "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
+ "kind": "enum",
"variants": [
{
- "kind": "nested",
"name": "Upgraded",
- "type": "openzeppelin::upgrades::upgradeable::UpgradeableComponent::Upgraded"
+ "type": "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
+ "kind": "nested"
}
]
},
{
- "kind": "enum",
- "name": "strkfarm::strats::master::Master::Event",
"type": "event",
+ "name": "strkfarm::strats::master::Master::Event",
+ "kind": "enum",
"variants": [
{
- "kind": "flat",
"name": "ReentrancyGuardEvent",
- "type": "openzeppelin::security::reentrancyguard::ReentrancyGuardComponent::Event"
+ "type": "openzeppelin_security::reentrancyguard::ReentrancyGuardComponent::Event",
+ "kind": "flat"
},
{
- "kind": "flat",
"name": "OwnableEvent",
- "type": "openzeppelin::access::ownable::ownable::OwnableComponent::Event"
+ "type": "openzeppelin_access::ownable::ownable::OwnableComponent::Event",
+ "kind": "flat"
},
{
- "kind": "flat",
"name": "UpgradeableEvent",
- "type": "openzeppelin::upgrades::upgradeable::UpgradeableComponent::Event"
+ "type": "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
+ "kind": "flat"
}
]
}
diff --git a/src/abi/rewards.abi.json b/src/abi/rewards.abi.json
new file mode 100644
index 0000000..ab1057a
--- /dev/null
+++ b/src/abi/rewards.abi.json
@@ -0,0 +1,187 @@
+[
+ {
+ "type": "impl",
+ "name": "MyRewardsImpl",
+ "interface_name": "strkfarm::strats::myrewards::IMyRewards"
+ },
+ {
+ "type": "struct",
+ "name": "strkfarm::strats::myrewards::IConfig",
+ "members": [
+ {
+ "name": "rewards_per_second",
+ "type": "core::integer::u128"
+ },
+ {
+ "name": "token",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "reward_receiver",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "start_time",
+ "type": "core::integer::u64"
+ }
+ ]
+ },
+ {
+ "type": "interface",
+ "name": "strkfarm::strats::myrewards::IMyRewards",
+ "items": [
+ {
+ "type": "function",
+ "name": "owner",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "type": "function",
+ "name": "upgrade",
+ "inputs": [
+ {
+ "name": "new_class",
+ "type": "core::starknet::class_hash::ClassHash"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "type": "function",
+ "name": "set_config",
+ "inputs": [
+ {
+ "name": "config",
+ "type": "strkfarm::strats::myrewards::IConfig"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "type": "function",
+ "name": "get_config",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "strkfarm::strats::myrewards::IConfig"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "type": "function",
+ "name": "withdraw",
+ "inputs": [
+ {
+ "name": "amount",
+ "type": "core::integer::u128"
+ },
+ {
+ "name": "to",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "type": "function",
+ "name": "rewards",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "core::integer::u128"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "type": "function",
+ "name": "give_rewards",
+ "inputs": [],
+ "outputs": [],
+ "state_mutability": "external"
+ }
+ ]
+ },
+ {
+ "type": "constructor",
+ "name": "constructor",
+ "inputs": [
+ {
+ "name": "owner",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "config",
+ "type": "strkfarm::strats::myrewards::IConfig"
+ }
+ ]
+ },
+ {
+ "type": "event",
+ "name": "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
+ "kind": "struct",
+ "members": [
+ {
+ "name": "class_hash",
+ "type": "core::starknet::class_hash::ClassHash",
+ "kind": "data"
+ }
+ ]
+ },
+ {
+ "type": "event",
+ "name": "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
+ "kind": "enum",
+ "variants": [
+ {
+ "name": "Upgraded",
+ "type": "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
+ "kind": "nested"
+ }
+ ]
+ },
+ {
+ "type": "event",
+ "name": "strkfarm::strats::myrewards::MyRewards::RewardSent",
+ "kind": "struct",
+ "members": [
+ {
+ "name": "amount",
+ "type": "core::integer::u128",
+ "kind": "data"
+ },
+ {
+ "name": "to",
+ "type": "core::starknet::contract_address::ContractAddress",
+ "kind": "data"
+ }
+ ]
+ },
+ {
+ "type": "event",
+ "name": "strkfarm::strats::myrewards::MyRewards::Event",
+ "kind": "enum",
+ "variants": [
+ {
+ "name": "UpgradeableEvent",
+ "type": "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
+ "kind": "flat"
+ },
+ {
+ "name": "RewardSent",
+ "type": "strkfarm::strats::myrewards::MyRewards::RewardSent",
+ "kind": "nested"
+ }
+ ]
+ }
+]
diff --git a/src/app/api/strategies/route.ts b/src/app/api/strategies/route.ts
index 5b07558..852c1aa 100755
--- a/src/app/api/strategies/route.ts
+++ b/src/app/api/strategies/route.ts
@@ -9,29 +9,34 @@ import { MY_STORE } from '@/store';
import MyNumber from '@/utils/MyNumber';
import { IStrategy, NFTInfo, TokenInfo } from '@/strategies/IStrategy';
import { STRKFarmStrategyAPIResult } from '@/store/strkfarm.atoms';
+import EndurAtoms, { endur } from '@/store/endur.store';
+import { privatePoolsAtom } from '@/store/protocols';
export const revalidate = 3600; // 1 hr
const allPoolsAtom = atom((get) => {
const pools: PoolInfo[] = [];
- const poolAtoms = [ZkLendAtoms, NostraLendingAtoms];
+ const poolAtoms = [ZkLendAtoms, NostraLendingAtoms, EndurAtoms];
return poolAtoms.reduce((_pools, p) => _pools.concat(get(p.pools)), pools);
});
async function getPools(store: any, retry = 0) {
const allPools: PoolInfo[] | undefined = store.get(allPoolsAtom);
+ // ! todo endur rewards
+ // const endurRewards = store.get(EndurAtoms.rewardInfo);
- const minProtocolsRequired = [zkLend.name, nostraLending.name];
+ const minProtocolsRequired = [zkLend.name, nostraLending.name, endur.name];
const hasRequiredPools = minProtocolsRequired.every((p) => {
if (!allPools) return false;
return allPools.some(
- (pool) => pool.protocol.name === p && pool.type == PoolType.Lending,
+ (pool) => pool.protocol.name === p && pool.type == PoolType.Lending, // || pool.type == PoolType.Staking),
);
});
const MAX_RETRIES = 120;
if (retry >= MAX_RETRIES) {
throw new Error('Failed to fetch pools');
} else if (!allPools || !hasRequiredPools) {
+ // || !endurRewards.data) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return getPools(store, retry + 1);
}
@@ -93,10 +98,11 @@ async function getStrategyInfo(
export async function GET(req: Request) {
const allPools = await getPools(MY_STORE);
const strategies = getStrategies();
+ const privatePools = MY_STORE.get(privatePoolsAtom);
strategies.forEach((strategy) => {
try {
- strategy.solve(allPools, '1000');
+ strategy.solve([...allPools, ...privatePools], '1000');
} catch (err) {
console.error('Error solving strategy', strategy.name, err);
}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index a498a71..faf12b3 100755
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -32,9 +32,9 @@ import { isMobile } from 'react-device-detect';
const banner_images = [
{
- desktop: '/banners/ognft.svg',
- mobile: '/banners/ognft_small.svg',
- link: 'https://x.com/strkfarm/status/1788558092109775029',
+ desktop: '/banners/endur.svg',
+ mobile: '/banners/endur_mobile.svg',
+ link: 'https://endur.fi',
},
{
desktop: '/banners/seed_grant.svg',
diff --git a/src/app/strategy/[strategyId]/_components/Strategy.tsx b/src/app/strategy/[strategyId]/_components/Strategy.tsx
index be36926..21df5fb 100755
--- a/src/app/strategy/[strategyId]/_components/Strategy.tsx
+++ b/src/app/strategy/[strategyId]/_components/Strategy.tsx
@@ -330,20 +330,22 @@ const Strategy = ({ params }: StrategyParams) => {
/>
{strategy.settings.alerts != undefined && (
- {strategy.settings.alerts.map((alert, index) => (
-
-
- {alert.text}
-
- ))}
+ {strategy.settings.alerts
+ .filter((a) => a.tab == 'deposit')
+ .map((alert, index) => (
+
+
+ {alert.text}
+
+ ))}
)}
@@ -358,6 +360,26 @@ const Strategy = ({ params }: StrategyParams) => {
buttonText="Redeem"
callsInfo={strategy.withdrawMethods}
/>
+ {strategy.settings.alerts != undefined && (
+
+ {strategy.settings.alerts
+ .filter((a) => a.tab == 'withdraw')
+ .map((alert, index) => (
+
+
+ {alert.text}
+
+ ))}
+
+ )}
diff --git a/src/components/HarvestTime.tsx b/src/components/HarvestTime.tsx
index 088bbfd..61c52a3 100644
--- a/src/components/HarvestTime.tsx
+++ b/src/components/HarvestTime.tsx
@@ -126,7 +126,7 @@ const HarvestTime: React.FC = ({ strategy, balData }) => {
- {!isMobile && (
+ {!isMobile && !strategy.settings.hideHarvestInfo && (
@@ -213,37 +213,39 @@ const HarvestTime: React.FC = ({ strategy, balData }) => {
)}
-
-
- Harvested{' '}
-
- {getDisplayCurrencyAmount(
- harvestTime?.data?.totalStrkHarvestedByContract.STRKAmount || 0,
- 2,
- )}{' '}
- STRK
- {' '}
- over {harvestTime?.data?.totalHarvestsByContract} claims. {' '}
- {lastHarvest && (
-
- Last harvested {timeAgo(lastHarvest)} .
-
- )}
-
-
+
+ Harvested{' '}
+
+ {getDisplayCurrencyAmount(
+ harvestTime?.data?.totalStrkHarvestedByContract.STRKAmount || 0,
+ 2,
+ )}{' '}
+ STRK
+ {' '}
+ over {harvestTime?.data?.totalHarvestsByContract} claims. {' '}
+ {lastHarvest && (
+
+ Last harvested {timeAgo(lastHarvest)} .
+
+ )}
+
+
+ )}
);
};
diff --git a/src/components/Strategies.tsx b/src/components/Strategies.tsx
index 91aefdf..57eb329 100755
--- a/src/components/Strategies.tsx
+++ b/src/components/Strategies.tsx
@@ -1,4 +1,4 @@
-import CONSTANTS from '@/constants';
+import { usePagination } from '@ajna/pagination';
import {
Container,
Link,
@@ -13,13 +13,16 @@ import {
} from '@chakra-ui/react';
import { useAtomValue } from 'jotai';
import React, { useMemo } from 'react';
+
+import CONSTANTS from '@/constants';
import { filteredPools } from '@/store/protocols';
-import { usePagination } from '@ajna/pagination';
-import { YieldStrategyCard } from './YieldCard';
import {
STRKFarmBaseAPYsAtom,
STRKFarmStrategyAPIResult,
} from '@/store/strkfarm.atoms';
+
+import { YieldStrategyCard } from './YieldCard';
+
export default function Strategies() {
const strkFarmPoolsRes = useAtomValue(STRKFarmBaseAPYsAtom);
const strkFarmPools = useMemo(() => {
diff --git a/src/components/YieldCard.tsx b/src/components/YieldCard.tsx
index 4dfecd8..5d80544 100644
--- a/src/components/YieldCard.tsx
+++ b/src/components/YieldCard.tsx
@@ -1,5 +1,13 @@
+import shield from '@/assets/shield.svg';
import CONSTANTS from '@/constants';
+import { addressAtom } from '@/store/claims.atoms';
import { PoolInfo } from '@/store/pools';
+import { getPoolInfoFromStrategy, sortAtom } from '@/store/protocols';
+import { STRKFarmStrategyAPIResult } from '@/store/strkfarm.atoms';
+import { UserStats, userStatsAtom } from '@/store/utils.atoms';
+import { isLive, StrategyLiveStatus } from '@/strategies/IStrategy';
+import { getDisplayCurrencyAmount } from '@/utils';
+import { TriangleDownIcon, TriangleUpIcon } from '@chakra-ui/icons';
import {
Avatar,
AvatarGroup,
@@ -21,18 +29,10 @@ import {
Tr,
VStack,
} from '@chakra-ui/react';
-import shield from '@/assets/shield.svg';
-import { StrategyLiveStatus } from '@/strategies/IStrategy';
import { useAtomValue } from 'jotai';
-import { getDisplayCurrencyAmount } from '@/utils';
-import { addressAtom } from '@/store/claims.atoms';
-import { FaWallet } from 'react-icons/fa';
-import { UserStats, userStatsAtom } from '@/store/utils.atoms';
-import { getPoolInfoFromStrategy, sortAtom } from '@/store/protocols';
-import { TriangleDownIcon, TriangleUpIcon } from '@chakra-ui/icons';
import mixpanel from 'mixpanel-browser';
-import { STRKFarmStrategyAPIResult } from '@/store/strkfarm.atoms';
import { isMobile } from 'react-device-detect';
+import { FaWallet } from 'react-icons/fa';
interface YieldCardProps {
pool: PoolInfo;
@@ -41,14 +41,17 @@ interface YieldCardProps {
}
function getStratCardBg(status: StrategyLiveStatus, index: number) {
- if (status == StrategyLiveStatus.ACTIVE || status == StrategyLiveStatus.NEW) {
+ if (status == StrategyLiveStatus.HOT) {
+ return '#414173';
+ }
+ if (isLive(status)) {
return index % 2 === 0 ? 'color1_50p' : 'color2_50p';
}
return 'bg';
}
function getStratCardBadgeBg(status: StrategyLiveStatus) {
- if (status === StrategyLiveStatus.NEW) {
+ if (isLive(status)) {
return 'cyan';
} else if (status === StrategyLiveStatus.COMING_SOON) {
return 'yellow';
@@ -201,12 +204,6 @@ function StrategyAPY(props: YieldCardProps) {
);
}
-function isLive(status: StrategyLiveStatus) {
- return (
- status === StrategyLiveStatus.ACTIVE || status === StrategyLiveStatus.NEW
- );
-}
-
function getStrategyWiseHoldingsInfo(
userData: UserStats | null | undefined,
id: string,
@@ -489,7 +486,7 @@ export default function YieldCard(props: YieldCardProps) {
<>
{
+ name = 'Endur';
+ link = 'https://endur.fi/r/strkfarm';
+ logo = 'https://endur.fi/favicon.ico';
+ incentiveDataKey: string = 'Endur';
+}
+
+export const endur = new Endur();
+
+const EndurAtoms = {
+ endurStats: customAtomWithFetch({
+ url: 'https://testnet.endur.fi/api/stats',
+ queryKey: 'Endur_stats',
+ }),
+ rewardInfo: customAtomWithQuery({
+ queryKey: 'Endur_reward',
+ queryFn: async () => {
+ const REWARDS_CONTRACT =
+ '0x3065fe1dacfaa108a764a9db51d9a5d1cbe7e23a8a9c9e13f12c291da1c1dbb';
+ const contract = new Contract(RewardsAbi, REWARDS_CONTRACT, provider);
+ const data: any = await contract.call('get_config', []);
+
+ const autoxSTRK = new AutoXSTRKStrategy(
+ 'autoxstrk',
+ 'autoxstrk',
+ CONSTANTS.CONTRACTS.AutoxSTRKFarm,
+ {
+ maxTVL: 2000000,
+ },
+ );
+ const STRK = getTokenInfoFromName('STRK');
+ const rewardsPerSecond = new MyNumber(
+ data.rewards_per_second.toString(),
+ STRK.decimals,
+ );
+ const tvl = await autoxSTRK.getTVL();
+
+ const apy =
+ Number(
+ rewardsPerSecond
+ .operate('mul', 365 * 24 * 60 * 60)
+ .toEtherToFixedDecimals(2),
+ ) / Number(tvl.amount.toEtherToFixedDecimals(2));
+ return apy;
+ },
+ }),
+ pools: atom((get) => {
+ const empty: PoolInfo[] = [];
+ const stats = get(EndurAtoms.endurStats);
+ if (stats.data) {
+ const poolInfo: PoolInfo = {
+ pool: {
+ id: 'endur_strk',
+ name: 'STRK',
+ logos: [getTokenInfoFromName('STRK').logo],
+ },
+ protocol: {
+ name: endur.name,
+ link: endur.link,
+ logo: endur.logo,
+ },
+ apr: stats.data.apy,
+ tvl: stats.data.tvl,
+ aprSplits: [
+ {
+ apr: stats.data.apy,
+ title: 'Net Yield',
+ description: 'Includes fees & Defi spring rewards',
+ },
+ ],
+ category: Category.STRK,
+ type: PoolType.Staking,
+ additional: {
+ riskFactor: 0.5,
+ tags: [StrategyLiveStatus.HOT],
+ isAudited: true,
+ },
+ borrow: {
+ apr: 0,
+ borrowFactor: 0,
+ },
+ lending: {
+ collateralFactor: 0,
+ },
+ };
+ return [poolInfo];
+ }
+ return empty;
+ }),
+};
+
+export default EndurAtoms;
diff --git a/src/store/pools.ts b/src/store/pools.ts
index 934c5f7..93547ef 100755
--- a/src/store/pools.ts
+++ b/src/store/pools.ts
@@ -17,6 +17,7 @@ export enum PoolType {
DEXV3 = 'Concentrated LP DEX',
Lending = 'Lending',
Derivatives = 'Derivatives',
+ Staking = 'Staking',
}
export interface APRSplit {
@@ -57,6 +58,39 @@ export interface PoolInfo extends PoolMetadata {
riskFactor: number;
tags: StrategyLiveStatus[];
isAudited: boolean;
+ is_promoted?: boolean;
+ };
+}
+
+export function getDefaultPoolInfo(): PoolInfo {
+ return {
+ pool: {
+ id: '',
+ name: '',
+ logos: [],
+ },
+ protocol: {
+ name: '',
+ link: '',
+ logo: '',
+ },
+ apr: 0,
+ tvl: 0,
+ aprSplits: [],
+ category: Category.Others,
+ type: PoolType.Derivatives,
+ additional: {
+ riskFactor: 0,
+ tags: [],
+ isAudited: false,
+ },
+ borrow: {
+ apr: 0,
+ borrowFactor: 0,
+ },
+ lending: {
+ collateralFactor: 0,
+ },
};
}
diff --git a/src/store/protocols.ts b/src/store/protocols.ts
index 93f1243..356ac19 100644
--- a/src/store/protocols.ts
+++ b/src/store/protocols.ts
@@ -1,23 +1,29 @@
+import strkfarmLogo from '@public/logo.png';
+import { atom } from 'jotai';
+import CarmineAtoms, { carmine } from './carmine.store';
import EkuboAtoms, { ekubo } from './ekobu.store';
import HaikoAtoms, { haiko } from './haiko.store';
import HashstackAtoms, { hashstack } from './hashstack.store';
import MySwapAtoms, { mySwap } from './myswap.store';
-import NostraDexAtoms, { nostraDex } from './nostradex.store';
import NostraDegenAtoms, { nostraDegen } from './nostradegen.store';
+import NostraDexAtoms, { nostraDex } from './nostradex.store';
import NostraLendingAtoms, { nostraLending } from './nostralending.store';
-import VesuAtoms, { vesu } from './vesu.store';
-import ZkLendAtoms, { zkLend } from './zklend.store';
-import CarmineAtoms, { carmine } from './carmine.store';
-import { atom } from 'jotai';
import { Category, PoolInfo, PoolType } from './pools';
-import strkfarmLogo from '@public/logo.png';
+import { getLiveStatusEnum } from './strategies.atoms';
import STRKFarmAtoms, {
strkfarm,
STRKFarmStrategyAPIResult,
} from './strkfarm.atoms';
-import { getLiveStatusEnum } from './strategies.atoms';
+import VesuAtoms, { vesu } from './vesu.store';
+import ZkLendAtoms, { zkLend } from './zklend.store';
+import EndurAtoms, { endur } from './endur.store';
export const PROTOCOLS = [
+ {
+ name: endur.name,
+ class: endur,
+ atoms: EndurAtoms,
+ },
{
name: strkfarm.name,
class: strkfarm,
@@ -106,11 +112,12 @@ const allProtocols = PROTOCOLS.map((p) => ({
name: p.name,
logo: p.class.logo,
}));
+
export const filters = {
categories: [...Object.values(Category)],
types: [...Object.values(PoolType)],
protocols: allProtocols.filter(
- (p, index) => allProtocols.findIndex((_p) => _p.name == p.name) == index,
+ (p, index) => allProtocols.findIndex((_p) => _p.name === p.name) === index,
),
};
@@ -142,6 +149,27 @@ export const updateFiltersAtom = atom(
},
);
+const privateProtocols = [
+ {
+ name: endur.name,
+ class: endur,
+ atoms: EndurAtoms,
+ },
+];
+
+export const privatePoolsAtom = atom((get) => {
+ // const pools: PoolInfo[] = [];
+ // const otherPools = getPrivatePools(get);
+ // return [
+ // ...privateProtocols.reduce(
+ // (_pools, p) => _pools.concat(get(p.atoms.pools)),
+ // pools,
+ // ),
+ // ...otherPools,
+ // ];
+ return [] as PoolInfo[];
+});
+
export const allPoolsAtomUnSorted = atom((get) => {
const pools: PoolInfo[] = [];
return PROTOCOLS.reduce(
@@ -193,6 +221,7 @@ export function getPoolInfoFromStrategy(
tags: [getLiveStatusEnum(strat.status.number)],
isAudited: strat.name.includes('XL') ? false : true,
leverage: strat.leverage,
+ is_promoted: strat.name.includes('Stake'),
},
};
}
diff --git a/src/store/strategies.atoms.ts b/src/store/strategies.atoms.ts
index db032d5..f7d1868 100755
--- a/src/store/strategies.atoms.ts
+++ b/src/store/strategies.atoms.ts
@@ -9,8 +9,11 @@ import CONSTANTS from '@/constants';
import { DeltaNeutralMM } from '@/strategies/delta_neutral_mm';
import Mustache from 'mustache';
import { getTokenInfoFromName } from '@/utils';
-import { allPoolsAtomUnSorted } from './protocols';
+import { allPoolsAtomUnSorted, privatePoolsAtom } from './protocols';
import { DeltaNeutralMM2 } from '@/strategies/delta_neutral_mm_2';
+import { AutoXSTRKStrategy } from '@/strategies/auto_xstrk.strat';
+import EndurAtoms, { endur } from './endur.store';
+import { getDefaultPoolInfo, PoolInfo } from './pools';
export interface StrategyInfo extends IStrategyProps {
name: string;
@@ -72,6 +75,13 @@ export function getStrategies() {
StrategyLiveStatus.ACTIVE,
{
maxTVL: 1000,
+ alerts: [
+ {
+ type: 'info',
+ text: 'Pro tip: Try to split your deposit between this strategy and ETH Sensei XL to avoid impact of yield fluctuations',
+ tab: 'deposit',
+ },
+ ],
},
);
const deltaNeutralMMSTRKETH = new DeltaNeutralMM(
@@ -98,6 +108,24 @@ export function getStrategies() {
StrategyLiveStatus.NEW,
{
maxTVL: 2000,
+ alerts: [
+ {
+ type: 'info',
+ text: 'Pro tip: Try to split your deposit between this strategy and ETH Sensei to avoid impact of yield fluctuations',
+ tab: 'deposit',
+ },
+ ],
+ },
+ );
+
+ const xSTRKStrategy = new AutoXSTRKStrategy(
+ 'Stake STRK',
+ 'Endur is Starknet’s dedicated staking platform, where you can stake STRK to earn staking rewards. This strategy, built on Endur, is an incentivized vault that boosts returns by offering additional rewards. In the future, it may transition to auto-compounding on DeFi Spring, reinvesting rewards for maximum growth. Changes will be announced at least three days in advance on our socials.',
+ CONSTANTS.CONTRACTS.AutoxSTRKFarm,
+ {
+ maxTVL: 2000000,
+ alerts: [],
+ is_promoted: true,
},
);
@@ -108,6 +136,7 @@ export function getStrategies() {
deltaNeutralMMETHUSDC,
deltaNeutralMMSTRKETH,
deltaNeutralMMETHUSDCReverse,
+ // xSTRKStrategy,
];
return strategies;
@@ -115,15 +144,35 @@ export function getStrategies() {
export const STRATEGIES_INFO = getStrategies();
+export const getPrivatePools = (get: any) => {
+ // A placeholder to fetch any external pools/rewards info
+ // that is not necessarily available in the allPools (i.e. not public)
+ const endurRewardInfo = get(EndurAtoms.rewardInfo);
+ const endurRewardPoolInfo = getDefaultPoolInfo();
+ endurRewardPoolInfo.pool.id = 'endur_strk_reward';
+ endurRewardPoolInfo.protocol.name = endur.name;
+ endurRewardPoolInfo.protocol.link = endur.link;
+ endurRewardPoolInfo.protocol.logo = endur.logo;
+ endurRewardPoolInfo.pool.name = 'STRK';
+ endurRewardPoolInfo.pool.logos = [getTokenInfoFromName('STRK').logo];
+ endurRewardPoolInfo.apr = endurRewardInfo.data || 0;
+
+ return [endurRewardPoolInfo];
+};
+
export const strategiesAtom = atom((get) => {
const strategies = getStrategies();
const allPools = get(allPoolsAtomUnSorted);
const requiredPools = allPools.filter(
- (p) => p.protocol.name === 'zkLend' || p.protocol.name === 'Nostra',
+ (p) =>
+ p.protocol.name === 'zkLend' ||
+ p.protocol.name === 'Nostra' ||
+ p.protocol.name === endur.name,
);
+ const privatePools: PoolInfo[] = get(privatePoolsAtom);
for (const s of strategies) {
- s.solve(requiredPools, '1000');
+ s.solve([...requiredPools, ...privatePools], '1000');
}
strategies.sort((a, b) => {
@@ -141,6 +190,8 @@ export function getLiveStatusNumber(status: StrategyLiveStatus) {
return 2;
} else if (status == StrategyLiveStatus.COMING_SOON) {
return 3;
+ } else if (status == StrategyLiveStatus.HOT) {
+ return 5;
}
return 4;
}
@@ -152,6 +203,8 @@ export function getLiveStatusEnum(status: number) {
return StrategyLiveStatus.ACTIVE;
} else if (status == 3) {
return StrategyLiveStatus.COMING_SOON;
+ } else if (status == 5) {
+ return StrategyLiveStatus.HOT;
}
return StrategyLiveStatus.RETIRED;
}
diff --git a/src/store/strkfarm.atoms.ts b/src/store/strkfarm.atoms.ts
index b0b0aa5..6c2520d 100644
--- a/src/store/strkfarm.atoms.ts
+++ b/src/store/strkfarm.atoms.ts
@@ -88,6 +88,7 @@ export class STRKFarm extends IDapp {
riskFactor,
tags: [getLiveStatusEnum(rawPool.status.number)],
isAudited: poolName.includes('XL') ? false : true,
+ is_promoted: poolName.includes('Stake'),
},
};
return poolInfo;
diff --git a/src/strategies/IStrategy.ts b/src/strategies/IStrategy.ts
index 2854896..21e2639 100755
--- a/src/strategies/IStrategy.ts
+++ b/src/strategies/IStrategy.ts
@@ -63,6 +63,7 @@ export enum StrategyLiveStatus {
NEW = 'New',
COMING_SOON = 'Coming Soon',
RETIRED = 'Retired',
+ HOT = 'Hot & New 🔥',
}
export interface IStrategyActionHook {
@@ -73,7 +74,13 @@ export interface IStrategyActionHook {
export interface IStrategySettings {
maxTVL: number;
- alerts?: { type: 'warning'; text: string }[];
+ alerts?: {
+ type: 'warning' | 'info';
+ text: string;
+ tab: 'all' | 'deposit' | 'withdraw';
+ }[];
+ hideHarvestInfo?: boolean;
+ is_promoted?: boolean;
}
export interface AmountInfo {
@@ -89,6 +96,14 @@ export interface DepositActionInputs {
isMax: boolean;
}
+export function isLive(status: StrategyLiveStatus) {
+ return (
+ status == StrategyLiveStatus.ACTIVE ||
+ status == StrategyLiveStatus.HOT ||
+ status == StrategyLiveStatus.NEW
+ );
+}
+
export interface WithdrawActionInputs extends DepositActionInputs {}
export class IStrategyProps {
@@ -144,10 +159,7 @@ export class IStrategyProps {
};
isLive() {
- return (
- this.liveStatus == StrategyLiveStatus.ACTIVE ||
- this.liveStatus == StrategyLiveStatus.NEW
- );
+ return isLive(this.liveStatus);
}
constructor(
@@ -306,6 +318,7 @@ export class IStrategy extends IStrategyProps {
_amount,
},
this.actions,
+ _pools,
);
if (_pools.length > 0) {
@@ -338,7 +351,7 @@ export class IStrategy extends IStrategyProps {
console.log('netYield1', sign, apr, action.amount, netYield);
});
this.netYield = netYield / Number(amount);
- console.log('netYield', netYield, this.netYield, Number(amount));
+ console.log('netYield2', netYield, this.netYield, Number(amount));
this.leverage = this.netYield / this.actions[0].pool.apr;
this.postSolve();
diff --git a/src/strategies/auto_xstrk.strat.ts b/src/strategies/auto_xstrk.strat.ts
new file mode 100644
index 0000000..15586d8
--- /dev/null
+++ b/src/strategies/auto_xstrk.strat.ts
@@ -0,0 +1,356 @@
+import CONSTANTS, { TOKENS, provider } from '@/constants';
+import { PoolInfo } from '@/store/pools';
+import {
+ DepositActionInputs,
+ IStrategy,
+ IStrategySettings,
+ StrategyAction,
+ StrategyLiveStatus,
+ TokenInfo,
+ WithdrawActionInputs,
+} from './IStrategy';
+import ERC20Abi from '@/abi/erc20.abi.json';
+import AutoStrkAbi from '@/abi/autoStrk.abi.json';
+import MasterAbi from '@/abi/master.abi.json';
+import MyNumber from '@/utils/MyNumber';
+import { Contract, num, uint256 } from 'starknet';
+import { atom } from 'jotai';
+import {
+ DUMMY_BAL_ATOM,
+ getBalance,
+ getBalanceAtom,
+ getERC20BalanceAtom,
+} from '@/store/balance.atoms';
+import { getPrice, getTokenInfoFromName } from '@/utils';
+import { endur } from '@/store/endur.store';
+
+interface Step {
+ name: string;
+ optimizer: (
+ pools: PoolInfo[],
+ amount: string,
+ prevActions: StrategyAction[],
+ ) => StrategyAction[];
+ filter: ((
+ pools: PoolInfo[],
+ amount: string,
+ prevActions: StrategyAction[],
+ ) => PoolInfo[])[];
+}
+
+export class AutoXSTRKStrategy extends IStrategy {
+ riskFactor = 0.5;
+ token: TokenInfo;
+ readonly lpTokenName: string;
+ readonly strategyAddress: string;
+
+ constructor(
+ name: string,
+ description: string,
+ strategyAddress: string,
+ settings: IStrategySettings,
+ ) {
+ const rewardTokens = [{ logo: CONSTANTS.LOGOS.STRK }];
+ const frmToken = TOKENS.find((t) => t.token == strategyAddress);
+ if (!frmToken) throw new Error('frmToken undefined');
+ const holdingTokens = [frmToken];
+
+ const token = 'STRK';
+ super(
+ `stake_${token.toLowerCase()}`,
+ 'Stake STRK',
+ name,
+ description,
+ rewardTokens,
+ holdingTokens,
+ StrategyLiveStatus.HOT,
+ settings,
+ );
+ this.token = getTokenInfoFromName(token);
+ // ! Change this to xSTRK later
+ this.lpTokenName = 'xSTRK';
+
+ this.steps = [
+ {
+ name: `Stake your ${token} to Endur`,
+ optimizer: this.optimizer,
+ filter: [this.filterSTRKEndur()],
+ },
+ {
+ name: `Collect launch incentives`,
+ optimizer: this.optimizer,
+ filter: [
+ (pools, _, _actions) => {
+ const eligiblePools = pools.filter(
+ (p) => p.pool.id == 'endur_strk_reward',
+ );
+ if (!eligiblePools)
+ throw new Error(`${this.tag}: [F1] no eligible pools`);
+ return eligiblePools;
+ },
+ ],
+ },
+ ];
+ const _risks = [...this.risks];
+ this.risks = [
+ this.getSafetyFactorLine(),
+ `Your original investment is safe. If you deposit 100 tokens, you will always get at least 100 tokens back, unless due to below reasons.`,
+ ..._risks.slice(1),
+ ];
+ this.strategyAddress = strategyAddress;
+
+ this.settings.alerts = [
+ {
+ type: 'info',
+ text: 'Pro tip: You can deposit STRK or xSTRK by selecting the token from above dropdown. STRK deposited staked to convert to xSTRK',
+ tab: 'deposit',
+ },
+ {
+ type: 'warning',
+ text: 'On withdrawal, you will receive xSTRK. You can redeem xSTRK for STRK on endur.fi',
+ tab: 'withdraw',
+ },
+ ];
+ this.settings.hideHarvestInfo = true;
+ }
+
+ filterSTRKEndur() {
+ return (
+ pools: PoolInfo[],
+ amount: string,
+ prevActions: StrategyAction[],
+ ) => {
+ console.log('filterSTRKEndur', pools);
+ return pools.filter(
+ (p) => p.pool.name == 'STRK' && p.protocol.name == endur.name,
+ );
+ };
+ }
+
+ optimizer(
+ eligiblePools: PoolInfo[],
+ amount: string,
+ actions: StrategyAction[],
+ ): StrategyAction[] {
+ console.log('optimizer', eligiblePools);
+ return [...actions, { pool: eligiblePools[0], amount, isDeposit: true }];
+ }
+
+ getUserTVL = async (user: string) => {
+ if (this.liveStatus == StrategyLiveStatus.COMING_SOON)
+ return {
+ amount: MyNumber.fromEther('0', this.token.decimals),
+ usdValue: 0,
+ tokenInfo: this.token,
+ };
+
+ // returns zToken
+ const balanceInfo = await getBalance(this.holdingTokens[0], user);
+ if (!balanceInfo.tokenInfo) {
+ return {
+ amount: MyNumber.fromEther('0', this.token.decimals),
+ usdValue: 0,
+ tokenInfo: this.token,
+ };
+ }
+ const price = await getPrice(this.token);
+ console.log('getUserTVL autoc', price, balanceInfo.amount.toEtherStr());
+ return {
+ amount: balanceInfo.amount,
+ usdValue: Number(balanceInfo.amount.toEtherStr()) * price,
+ tokenInfo: balanceInfo.tokenInfo,
+ };
+ };
+
+ getTVL = async () => {
+ if (!this.isLive())
+ return {
+ amount: MyNumber.fromEther('0', this.token.decimals),
+ usdValue: 0,
+ tokenInfo: this.token,
+ };
+
+ const strategyContract = new Contract(
+ AutoStrkAbi,
+ this.strategyAddress,
+ provider,
+ );
+ const asset = num.getHexString(
+ (await strategyContract.call('asset', [])).toString(),
+ );
+ console.log(`getTVL asset`, asset);
+ const STRKINfo = getTokenInfoFromName('STRK');
+ const isSTRK = asset == STRKINfo.token;
+ const xSTRKInfo = getTokenInfoFromName('xSTRK');
+ const isxSTRK = asset == xSTRKInfo.token;
+ console.log(`getTVL isSTRK`, isSTRK, isxSTRK);
+ if (isSTRK) {
+ const totalAssets = new MyNumber(
+ (await strategyContract.call('total_assets', [])).toString(),
+ STRKINfo.decimals,
+ );
+ const price = await getPrice(this.token);
+ return {
+ amount: totalAssets,
+ usdValue: Number(totalAssets.toEtherStr()) * price,
+ tokenInfo: STRKINfo,
+ };
+ } else if (isxSTRK) {
+ const xSTRKTotalAssets = new MyNumber(
+ (await strategyContract.call('total_assets', [])).toString(),
+ xSTRKInfo.decimals,
+ );
+ const xSTRKContract = new Contract(
+ AutoStrkAbi,
+ xSTRKInfo.token,
+ provider,
+ );
+ const strkAmount = new MyNumber(
+ (
+ await xSTRKContract.call('convert_to_assets', [
+ uint256.bnToUint256(xSTRKTotalAssets.toString()),
+ ])
+ ).toString(),
+ STRKINfo.decimals,
+ );
+ const price = await getPrice(this.token);
+ return {
+ amount: strkAmount,
+ usdValue: Number(strkAmount.toEtherStr()) * price,
+ tokenInfo: STRKINfo,
+ };
+ }
+ throw new Error(`getTVL asset not STRK or xSTRK`);
+ };
+
+ depositMethods = (inputs: DepositActionInputs) => {
+ const { amount, address, provider } = inputs;
+ const baseTokenInfo: TokenInfo = TOKENS.find(
+ (t) => t.name == this.token.name,
+ ) as TokenInfo; //
+ const xTokenInfo: TokenInfo = TOKENS.find(
+ (t) => t.name == this.lpTokenName,
+ ) as TokenInfo;
+
+ if (!address || address == '0x0') {
+ return [
+ {
+ tokenInfo: baseTokenInfo,
+ calls: [],
+ balanceAtom: DUMMY_BAL_ATOM,
+ },
+ {
+ tokenInfo: xTokenInfo,
+ calls: [],
+ balanceAtom: DUMMY_BAL_ATOM,
+ },
+ ];
+ }
+
+ const baseTokenContract = new Contract(
+ ERC20Abi,
+ baseTokenInfo.token,
+ provider,
+ );
+ const xTokenContract = new Contract(ERC20Abi, xTokenInfo.token, provider);
+ const masterContract = new Contract(
+ MasterAbi,
+ CONSTANTS.CONTRACTS.Master,
+ provider,
+ );
+ const strategyContract = new Contract(
+ AutoStrkAbi,
+ this.strategyAddress,
+ provider,
+ );
+
+ // base token
+ const call11 = baseTokenContract.populate('approve', [
+ masterContract.address,
+ uint256.bnToUint256(amount.toString()),
+ ]);
+ const call12 = masterContract.populate('invest_to_xstrk_auto', [
+ this.strategyAddress,
+ uint256.bnToUint256(amount.toString()),
+ address,
+ ]);
+
+ // zToken
+ // ! switch to xSTRK later
+ const call21 = xTokenContract.populate('approve', [
+ this.strategyAddress,
+ uint256.bnToUint256(amount.toString()),
+ ]);
+ const call22 = strategyContract.populate('deposit', [
+ uint256.bnToUint256(amount.toString()),
+ address,
+ ]);
+
+ const calls1 = [call11, call12];
+ const calls2 = [call21, call22];
+
+ return [
+ {
+ tokenInfo: baseTokenInfo,
+ calls: calls1,
+ balanceAtom: getBalanceAtom(baseTokenInfo, atom(true)),
+ },
+ {
+ tokenInfo: xTokenInfo,
+ calls: calls2,
+ balanceAtom: getBalanceAtom(xTokenInfo, atom(true)),
+ },
+ ];
+ };
+
+ withdrawMethods = (inputs: WithdrawActionInputs) => {
+ const { amount, address, provider } = inputs;
+ const frmToken: TokenInfo = TOKENS.find(
+ (t) => t.token == this.strategyAddress,
+ ) as TokenInfo;
+
+ if (!address || address == '0x0') {
+ return [
+ {
+ tokenInfo: frmToken,
+ calls: [],
+ balanceAtom: DUMMY_BAL_ATOM,
+ },
+ ];
+ }
+
+ // const baseTokenContract = new Contract(ERC20Abi, baseTokenInfo.token, provider);
+ const frmTokenContract = new Contract(ERC20Abi, frmToken.token, provider);
+ // const masterContract = new Contract(MasterAbi, CONSTANTS.CONTRACTS.Master, provider);
+ const strategyContract = new Contract(
+ AutoStrkAbi,
+ this.strategyAddress,
+ provider,
+ );
+
+ // base token
+ // const call11 = baseTokenContract.populate("approve", [masterContract.address, uint256.bnToUint256(amount.toString())])
+ // const call12 = masterContract.populate("invest_auto_strk", [this.strategyAddress, uint256.bnToUint256(amount.toString()), address])
+
+ // zToken
+ // const call1 = frmTokenContract.populate('approve', [
+ // this.strategyAddress,
+ // uint256.bnToUint256(amount.toString()),
+ // ]);
+ const call2 = strategyContract.populate('redeem', [
+ uint256.bnToUint256(amount.toString()),
+ address,
+ address,
+ ]);
+
+ const calls = [call2];
+
+ return [
+ {
+ tokenInfo: frmToken,
+ calls,
+ balanceAtom: getERC20BalanceAtom(frmToken),
+ },
+ ];
+ };
+}
diff --git a/src/utils/MyNumber.ts b/src/utils/MyNumber.ts
index 93edd5d..85da1ae 100755
--- a/src/utils/MyNumber.ts
+++ b/src/utils/MyNumber.ts
@@ -65,7 +65,7 @@ export default class MyNumber {
return this.bigNumber[command](fullNum);
}
- operate(command: 'div' | 'plus', value: string | number) {
+ operate(command: 'div' | 'plus' | 'mul', value: string | number) {
const bn = new BigNumber(Number(value).toFixed(6));
return new MyNumber(this.bigNumber[command](bn).toFixed(0), this.decimals);
}
From 98f906b808408ef2049030d0d16c061f9d360097 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Mon, 25 Nov 2024 21:10:19 +0530
Subject: [PATCH 19/22] fix /strategies API
---
src/app/api/strategies/route.ts | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/app/api/strategies/route.ts b/src/app/api/strategies/route.ts
index 852c1aa..5b07558 100755
--- a/src/app/api/strategies/route.ts
+++ b/src/app/api/strategies/route.ts
@@ -9,34 +9,29 @@ import { MY_STORE } from '@/store';
import MyNumber from '@/utils/MyNumber';
import { IStrategy, NFTInfo, TokenInfo } from '@/strategies/IStrategy';
import { STRKFarmStrategyAPIResult } from '@/store/strkfarm.atoms';
-import EndurAtoms, { endur } from '@/store/endur.store';
-import { privatePoolsAtom } from '@/store/protocols';
export const revalidate = 3600; // 1 hr
const allPoolsAtom = atom((get) => {
const pools: PoolInfo[] = [];
- const poolAtoms = [ZkLendAtoms, NostraLendingAtoms, EndurAtoms];
+ const poolAtoms = [ZkLendAtoms, NostraLendingAtoms];
return poolAtoms.reduce((_pools, p) => _pools.concat(get(p.pools)), pools);
});
async function getPools(store: any, retry = 0) {
const allPools: PoolInfo[] | undefined = store.get(allPoolsAtom);
- // ! todo endur rewards
- // const endurRewards = store.get(EndurAtoms.rewardInfo);
- const minProtocolsRequired = [zkLend.name, nostraLending.name, endur.name];
+ const minProtocolsRequired = [zkLend.name, nostraLending.name];
const hasRequiredPools = minProtocolsRequired.every((p) => {
if (!allPools) return false;
return allPools.some(
- (pool) => pool.protocol.name === p && pool.type == PoolType.Lending, // || pool.type == PoolType.Staking),
+ (pool) => pool.protocol.name === p && pool.type == PoolType.Lending,
);
});
const MAX_RETRIES = 120;
if (retry >= MAX_RETRIES) {
throw new Error('Failed to fetch pools');
} else if (!allPools || !hasRequiredPools) {
- // || !endurRewards.data) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return getPools(store, retry + 1);
}
@@ -98,11 +93,10 @@ async function getStrategyInfo(
export async function GET(req: Request) {
const allPools = await getPools(MY_STORE);
const strategies = getStrategies();
- const privatePools = MY_STORE.get(privatePoolsAtom);
strategies.forEach((strategy) => {
try {
- strategy.solve([...allPools, ...privatePools], '1000');
+ strategy.solve(allPools, '1000');
} catch (err) {
console.error('Error solving strategy', strategy.name, err);
}
From aba46de92948e052d4721cd779ec2998ccba4c1c Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Mon, 25 Nov 2024 21:41:05 +0530
Subject: [PATCH 20/22] update endur endpoint
---
src/store/endur.store.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/store/endur.store.ts b/src/store/endur.store.ts
index 7530236..1fc8e65 100644
--- a/src/store/endur.store.ts
+++ b/src/store/endur.store.ts
@@ -38,7 +38,7 @@ export const endur = new Endur();
const EndurAtoms = {
endurStats: customAtomWithFetch({
- url: 'https://testnet.endur.fi/api/stats',
+ url: 'https://app.endur.fi/api/stats',
queryKey: 'Endur_stats',
}),
rewardInfo: customAtomWithQuery({
From 9058b6103291e3c3a33eed8b94ad82003c50bc87 Mon Sep 17 00:00:00 2001
From: akiraonstarknet
Date: Mon, 25 Nov 2024 21:43:00 +0530
Subject: [PATCH 21/22] fix banner pointer
---
src/app/page.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/app/page.tsx b/src/app/page.tsx
index faf12b3..20d1929 100755
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -34,7 +34,7 @@ const banner_images = [
{
desktop: '/banners/endur.svg',
mobile: '/banners/endur_mobile.svg',
- link: 'https://endur.fi',
+ link: 'https://endur.fi/r/strkfarm',
},
{
desktop: '/banners/seed_grant.svg',
@@ -114,7 +114,7 @@ export default function Home() {
-
+
{banner_images.map((banner, index) => (
Date: Tue, 26 Nov 2024 16:36:19 +0530
Subject: [PATCH 22/22] update endur banners
---
public/banners/endur.svg | 230 +++++++++++++++++++++++++-------
public/banners/endur_mobile.svg | 228 ++++++++++++++++++++++++-------
2 files changed, 360 insertions(+), 98 deletions(-)
diff --git a/public/banners/endur.svg b/public/banners/endur.svg
index 20e2109..6df51de 100644
--- a/public/banners/endur.svg
+++ b/public/banners/endur.svg
@@ -1,61 +1,191 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
diff --git a/public/banners/endur_mobile.svg b/public/banners/endur_mobile.svg
index d9c328d..770a4ce 100644
--- a/public/banners/endur_mobile.svg
+++ b/public/banners/endur_mobile.svg
@@ -1,59 +1,191 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+