Skip to content

Commit 793eb63

Browse files
committed
feat: connect uniswap v2 mainnet theGraph
1 parent 4b4dbc4 commit 793eb63

File tree

9 files changed

+329
-32
lines changed

9 files changed

+329
-32
lines changed

src/app/swap/page.tsx

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ import { shallow } from 'zustand/shallow';
2626

2727
export default function Home() {
2828
const { address, status, isConnected } = useAccount();
29+
const {
30+
inputAsset,
31+
outputAsset,
32+
} = useSwapStore(
33+
state => ({
34+
inputAsset: state.inputAsset,
35+
outputAsset: state.outputAsset,
36+
}),
37+
shallow
38+
);
2939

3040
const {
3141
initAssets,
@@ -96,15 +106,15 @@ export default function Home() {
96106
justifyContent={'space-evenly'}>
97107
<SwampAvatar
98108
boxSize={24}
99-
name = {"ETH"}
100-
src = {""}
101-
// name={token?.name}
102-
// src={token?.logoURI!}
103-
// ml={1}
109+
// name = {"ETH"}
110+
// src = {""}
111+
name={inputAsset?.name ?? "ETH"}
112+
src={inputAsset?.logoURI!}
113+
ml={1}
104114
/>
105115
<Text ml={1} mr={1} fontSize={'0.875rem'}>
106-
ETH
107-
{/* {token?.symbol} */}
116+
{/* ETH */}
117+
{inputAsset?.symbol ?? "ETH"}
108118
</Text>
109119
</Button>
110120
</TokenSelector>
@@ -128,15 +138,12 @@ export default function Home() {
128138
justifyContent={'space-evenly'}>
129139
<SwampAvatar
130140
boxSize={24}
131-
name = {"ETH"}
132-
src = {""}
133-
// name={token?.name}
134-
// src={token?.logoURI!}
135-
// ml={1}
141+
name={outputAsset?.name ?? "ETH"}
142+
src={outputAsset?.logoURI!}
143+
ml={1}
136144
/>
137145
<Text ml={1} mr={1} fontSize={'0.875rem'} fontFamily={'Proto'}>
138-
Select Token
139-
{/* {token?.symbol} */}
146+
{outputAsset?.symbol ?? "Select Token"}
140147
</Text>
141148
</Button>
142149
</TokenSelector>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import {
2+
CheckIcon,
3+
ExternalLinkIcon,
4+
InfoIcon,
5+
WarningIcon,
6+
WarningTwoIcon,
7+
} from '@chakra-ui/icons';
8+
import {
9+
Box,
10+
CloseButton,
11+
HStack,
12+
Icon,
13+
Link,
14+
Spinner,
15+
Text,
16+
createStandaloneToast,
17+
} from '@chakra-ui/react';
18+
19+
type statusToast =
20+
| 'info'
21+
| 'warning'
22+
| 'success'
23+
| 'error'
24+
| 'loading'
25+
| undefined;
26+
27+
const generateToast = (
28+
title: string,
29+
description: string,
30+
status: statusToast,
31+
txHash?: string
32+
) => {
33+
const { toast } = createStandaloneToast();
34+
const color =
35+
status === 'info'
36+
? 'pink'
37+
: status === 'loading'
38+
? 'yellow'
39+
: status === 'success'
40+
? 'green'
41+
: 'red';
42+
43+
const id = Math.random().toString(36).substring(2, 9);
44+
return toast({
45+
isClosable: true,
46+
position: 'bottom-left',
47+
duration: 10000,
48+
id,
49+
render: () => {
50+
const onClose = () => toast.close(id);
51+
const icon =
52+
status === 'info'
53+
? InfoIcon
54+
: status === 'success'
55+
? CheckIcon
56+
: status === 'warning'
57+
? WarningTwoIcon
58+
: WarningIcon;
59+
return (
60+
<Box
61+
mt={{ base: 0, md: -10 }}
62+
ml={{ base: 0, md: 10 }}
63+
mb={{ base: 0, md: 10 }}
64+
bg={'darkblue.500'}
65+
border={'1px solid'}
66+
borderColor={`${color}.500`}
67+
borderRadius={'2xl'}
68+
p={4}
69+
width={{ base: '75vw', md: '25vw' }}
70+
maxH={'20vh'}
71+
color={'whiteAlpha.900'}>
72+
<CloseButton
73+
float={'right'}
74+
position={'relative'}
75+
top={-3}
76+
right={-3}
77+
zIndex={10}
78+
onClick={onClose}
79+
/>
80+
<HStack>
81+
{status === 'loading' ? (
82+
<Spinner size={'sm'} color={`${color}.500`} />
83+
) : (
84+
<Icon as={icon} color={`${color}.500`} />
85+
)}
86+
87+
<Text fontSize={'md'}>{title}</Text>
88+
</HStack>
89+
<Box
90+
maxH={'8vh'}
91+
scrollBehavior={'smooth'}
92+
overflowY={'scroll'}
93+
sx={{
94+
'::-webkit-scrollbar': {
95+
display: 'none',
96+
},
97+
}}>
98+
<Text mt={2} fontSize={'sm'}>
99+
{description}
100+
</Text>
101+
{txHash && (
102+
<Link
103+
href={`${process.env.NEXT_PUBLIC_EXPLORER}/tx/${txHash}`}
104+
isExternal
105+
display={'inline-flex'}
106+
mt={2}
107+
color={`${color}.500`}>
108+
<ExternalLinkIcon mr={2} />
109+
<Text fontSize={'sm'}>View transaction in explorer</Text>
110+
</Link>
111+
)}
112+
</Box>
113+
</Box>
114+
);
115+
},
116+
});
117+
};
118+
export default generateToast;

src/components/uis/TokenEntry.tsx

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import EquilibreAvatar from '@/components/core/SwampAvatar';
2+
import generateToast from '@/components/toast/generateToast';
3+
import { Token } from '@/interfaces';
4+
import { useSwapStore } from '@/store/swap/swapStore';
5+
import { AddIcon } from '@chakra-ui/icons';
6+
import { Stack, Text } from '@chakra-ui/react';
7+
import { useWalletClient } from 'wagmi';
8+
9+
type TokenEntryProps = {
10+
token: Token;
11+
type: 'input' | 'output';
12+
onClose: () => void;
13+
};
14+
15+
const TokenEntry = ({ token, type, onClose }: TokenEntryProps) => {
16+
const {
17+
actions: { setAsset },
18+
} = useSwapStore(state => state);
19+
const handleOnClick = (): void => {
20+
setAsset(token.address, type);
21+
onClose();
22+
};
23+
const client = useWalletClient();
24+
const handleOnClickAddAsset = (): void => {
25+
if (!client.isSuccess) return;
26+
client.data
27+
?.watchAsset({
28+
options: {
29+
address: token.address,
30+
symbol: token.symbol,
31+
decimals: Number(token.decimals),
32+
image: token.logoURI,
33+
},
34+
type: 'ERC20',
35+
})
36+
.then(() => {
37+
generateToast(
38+
'Asset added',
39+
`${token.symbol} has been added to your wallet`,
40+
'success'
41+
);
42+
})
43+
.catch(err => {
44+
if (err.message.includes('Rabby')) {
45+
generateToast(
46+
'Rabby functionality not available',
47+
err.message.split('\n')[2],
48+
'error'
49+
);
50+
return;
51+
} else {
52+
generateToast(
53+
'Asset already added',
54+
`${token.symbol} has already been added to your wallet`,
55+
'error'
56+
);
57+
}
58+
});
59+
};
60+
61+
return (
62+
<Stack direction={'row'} alignItems={'center'}>
63+
<AddIcon
64+
boxSize={3}
65+
transition={'transform 0.35s ease-out, background 0.15s ease-out'}
66+
_hover={{
67+
transform: 'scale(1.15, 1.15)',
68+
cursor: 'pointer',
69+
}}
70+
_active={{ transform: 'scale(1, 1)' }}
71+
onClick={handleOnClickAddAsset}
72+
/>
73+
<Stack
74+
direction={'row'}
75+
alignItems={'center'}
76+
w={'-webkit-fill-available'}
77+
justifyContent={'space-between'}
78+
transition={'transform 0.35s ease-out, background 0.15s ease-out'}
79+
_hover={{
80+
cursor: 'pointer',
81+
}}
82+
onClick={handleOnClick}>
83+
<Stack direction={'row'} alignItems={'center'}>
84+
<EquilibreAvatar size={'md'} name={token.name} src={token.logoURI} />
85+
<Stack spacing={'-0.5'}>
86+
<Text fontSize={'sm'}>{token.symbol}</Text>
87+
<Text fontFamily={'Arista'} fontSize={'sm'} color={'gray.500'}>
88+
{token.name}
89+
</Text>
90+
</Stack>
91+
</Stack>
92+
<Stack textAlign={'right'} spacing={'-0.5'}>
93+
<Text fontSize={'sm'}>{token.balance}</Text>
94+
95+
<Text fontSize={'sm'} fontFamily={'Arista'} color={'gray.500'}>
96+
Balance
97+
</Text>
98+
</Stack>
99+
</Stack>
100+
</Stack>
101+
);
102+
};
103+
104+
export default TokenEntry;

src/components/uis/TokenSelector.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
useDisclosure,
2323
} from '@chakra-ui/react';
2424
import React, { useEffect } from 'react';
25+
import TokenEntry from './TokenEntry';
2526

2627
type TokenSelectorProps = {
2728
children: any;
@@ -131,13 +132,13 @@ const TokenSelector = ({ children, type }: TokenSelectorProps) => {
131132
{(search && search != '' ? filteredTokens : tokenList)?.map(
132133
(token: Token, index) => {
133134
return (
134-
<div key = {index}>{token.name}</div>
135-
// <TokenEntry
136-
// key={index}
137-
// token={token}
138-
// type={type}
139-
// onClose={onClose}
140-
// />
135+
// <div key = {index}>{token.name}</div>
136+
<TokenEntry
137+
key={index}
138+
token={token}
139+
type={type}
140+
onClose={onClose}
141+
/>
141142
);
142143
}
143144
)}

src/config/apolloConfig/apollo.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
import { ApolloClient } from 'apollo-client'
3+
import { InMemoryCache } from 'apollo-cache-inmemory'
4+
import { HttpLink } from 'apollo-link-http'
5+
6+
export const client = new ApolloClient({
7+
link: new HttpLink({
8+
uri: process.env.NEXT_PUBLIC_UNISWAP_SUBGRAPH_URL ?? 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2',
9+
}),
10+
cache: new InMemoryCache(),
11+
})

src/config/apolloConfig/queries.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import gql from 'graphql-tag'
2+
3+
export const GET_PAIRS = gql`
4+
query {
5+
pairs {
6+
id
7+
token0 {
8+
symbol
9+
}
10+
token1 {
11+
symbol
12+
}
13+
reserve0
14+
reserve1
15+
}
16+
}
17+
`;
18+
19+
export const GET_TOKENS = gql`
20+
query {
21+
tokens {
22+
id
23+
symbol
24+
name
25+
decimals
26+
}
27+
}
28+
`;

src/store/baseAssetsStore.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import axios from 'axios';
55
import { create } from 'zustand';
66
import { devtools } from 'zustand/middleware';
77

8+
import { fetchTokenData } from '@/utils/fetchData';
9+
810
interface BaseAssetState {
911
baseAssets: Token[];
1012
isLoading: boolean;
@@ -24,11 +26,10 @@ export const useBaseAssetStore = create<BaseAssetState>()(
2426
initBaseAssets: async () => {
2527
console.log(process.env.NEXT_PUBLIC_UNISWAP_SUBGRAPH_URL);
2628
set({ isLoading: true });
27-
await axios
28-
.get(BASE_URL)
29-
.then(response => {
30-
console.log(response);
31-
let baseAssets = response.data.data;
29+
await fetchTokenData()
30+
.then(result => {
31+
let baseAssets = result?.data.tokens;
32+
console.log('Fetched tokens:', result);
3233
baseAssets = mapToken(baseAssets);
3334

3435
set({ baseAssets });

0 commit comments

Comments
 (0)