Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Trade count #1584

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
6dec33d
setup trending query
GrandSchtroumpf Nov 7, 2024
debdf37
get missing token
GrandSchtroumpf Nov 7, 2024
09e0c6f
add loading state
GrandSchtroumpf Nov 18, 2024
0a49900
Merge remote-tracking branch 'origin/main' into issue-#1377
GrandSchtroumpf Nov 19, 2024
c240047
add animated figures
GrandSchtroumpf Nov 20, 2024
df30cc8
reorganize sort
GrandSchtroumpf Nov 20, 2024
a93c8f1
display only for Celo & Sei
GrandSchtroumpf Nov 20, 2024
bee6dd5
[CI] Update Screenshots
GrandSchtroumpf Nov 20, 2024
96fdb2f
update font size
GrandSchtroumpf Nov 20, 2024
7f0a05a
use 30sec animation
GrandSchtroumpf Nov 20, 2024
569ec60
[CI] Update Screenshots
GrandSchtroumpf Nov 20, 2024
48cef82
2min animation duration
GrandSchtroumpf Nov 20, 2024
15329d8
[CI] Update Screenshots
GrandSchtroumpf Nov 20, 2024
99a0433
custom easing curve
GrandSchtroumpf Nov 21, 2024
6c0f69e
increase deceleration
GrandSchtroumpf Nov 21, 2024
1eaaed9
[CI] Update Screenshots
GrandSchtroumpf Nov 21, 2024
97a2977
change params
GrandSchtroumpf Nov 21, 2024
5347d53
[CI] Update Screenshots
GrandSchtroumpf Nov 21, 2024
c34ce63
apply requested changed
GrandSchtroumpf Nov 22, 2024
f499b67
[CI] Update Screenshots
GrandSchtroumpf Nov 22, 2024
f1cd2ee
smaller font
GrandSchtroumpf Nov 22, 2024
dcf53c9
[CI] Update Screenshots
GrandSchtroumpf Nov 22, 2024
1c9b0f6
add spacing
GrandSchtroumpf Nov 22, 2024
63da385
[CI] Update Screenshots
GrandSchtroumpf Nov 22, 2024
17be271
update animation pattern
GrandSchtroumpf Nov 25, 2024
d6993ca
[CI] Update Screenshots
GrandSchtroumpf Nov 25, 2024
7fcd38a
split animations
GrandSchtroumpf Nov 25, 2024
27c7443
[CI] Update Screenshots
GrandSchtroumpf Nov 25, 2024
d31d3d7
calculate total trade
GrandSchtroumpf Nov 26, 2024
8d4f1a9
[CI] Update Screenshots
GrandSchtroumpf Nov 26, 2024
a9b73c0
update initial animation
GrandSchtroumpf Nov 26, 2024
4e4dcbb
[CI] Update Screenshots
GrandSchtroumpf Nov 26, 2024
deca9d1
increase duration for update
GrandSchtroumpf Nov 26, 2024
8f0aa2a
[CI] Update Screenshots
GrandSchtroumpf Nov 26, 2024
4c6dc0b
update every 2min
GrandSchtroumpf Nov 26, 2024
7e28edb
[CI] Update Screenshots
GrandSchtroumpf Nov 26, 2024
f8a81d7
change animation
GrandSchtroumpf Nov 26, 2024
0d7b596
[CI] Update Screenshots
GrandSchtroumpf Nov 26, 2024
42d2c0d
fix font & overlapping animations
GrandSchtroumpf Nov 27, 2024
e35bcf7
[CI] Update Screenshots
GrandSchtroumpf Nov 27, 2024
8c1086f
improve loading
GrandSchtroumpf Nov 27, 2024
3976f69
[CI] Update Screenshots
GrandSchtroumpf Nov 27, 2024
35bd08f
add links
GrandSchtroumpf Nov 27, 2024
2475ffe
[CI] Update Screenshots
GrandSchtroumpf Nov 27, 2024
5717ccd
requested changes
GrandSchtroumpf Dec 3, 2024
6213d28
[CI] Update Screenshots
GrandSchtroumpf Dec 4, 2024
d0a683b
request changes
GrandSchtroumpf Dec 10, 2024
c49659d
[CI] Update Screenshots
GrandSchtroumpf Dec 10, 2024
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ The file `common.ts` with type [`AppConfig`](src/config/types.ts) contains impor
- `ui`
- `priceChart`: use `tradingView` chart or `native` chart for token pair price history. You need to provide a backend with price history endpoint to support `native` view.
- `useGradientBranding`: Flag to enable gradient styles for buttons.
- `tradeCount`: Display the amount of trades in the explorer page.

