Skip to content

Commit

Permalink
Basin UI - Wells page (#496)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xalecks authored Jun 21, 2023
2 parents 3db5ac6 + 7afcf4c commit 3738e44
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 40 deletions.
2 changes: 1 addition & 1 deletion projects/dex-ui/src/components/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type Props = {
export const Checkbox: FC<Props> = ({ label, checked = false, mode, checkboxColor, onClick = () => {} }) => {
return (
<StyledCheckbox>
<HiddenCheckbox type="checkbox" role={"checkbox"} checked={checked} />
<HiddenCheckbox type="checkbox" role={"checkbox"} checked={checked} readOnly/>
<HoverContainer>
<StyledCheckboxContainer checked={checked} onClick={onClick} mode={mode} checkboxColor={checkboxColor}>
<HoverCheckmark checked={checked} checkboxColor={checkboxColor} />
Expand Down
12 changes: 9 additions & 3 deletions projects/dex-ui/src/components/PageComponents/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,31 @@ import { Link } from "react-router-dom";

type Props = {
title: string;
fontweight?: string;
parent?: {
title: string;
path: string;
};
};

export const Title: FC<Props> = ({ title, parent }) => (
export const Title: FC<Props> = ({ title, parent, fontweight }) => (
<Container>
{parent && <ParentText to={parent.path}>{parent.title} &gt;&nbsp;</ParentText>}
<TitleText>{title}</TitleText>
<TitleText fontweight={fontweight}>{title}</TitleText>
</Container>
);

type TitleProps = {
fontweight?: string;
}

const Container = styled.div`
display: flex;
flex-direction: row;
`;
const TitleText = styled.div`
const TitleText = styled.div<TitleProps>`
${BodyL}
${(props) => (props.fontweight && `font-weight: ${props.fontweight}`)};
text-transform: uppercase;
`;
const ParentText = styled(Link)`
Expand Down
15 changes: 9 additions & 6 deletions projects/dex-ui/src/components/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import styled from "styled-components";

export const Table = styled.table`
border: 0.5px solid #000;
border: 0.5px solid #9CA3AF;
border-collapse: collapse;
table-layout: fixed;
overflow: hidden;
width: 100%;
`;

export const Row = styled.tr`
background-color: #fff;
height: 120px;
border-bottom: 0.5px solid #000;
border-bottom: 0.5px solid #9CA3AF;
:hover {
cursor: pointer;
Expand All @@ -17,23 +20,23 @@ export const Row = styled.tr`
`;
export const Th = styled.th`
padding: 16px;
border-right: 0.5px solid #000;
color: #4b5563;
font-weight: 400;
font-size: 16px;
line-height: 17px;
line-height: 16px;
text-align: ${(props) => props.align || "left"};
text-transform: uppercase;
cursor: default;
`;
export const Td = styled.td`
padding: 16px;
border-right: 0.5px solid #000;
text-align: ${(props) => props.align || "left"};
`;
export const THead = styled.thead`
${Row} {
height: 48px;
background-color: #f9f9f9;
border-bottom: 0.5px solid #000;
border-bottom: 0.5px solid #9CA3AF;
}
`;
export const TBody = styled.tbody``;
199 changes: 170 additions & 29 deletions projects/dex-ui/src/pages/Wells.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,77 @@
import { Well } from "@beanstalk/sdk/Wells";
import React, { ReactNode } from "react";
import { TokenValue } from "@beanstalk/sdk";
import React, { ReactNode, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Item } from "src/components/Layout";
import { Page } from "src/components/Page";
import { Title } from "src/components/PageComponents/Title";
import { TabButton } from "src/components/TabButton";
import { Row, TBody, THead, Table, Td, Th } from "src/components/Table";
import { Row as TabRow } from "src/components/Layout";
import { TokenLogo } from "src/components/TokenLogo";
import { getPrice } from "src/utils/price/usePrice";
import useSdk from "src/utils/sdk/useSdk";
import { useWells } from "src/wells/useWells";
import styled from "styled-components";
import { useAccount } from "wagmi";

export const Wells = () => {
const { data: wells, isLoading, error } = useWells();
const navigate = useNavigate();
const sdk = useSdk();
const { address } = useAccount();
const [wellLiquidity, setWellLiquidity] = useState<(TokenValue | undefined)[]>([]);
const [wellFunctionNames, setWellFunctionNames] = useState<string[]>([])
const [wellLpBalances, setWellLpBalances] = useState<(TokenValue | undefined)[]>([])
const [tab, showTab] = useState<number>(0)

useMemo(() => {
const run = async() => {
if (!wells || !wells.length) return;
let _wellsLiquidityUSD = [];
for (let i = 0; i < wells.length; i++) {
if (!wells[i].tokens) return;
const _tokenPrices = await Promise.all(wells[i].tokens!.map((token) => getPrice(token, sdk)));
const _reserveValues = wells[i].reserves?.map((tokenReserve, index) => tokenReserve.mul(_tokenPrices[index] as TokenValue || TokenValue.ZERO));
let initialValue = TokenValue.ZERO;
const _totalWellLiquidity = _reserveValues?.reduce((accumulator, currentValue) => currentValue.add(accumulator), initialValue);
_wellsLiquidityUSD[i] = _totalWellLiquidity;
}
setWellLiquidity(_wellsLiquidityUSD);

let _wellsFunctionNames = [];
for (let i = 0; i < wells.length; i++) {
if (!wells[i].wellFunction) return;
const _wellName = await wells[i].wellFunction!.contract.name();
_wellsFunctionNames[i] = _wellName;
}
setWellFunctionNames(_wellsFunctionNames);

let _wellsLpBalances = [];
for (let i = 0; i < wells.length; i++) {
if (!address || !wells[i].lpToken) return;
const _lpBalance = await wells[i].lpToken?.getBalance(address);
_wellsLpBalances[i] = _lpBalance;
}
setWellLpBalances(_wellsLpBalances);
}

run();
}, [sdk, wells, address]);

if (isLoading) return <div>loading...</div>;
if (error) return <div>{error.message}</div>;

const rows = wells?.map((well) => {
function WellRow(well: any, index: any) {
if (!well) return;
const tokens = well.tokens || [];
const logos: ReactNode[] = [];
const smallLogos: ReactNode[] = [];
const symbols: string[] = [];
const gotoWell = () => navigate(`/wells/${well.address}`);

tokens.map((token) => {
tokens.map((token: any) => {
logos.push(<TokenLogo token={token} size={25} key={token.symbol} />);
smallLogos.push(<TokenLogo token={token} size={16} key={token.symbol} />);
symbols.push(token.symbol);
});

Expand All @@ -35,72 +85,163 @@ export const Wells = () => {
</WellDetail>
</Td>
<Td>
<DataText>price function</DataText>
<WellPricing>{wellFunctionNames[index] ? wellFunctionNames[index] : "Price Function"}</WellPricing>
</Td>
<Td align="right">
<TradingFee>0.00%</TradingFee>
</Td>
<Td align="right">
<Amount>${wellLiquidity[index] ? wellLiquidity[index]!.toHuman("short") : "-.--"}</Amount>
</Td>
<Td align="right">
<Reserves>{smallLogos[0]}{well.reserves![0] ? well.reserves![0].toHuman("short") : "-.--"}</Reserves>
<Reserves>{smallLogos[1]}{well.reserves![1] ? well.reserves![1].toHuman("short") : "-.--"}</Reserves>
{well.reserves && well.reserves.length > 2 ?
<MoreReserves>{`+ ${well.reserves.length - 2} MORE`}</MoreReserves>
: null }
</Td>
</Row>
)
};

function MyLPsRow(well: any, index: any) {
if (!well || !wellLpBalances || !wellLpBalances[index] || wellLpBalances[index]!.eq(TokenValue.ZERO)) return;
const tokens = well.tokens || [];
const logos: ReactNode[] = [];
const symbols: string[] = [];
const gotoWell = () => navigate(`/wells/${well.address}`);

tokens.map((token: any) => {
logos.push(<TokenLogo token={token} size={25} key={token.symbol} />);
symbols.push(token.symbol);
});

return (
<Row key={well.address} onClick={gotoWell}>
<Td>
<DataText>pump</DataText>
<WellDetail>
<TokenLogos>{logos}</TokenLogos>
<TokenSymbols>{symbols.join("/")}</TokenSymbols>
</WellDetail>
</Td>
<Td align="right">
<Amount>$100,000</Amount>
<WellLPBalance>{`${wellLpBalances[index]!.toHuman("short")} ${well.lpToken.symbol}`}</WellLPBalance>
</Td>
</Row>
);
});
)
};

const rows = wells?.map((well, index) => { return tab === 0 ? WellRow(well, index) : MyLPsRow(well, index) })

const anyLpPositions = !rows.every((row) => row === undefined)

return (
<Page>
<Title title="Liquidity" />

<Title fontweight={"600"} title="WELLS" />
<TabRow gap={24}>
<Item stretch>
<TabButton onClick={() => showTab(0)} active={tab === 0} stretch bold justify hover>
<span>View Wells</span>
</TabButton>
</Item>
<Item stretch>
<TabButton onClick={() => showTab(1)} active={tab === 1} stretch bold justify hover>
<span>My Liquidity Positions</span>
</TabButton>
</Item>
</TabRow>
<Table>
{tab === 0 ?
<THead>
<Row>
<Th>Well Name and Details</Th>
<Th>Pricing Function</Th>
<Th>Pump(s)</Th>
<Th>Well</Th>
<Th>Well Pricing Function</Th>
<Th align="right">Trading Fees</Th>
<Th align="right">Total Liquidity</Th>
<Th align="right">Reserves</Th>
</Row>
</THead>
<TBody>{rows}</TBody>
:
<THead>
<Row>
<Th>My Positions</Th>
<Th align="right">My Liquidity</Th>
</Row>
</THead>
}
<TBody>
{anyLpPositions === false && tab === 1 ?
<NoLPRow colSpan={2}><NoLPMessage>Liquidity Positions will appear here.</NoLPMessage></NoLPRow>
:
rows
}
</TBody>
</Table>
</Page>
);
};

const WellDetail = styled.div``;
const WellDetail = styled.div`
`;

const TokenLogos = styled.div`
display: flex;
div:not(:first-child) {
margin-left: -8px;
}
`;
const TokenSymbols = styled.div`
font-weight: 700;
font-size: 20px;
line-height: 24px;
margin-top: 8px;
color: #1c1917;
`;

const Amount = styled.div`
font-weight: 500;
font-size: 24px;
line-height: 30px;
font-size: 20px;
line-height: 24px;
color: #1c1917;
`;

const DataText = styled.div`
font-weight: 400;
font-size: 16px;
const Reserves = styled.div`
display: flex;
flex-direction: row;
justify-content flex-end;
gap: 8px;
flex: 1;
`;

const MoreReserves = styled.div`
color: #9CA3AF;
`;

const TradingFee = styled.div`
font-size: 20px;
line-height: 24px;
color: #9ca3af;
color: #4B5563;
text-transform: uppercase;
`;

const Deployer = styled.div`
font-weight: 400;
font-size: 16px;
const WellPricing = styled.div`
font-size: 20px;
line-height: 24px;
text-transform: capitalize;
`;

color: #1c1917;
text-transform: uppercase;
const NoLPRow = styled.td`
background-color: #fff;
height: 120px;
border-bottom: 0.5px solid #9CA3AF;
`;

const NoLPMessage = styled.div`
display: flex;
justify-content: center;
color: #4B5563;
`;

const WellLPBalance = styled.div`
font-size: 20px;
line-height: 24px;
`
5 changes: 4 additions & 1 deletion projects/dex-ui/src/wells/useWells.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export const useWells = () => {
sdk.wells
.getWell(address, {
name: true,
tokens: true
tokens: true,
wellFunction: true,
reserves: true,
lpToken: true,
})
.catch((err) => {
Log.module("wells").log(`Failed to load Well [${address}]: ${err.message}`);
Expand Down

0 comments on commit 3738e44

Please sign in to comment.