Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
07cb796
Enhance SVG handling and UI components
EjembiEmmanuel Jul 8, 2025
5693571
Add APY History component and integrate into Strategy view
EjembiEmmanuel Jul 9, 2025
07a1dd0
Refactor Strategy component and enhance UI consistency
EjembiEmmanuel Jul 9, 2025
889f3d0
Update dependencies in package.json and yarn.lock
EjembiEmmanuel Jul 10, 2025
ac12293
Enhance APYHistory component with time range selection and theme updates
EjembiEmmanuel Jul 10, 2025
ca115d9
Refactor UI components for improved styling
EjembiEmmanuel Jul 11, 2025
a3ad68c
add zklend batch 2
akiraonstarknet Jul 15, 2025
92ba903
Implement APY history retrieval and update pre-commit hook
EjembiEmmanuel Jul 24, 2025
1bfa417
fix xSTRK APY bug, increase xSTRK limit
akiraonstarknet Aug 6, 2025
5a5b7f4
update sensei - confirmation, faqs, etc
akiraonstarknet Aug 10, 2025
2d82dba
fix withdraw section i sensei
akiraonstarknet Aug 10, 2025
b884aa3
fix Received invalid amount bug
akiraonstarknet Aug 10, 2025
7a1fe1b
add errors in solve
akiraonstarknet Aug 10, 2025
b0c781f
Merge pull request #160 from akiraonstarknet/dev
akiraonstarknet Aug 10, 2025
2237d7e
add universal strategy
akiraonstarknet Aug 22, 2025
2366866
build fix
akiraonstarknet Aug 23, 2025
d12ce02
bump @strkfarm/sdk => 1.0.60, add UI details for meta strats
akiraonstarknet Aug 28, 2025
a6eabde
add @noble/curves
akiraonstarknet Aug 28, 2025
a310ccd
fix withdraw status in txs
akiraonstarknet Aug 28, 2025
c640115
build fix
akiraonstarknet Aug 29, 2025
1ed53e6
standardise tooltips, switch to canAsk wallet connection
akiraonstarknet Aug 29, 2025
11e46e9
switch to neverAsk
akiraonstarknet Aug 29, 2025
c9c0268
add auto-connect retry
akiraonstarknet Aug 29, 2025
603d7d9
debug connectWallet
akiraonstarknet Aug 29, 2025
94d28d8
update starknetkit
akiraonstarknet Aug 29, 2025
fa9d1a4
add rewards apy
akiraonstarknet Aug 31, 2025
7eeeaa0
build fix
akiraonstarknet Aug 31, 2025
9facd28
fix vercel crons
akiraonstarknet Aug 31, 2025
e818ab5
fix rewards receiver
akiraonstarknet Aug 31, 2025
71e7cee
rm duplicate cron
akiraonstarknet Aug 31, 2025
db39fce
fix strategy page apy toolti[
akiraonstarknet Aug 31, 2025
b54e7b9
fix wallet connect issue, tx history, deciamals, etc
akiraonstarknet Sep 1, 2025
922e43e
Merge pull request #162 from akiraonstarknet/dev
akiraonstarknet Sep 1, 2025
f69d089
fix wallet[temp]
akiraonstarknet Sep 1, 2025
287212e
Merge branch 'dev' into prod
akiraonstarknet Sep 1, 2025
0bf4b5d
fix build
akiraonstarknet Sep 1, 2025
c0d1553
reset package/
akiraonstarknet Sep 1, 2025
76ff8f9
improve loading comp
akiraonstarknet Sep 1, 2025
a765393
upgrade to sn@8, @strkfarm/sdk@1.1.1
akiraonstarknet Sep 1, 2025
23cb2d9
build fixes
akiraonstarknet Sep 1, 2025
3d024ae
@strkfarm/sdk@1.1.3
akiraonstarknet Sep 1, 2025
a9cc13a
fix pending=>latest
akiraonstarknet Sep 1, 2025
6a5de05
fix u256max issue;
akiraonstarknet Sep 1, 2025
2a443f7
Merge remote-tracking branch 'upstream/dev' into dev
EjembiEmmanuel Sep 3, 2025
b7b3d0a
Merge remote-tracking branch 'akira/dev' into fix/tnc-signing
EjembiEmmanuel Sep 3, 2025
5667967
Remove scheduled cron job for API strategies in vercel.json
EjembiEmmanuel Sep 3, 2025
b0b663d
Enhance TnC signing process with error handling and logging
EjembiEmmanuel Sep 3, 2025
625b59d
Comment out console removal configuration in next.config.mjs
EjembiEmmanuel Sep 3, 2025
572830f
Enhance TnC signing feedback by replacing console logs with toast not…
EjembiEmmanuel Sep 3, 2025
e83af16
Refactor Navbar connector initialization for improved readability and…
EjembiEmmanuel Sep 3, 2025
f0c59a2
Refactor TnCModal component to simplify address validation logic duri…
EjembiEmmanuel Sep 3, 2025
e78344d
Update next.config.mjs to enable console removal for production, and …
EjembiEmmanuel Sep 3, 2025
3b8a858
Fix typo in TnC signing error message and improve error handling in T…
EjembiEmmanuel Sep 3, 2025
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
3 changes: 2 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
yarn run lint:fix && yarn run format:fix && git add .
STAGED_FILES=$(git diff --cached --name-only)
yarn run lint:fix && yarn run format:fix && git add $STAGED_FILES
5 changes: 5 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ const nextConfig = {
},
webpack(config, options) {
if (options.isServer) config.devtool = 'source-map';
config.module.rules.push({
test: /\.svg$/,
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack'],
});
return config;
},
async headers() {
Expand Down
17 changes: 10 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
"@emotion/styled": "11.11.0",
"@next/third-parties": "14.1.3",
"@nikolovlazar/chakra-ui-prose": "1.2.1",
"@noble/curves": "^2.0.0",
"@prisma/client": "5.18.0",
"@starknet-react/chains": "3.0.0",
"@starknet-react/core": "3.0.1",
"@strkfarm/sdk": "^1.0.51",
"@starknet-react/chains": "^5.0.1",
"@starknet-react/core": "^5.0.1",
"@strkfarm/sdk": "1.1.3",
"@tanstack/query-core": "5.28.0",
"@types/mixpanel-browser": "2.49.0",
"@types/mustache": "4.2.5",
Expand All @@ -51,8 +52,8 @@
"combined-stream": "^1.0.8",
"ethers": "6.11.1",
"framer-motion": "11.0.5",
"get-starknet": "3.3.3",
"get-starknet-core": "3.3.3",
"get-starknet": "^3.3.3",
"get-starknet-core": "^3.3.5",
"graphql": "16.9.0",
"jotai": "2.6.4",
"jotai-tanstack-query": "0.8.5",
Expand All @@ -72,13 +73,15 @@
"react-responsive-carousel": "3.2.23",
"react-select": "5.8.0",
"react-share": "5.1.0",
"recharts": "^3.1.0",
"sharp": "0.33.4",
"starknet": "6.11.0",
"starknetkit": "2.4.0",
"starknet": "8.5.2",
"starknetkit": "^3.0.3",
"swr": "2.2.5",
"wonka": "6.3.4"
},
"devDependencies": {
"@svgr/webpack": "^8.1.0",
"@types/lodash.debounce": "^4.0.9",
"@types/node": "20",
"@types/react": "18",
Expand Down
201 changes: 201 additions & 0 deletions public/banners/troves_starktember.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
213 changes: 213 additions & 0 deletions public/banners/troves_starktember_mobile.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/fallback-profile-icon.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/fulllogo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 71 additions & 30 deletions src/app/api/lib.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TrovesStrategyAPIResult } from '@/store/troves.atoms';
import { UniversalStrategies } from '@strkfarm/sdk';
import { Redis } from '@upstash/redis';
import { Contract, RpcProvider, uint256 } from 'starknet';
import { Contract, RpcProvider } from 'starknet';

const kvRedis = new Redis({
url: process.env.VK_REDIS_KV_REST_API_URL,
Expand Down Expand Up @@ -47,19 +48,53 @@ export const getRewardsInfo = async (
strategies: Pick<TrovesStrategyAPIResult, 'id' | 'tvlUsd' | 'contract'>[],
) => {
const funder =
'0x02D6cf6182259ee62A001EfC67e62C1fbc0dF109D2AA4163EB70D6d1074F0173';
const allowedStrats = [
'0x0291816c46b4fb9db4d544bac7feb651ab1ae2de3b52e133c0ad23a87dd7c17d';

const tokenWiseConfig = [
{
id: 'vesu_fusion_eth',
// ! consider exchange rate of vToken
maxRewardsPerDay: 0.047, // in token units
maxAPY: 200, // in percent
underlyingTokenName: 'ETH',
decimals: 18,
rewardToken:
'0x021fe2ca1b7e731e4a5ef7df2881356070c5d72db4b2d19f9195f6b641f75df0',
token: 'ETH',
maxAPY: 100, // in %
maxRewardsPerDay: 0.538755 / 15, // tokem amount / days
},
{
token: 'WBTC',
maxAPY: 100, // in %
maxRewardsPerDay: 0.02191182 / 15, // tokem amount / days
},
{
token: 'USDC',
maxAPY: 100, // in %
maxRewardsPerDay: 2306 / 15, // tokem amount / days
},
{
token: 'USDT',
maxAPY: 75, // in %
maxRewardsPerDay: 1349 / 15, // tokem amount / days
},
{
token: 'STRK',
maxAPY: 75, // in %
maxRewardsPerDay: 10500 / 15, // tokem amount / days
},
];
const allowedStrats = UniversalStrategies.map((u) => {
const tokenWiseInfo = tokenWiseConfig.find(
(t) => t.token === u.depositTokens[0].symbol,
);
if (!tokenWiseInfo) {
throw new Error(`No token config found for ${u.depositTokens[0].symbol}`);
}
return {
id: `evergreen_${u.depositTokens[0].symbol.toLowerCase()}`,
// ! consider exchange rate of vToken
maxRewardsPerDay: tokenWiseInfo.maxRewardsPerDay || 0,
maxAPY: tokenWiseInfo.maxAPY || 0,
underlyingTokenName: u.depositTokens[0].symbol,
decimals: u.depositTokens[0].decimals,
rewardToken: u.depositTokens[0].address.address,
rewardReceiver: u.additionalInfo.vaultAllocator.address,
};
});

const provider = new RpcProvider({
nodeUrl: process.env.RPC_URL!,
Expand Down Expand Up @@ -88,23 +123,25 @@ export const getRewardsInfo = async (
);
const priceData = await priceResponse.json();
// consider token price of vToken
const clsVToken = await provider.getClassAt(stratAllowed.rewardToken);
const tokenContractVToken = new Contract(
clsVToken.abi,
stratAllowed.rewardToken,
provider,
);
const shareValue = await tokenContractVToken.call('convert_to_assets', [
uint256.bnToUint256((1e18).toString()),
]);
console.log(`shareValue::${stratId}::${shareValue}`);
const tokenPrice =
(priceData.price *
Number(
(BigInt(shareValue.toString()) * BigInt(10000)) /
BigInt((1e18).toString()),
)) /
10000;
// const clsVToken = await provider.getClassAt(stratAllowed.rewardToken);

// useful math when reward token is a ERC4626 token
// const tokenContractVToken = new Contract(
// clsVToken.abi,
// stratAllowed.rewardToken,
// provider,
// );
// const shareValue = await tokenContractVToken.call('convert_to_assets', [
// uint256.bnToUint256((1e18).toString()),
// ]);
// console.log(`shareValue::${stratId}::${shareValue}`);
const tokenPrice = priceData.price;
// (priceData.price *
// Number(
// (BigInt(shareValue.toString()) * BigInt(10000)) /
// BigInt((1e18).toString()),
// )) /
// 10000;
console.log(
`RewardCalc::${stratId}::tokenPrice::${tokenPrice}, underlyingTokenPrice::${priceData.price}`,
);
Expand All @@ -130,7 +167,11 @@ export const getRewardsInfo = async (
// if less bal available, use the available balance
const rewardToken = stratAllowed.rewardToken;
const cls = await provider.getClassAt(rewardToken);
const tokenContract = new Contract(cls.abi, rewardToken, provider);
const tokenContract = new Contract({
abi: cls.abi,
address: rewardToken,
providerOrAccount: provider,
});
const available = await tokenContract.balanceOf(funder);
const availableBal =
Number(
Expand All @@ -154,7 +195,7 @@ export const getRewardsInfo = async (
maxRewardsPerDay: stratAllowed.maxRewardsPerDay,
rewardToken: stratAllowed.rewardToken,
funder,
receiver: strat.contract[0].address,
receiver: stratAllowed.rewardReceiver,
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/api/price/[name]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ async function initRedis() {
try {
console.log('initRedis server');
// eslint-disable-next-line
const config = getMainnetConfig();
const config = getMainnetConfig(process.env.RPC_URL!, 'latest');
const pricer = new PricerRedis(config, []);
if (!process.env.REDIS_URL) {
console.warn('REDIS_URL not set');
Expand Down
39 changes: 39 additions & 0 deletions src/app/api/strategies/apyHistory/[strategyId]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { NextRequest } from 'next/server';
import { getStrategies } from '@/store/strategies.atoms';

export async function GET(req: NextRequest, context: any) {
const { params } = context;
const { searchParams } = new URL(req.url);
const strategyId = params.strategyId;

const duration = parseInt(searchParams.get('duration') || '7', 10);

const strategies = getStrategies();
const strategy = strategies.find((s) => s.id === strategyId);

if (!strategy) {
return new Response(JSON.stringify({ error: 'Strategy not found' }), {
status: 404,
headers: { 'Content-Type': 'application/json' },
});
}

const result = await fetch(`https://app.endur.fi/api/blocks/${duration}`);
const response = await result.json();

const blockInfo = response.blocks.map(
(block: { block: number; timestamp: number }) => {
return { block: block.block, timestamp: block.timestamp };
},
);

const apyHistory = {
strategy: strategy.name,
history: await strategy.getAPYHistory(blockInfo),
};

return new Response(JSON.stringify({ apyHistory }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}
5 changes: 4 additions & 1 deletion src/app/api/strategies/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { MY_STORE } from '@/store';
import VesuAtoms, { vesu } from '@/store/vesu.store';
import EndurAtoms, { endur } from '@/store/endur.store';
import { setDataToRedis, getDataFromRedis, getRewardsInfo } from '../lib';
import { DEFAULT_APY_METHODLOGY } from '@/constants';

export const revalidate = 1800; // 30 minutes
export const dynamic = 'force-dynamic';
Expand Down Expand Up @@ -59,14 +60,16 @@ async function getStrategyInfo(
): Promise<TrovesStrategyAPIResult> {
const tvl = await strategy.getTVL();

const data = {
const defaultAPYMethodology = DEFAULT_APY_METHODLOGY;
const data: TrovesStrategyAPIResult = {
name: strategy.name,
id: strategy.id,
apy: strategy.netYield,
apySplit: {
baseApy: strategy.netYield,
rewardsApy: 0,
},
apyMethodology: strategy.metadata.apyMethodology || defaultAPYMethodology,
depositToken: (
await strategy.depositMethods({
amount: MyNumber.fromZero(),
Expand Down
13 changes: 11 additions & 2 deletions src/app/api/tnc/signUser/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ const mixpanel = Mixpanel.init('118f29da6a372f0ccb6f541079cad56b');
export async function POST(req: Request) {
const { address, signature } = await req.json();

if (process.env.NEXT_PUBLIC_IGNORE_SIGNING === 'true') {
console.warn('Signing is ignored in this environment');
return NextResponse.json({
success: true,
message: 'Signing is ignored in this environment',
user: null,
});
}

console.debug('address', address, 'signature', signature);
if (!address || !signature) {
return NextResponse.json({
Expand Down Expand Up @@ -43,7 +52,7 @@ export async function POST(req: Request) {
nodeUrl: process.env.NEXT_PUBLIC_RPC_URL!,
});

const myAccount = new Account(provider, address, '');
const myAccount = new Account({ provider, address, signer: '' });

let isValid = false;

Expand Down Expand Up @@ -94,7 +103,7 @@ export async function POST(req: Request) {

if (!isValid) {
try {
const cls = await provider.getClassAt(address, 'pending');
const cls = await provider.getClassAt(address, 'latest');
// means account is deployed
return NextResponse.json({
success: false,
Expand Down
12 changes: 6 additions & 6 deletions src/app/community/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@ const CommunityPage = () => {
isOGNFTEligible.isError,
]);

const ogNFTContract = new Contract(
NFTAbi,
process.env.NEXT_PUBLIC_OG_NFT_CONTRACT || '',
provider,
);
const ogNFTContract = new Contract({
abi: NFTAbi,
address: process.env.NEXT_PUBLIC_OG_NFT_CONTRACT || '',
providerOrAccount: provider,
});

const {
sendAsync: claimOGNFT,
Expand All @@ -106,7 +106,7 @@ const CommunityPage = () => {
const ogNFTAddr: `0x${string}` = (process.env.NEXT_PUBLIC_OG_NFT_CONTRACT ||
'0x0') as `0x${string}`;
const { data: ogNFTBalance, status: balanceQueryStatus } = useReadContract({
abi: NFTAbi,
abi: NFTAbi as any,
address: ogNFTAddr,
functionName: 'balanceOf',
args: [address || '0x0', 1],
Expand Down
51 changes: 51 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,57 @@ body {
);
}

.strategy-page-gradient {
background: linear-gradient(
0deg,
rgba(33, 33, 33, 0.35),
rgba(33, 33, 33, 0.35)
),
linear-gradient(
288.17deg,
rgba(144, 105, 240, 0.2) -123.96%,
rgba(33, 33, 33, 0.2) 101.38%
);
}

.apy-gradient {
background: linear-gradient(
0deg,
rgba(33, 33, 33, 0.35),
rgba(33, 33, 33, 0.35)
),
linear-gradient(
326.73deg,
rgba(144, 105, 240, 0.5) -541.23%,
rgba(33, 33, 33, 0.4) 92.85%
);
}

.holdings-gradient {
background: linear-gradient(
0deg,
rgba(33, 33, 33, 0.35),
rgba(33, 33, 33, 0.35)
),
linear-gradient(
326.73deg,
rgba(144, 105, 240, 0.5) -541.23%,
rgba(33, 33, 33, 0.4) 92.85%
);
}

.faded-purple-gradient {
background: linear-gradient(
0deg,
rgba(33, 33, 33, 0.35),
rgba(33, 33, 33, 0.35)
),
linear-gradient(
326.73deg,
rgba(144, 105, 240, 0.5) -541.23%,
rgba(33, 33, 33, 0.4) 92.85%
);
}
.connect-button-gradient {
background: linear-gradient(93.94deg, #9069f0 3.22%, #4a14cd 101.67%);
}
Expand Down
Loading
Loading