#### Gas token different than native token

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion src/components/debug/DebugTransferNFT.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export const DebugTransferNFT = () => {
inputId
);
await tx.wait();
await cache.invalidateQueries({ queryKey: QueryKey.strategies(user) });
await cache.invalidateQueries({
queryKey: QueryKey.strategiesByUser(user),
});
setIsSuccess(true);
} catch (e) {
console.error('failed to transfer NFT', e);
Expand Down
333 changes: 333 additions & 0 deletions src/components/explorer/ExplorerHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
import { buttonStyles } from 'components/common/button/buttonStyles';
import { TokensOverlap } from 'components/common/tokensOverlap';
import { useTokens } from 'hooks/useTokens';
import { Strategy, useGetStrategyList } from 'libs/queries';
import {
PairTrade,
Trending,
useTrending,
} from 'libs/queries/extApi/tradeCount';
import { Link } from 'libs/routing';
import { CSSProperties, useEffect, useRef } from 'react';
import { toPairSlug } from 'utils/pairSearch';

const useTrendingPairs = (trending?: Trending) => {
const { tokensMap } = useTokens();
if (!trending) return { isLoading: true, data: [] };
const pairs: Record<string, PairTrade> = {};
for (const trade of trending?.pairCount ?? []) {
pairs[trade.pairAddresses] ||= trade;
}
const list = Object.values(pairs)
.filter((pair) => !!pair.pairTrades_24h)
.sort((a, b) => b.pairTrades - a.pairTrades)
.splice(0, 3);

// If there are less than 3, pick the remaining best
if (list.length < 3) {
const remaining = Object.values(pairs)
.filter((pair) => !!pair.pairTrades_24h)
.sort((a, b) => b.pairTrades - a.pairTrades)
.splice(0, 3 - list.length);
list.push(...remaining);
}

// Sort again in case we had to add more
const data = list
.sort((a, b) => b.pairTrades - a.pairTrades)
.map((pair) => ({
pairAddress: pair.pairAddresses,
base: tokensMap.get(pair.token0.toLowerCase())!,
quote: tokensMap.get(pair.token1.toLowerCase())!,
trades: pair.pairTrades,
}));
return { isLoading: false, data };
};

interface StrategyWithTradeCount extends Strategy {
trades: number;
}
const useTrendStrategies = (
trending?: Trending
): { isLoading: boolean; data: StrategyWithTradeCount[] } => {
const trades = trending?.tradeCount ?? [];
const list = trades
.filter((t) => !!t.strategyTrades_24h)
.sort((a, b) => b.strategyTrades - a.strategyTrades)
.splice(0, 3);

// If there are less than 3, pick the remaining best
if (list.length < 3) {
const remaining = trades
.filter((t) => !!t.strategyTrades_24h)
.sort((a, b) => b.strategyTrades - a.strategyTrades)
.splice(0, 3 - list.length);
list.push(...remaining);
}
GrandSchtroumpf marked this conversation as resolved.
Show resolved Hide resolved

const record: Record<string, number> = {};
for (const item of list) {
record[item.id] = item.strategyTrades;
}
const ids = list.map((s) => s.id);
const query = useGetStrategyList(ids);
if (query.isLoading) return { isLoading: true, data: [] };

const data = (query.data ?? []).map((strategy) => ({
...strategy,
trades: record[strategy.id],
}));
return { isLoading: false, data };
};

export const ExplorerHeader = () => {
const { data: trending, isLoading, isError } = useTrending();
const trendingStrategies = useTrendStrategies(trending);
const trendingPairs = useTrendingPairs(trending);
const strategies = trendingStrategies.data;
const pairs = trendingPairs.data;

const strategiesLoading = trendingStrategies.isLoading || isLoading;
const pairLoading = trendingPairs.isLoading || isLoading;
if (isError) return;
return (
<header className="mb-42 flex gap-32">
<article className="flex w-full flex-col items-center justify-around gap-16 py-20 md:w-[40%] md:items-start">
<h2 className="text-24 font-weight-400 font-title my-0">
Total Trades
</h2>
<Trades trades={trending?.totalTradeCount} />
<div className="flex gap-16">
<Link
to="/trade/disposable"
className={buttonStyles({ variant: 'success' })}
>
Create Strategy
</Link>
<Link
to="/trade/market"
className={buttonStyles({ variant: 'white' })}
>
Trade
</Link>
</div>
</article>
<article className="border-background-800 grid hidden flex-1 gap-8 rounded border-2 p-20 md:block">
<h2 className="text-20 font-weight-400 font-title">Popular Pairs</h2>
<table className="font-weight-500 text-14 w-full">
<thead className="text-16 text-white/60">
<tr>
<th className="font-weight-400 text-start">Token Pair</th>
<th className="font-weight-400 text-end">Trades</th>
</tr>
</thead>
<tbody className="font-weight-500">
{pairLoading &&
[1, 2, 3].map((id) => (
<tr key={id}>
<td>
<Loading height={34} />
</td>
<td>
<Loading height={34} />
</td>
</tr>
))}
{pairs.map(({ pairAddress, base, quote, trades }) => (
<tr key={pairAddress}>
<td>
<Link
to="/explore/$type/$slug"
params={{
type: 'token-pair',
slug: toPairSlug(base, quote),
}}
className="block w-full"
>
<div className="inline-flex items-center gap-8">
<TokensOverlap tokens={[base, quote]} size={18} />
<span>{base?.symbol}</span>
<span className="text-white/60">/</span>
<span>{quote?.symbol}</span>
</div>
</Link>
</td>
<td className="py-8 text-end">
<Link
to="/explore/$type/$slug"
params={{
type: 'token-pair',
slug: toPairSlug(base, quote),
}}
className="block w-full"
>
{formatter.format(trades)}
</Link>
</td>
</tr>
))}
</tbody>
</table>
</article>
<article className="border-background-800 grid hidden flex-1 gap-8 rounded border-2 p-20 lg:block">
<h2 className="text-20 font-weight-400 font-title">
Trending Strategies
</h2>
<table className="text-14 w-full">
<thead className="text-16 text-white/60">
<tr>
<th className="font-weight-400 text-start">ID</th>
<th className="font-weight-400 text-end">Trades</th>
</tr>
</thead>
<tbody className="font-weight-500">
{strategiesLoading &&
[1, 2, 3].map((id) => (
<tr key={id}>
<td>
<Loading height={34} />
</td>
<td>
<Loading height={34} />
</td>
</tr>
))}
{strategies.map(({ id, idDisplay, base, quote, trades }) => (
<tr key={id}>
<td>
<Link
to="/strategy/$id"
params={{ id }}
className="block w-full"
>
<div className="bg-background-700 flex gap-8 rounded px-8">
<TokensOverlap tokens={[base, quote]} size={18} />
{idDisplay}
</div>
</Link>
</td>
<td className="w-full py-8 text-end">
<Link
to="/strategy/$id"
params={{ id }}
className="block w-full"
>
{formatter.format(trades)}
</Link>
</td>
</tr>
))}
</tbody>
</table>
</article>
</header>
);
};

const Loading = (style: CSSProperties) => (
<div className="animate-pulse p-4" style={style}>
<div className="bg-background-700 h-full rounded"></div>
</div>
);

const formatter = new Intl.NumberFormat(undefined, {
maximumFractionDigits: 0,
});

interface TradesProps {
trades?: number;
}

const Trades = ({ trades }: TradesProps) => {
const ref = useRef<HTMLParagraphElement>(null);
const anims = useRef<Promise<Animation>[]>();
const lastTrades = useRef(0);
const initDelta = 60;

useEffect(() => {
if (typeof trades !== 'number') return;
let tradesChanged = false;
const start = async () => {
const from = lastTrades.current || trades - initDelta;
const to = trades;
const letters = ref.current!.children;
// Initial animation
if (!lastTrades.current) {
const initAnims: Promise<Animation>[] = [];
const next = formatter.format(from).split('');
for (let i = 0; i < next.length; i++) {
const v = next[i];
if (!'0123456789'.includes(v)) continue;
const anim = letters[i]?.animate(
[{ transform: `translateY(-${v}0%)` }],
{
duration: 1000,
delay: i * 100,
fill: 'forwards',
easing: 'cubic-bezier(1,-0.54,.65,1.46)',
}
);
if (anim) initAnims.push(anim.finished);
}
await Promise.allSettled(initAnims);
}
// Wait for lingering animations if any
await Promise.allSettled(anims.current ?? []);
anims.current = [];
let previous = formatter.format(from - 1).split('');
for (let value = from; value <= to; value++) {
const next = formatter.format(value).split('');
for (let i = 0; i < next.length; i++) {
if (tradesChanged) return;
const v = next[i];
if (!'0123456789'.includes(v)) continue;
if (previous[i] === next[i]) continue;
const anim = letters[i].animate(
[{ transform: `translateY(-${v}0%)` }],
{
duration: 1000,
delay: 2000,
fill: 'forwards',
easing: 'cubic-bezier(1,.11,.55,.79)',
}
);
anims.current.push(anim.finished);
}
previous = next;
await Promise.allSettled(anims.current ?? []);
lastTrades.current = value;
}
};
start();
return () => {
tradesChanged = true;
};
}, [trades]);

if (typeof trades !== 'number') {
return <Loading height={40} width="10ch" fontSize="36px" />;
}

const initial = trades ? formatter.format(trades - initDelta) : '0';
return (
<p ref={ref} className="text-36 font-title flex h-[40px] overflow-hidden">
{initial.split('').map((v, i) => {
if (!'0123456789'.includes(v)) return <span key={i}>{v}</span>;
return (
<span key={i} className="grid h-max text-center">
<span>0</span>
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
</span>
);
})}
</p>
);
};
3 changes: 2 additions & 1 deletion src/components/strategies/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Token } from 'libs/tokens';
import { formatNumber } from 'utils/helpers';
import { BaseOrder } from './types';
import { endOfDay, getUnixTime, startOfDay, subDays } from 'date-fns';
import { StrategyType } from 'libs/routing';

type StrategyOrderInput =
| { min: string; max: string }
Expand Down Expand Up @@ -35,7 +36,7 @@ export const isDisposableStrategy = (strategy: Strategy) => {
return false;
};

export const getStrategyType = (strategy: Strategy) => {
export const getStrategyType = (strategy: Strategy): StrategyType => {
if (isOverlappingStrategy(strategy)) return 'overlapping';
if (isDisposableStrategy(strategy)) return 'disposable';
return 'recurring';
Expand Down
2 changes: 1 addition & 1 deletion src/components/strategies/edit/EditStrategyForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export const EditStrategyForm: FC<Props> = (props) => {
console.log('tx hash', tx.hash);
await tx.wait();
cache.invalidateQueries({
queryKey: QueryKey.strategies(user),
queryKey: QueryKey.strategiesByUser(user),
});
carbonEvents.strategyEdit.strategyEditPrices({
...strategyEventData,
Expand Down
2 changes: 1 addition & 1 deletion src/components/strategies/useDeleteStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const useDeleteStrategy = () => {
await tx.wait();

void cache.invalidateQueries({
queryKey: QueryKey.strategies(user),
queryKey: QueryKey.strategiesByUser(user),
});
console.log('tx confirmed');
successEventsCb?.();
Expand Down
2 changes: 1 addition & 1 deletion src/components/strategies/usePauseStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const usePauseStrategy = () => {
await tx.wait();

void cache.invalidateQueries({
queryKey: QueryKey.strategies(user),
queryKey: QueryKey.strategiesByUser(user),
});
console.log('tx confirmed');
successEventsCb?.();
Expand Down
Loading