Skip to content

Commit

Permalink
feat(buyback-ui): added workspace (#257)
Browse files Browse the repository at this point in the history
* feat(buyback-ui): added workspace

* feat(chart): implemented chart to ultrasound workspace

* feat(useSellSNX): impleneted mutation to sell snx

* yarn typecheck

* feat(snxPrice): added snx price hook

* chore(typecheck)

* chore(theme): remove extending theme func

* fix(deps)

* feat(button): disable when not on base

* feat(BurnSNX): added margin to botton row

* fix(deps)

* fix: update snx price hook

* feat(SNXPrice): used pyth price

* feat(input): fixed input

* fix(typescript)

* feat(links): added links to why text and learn more button

---------

Co-authored-by: Peiman <[email protected]>
  • Loading branch information
fritzschoff and Rickk137 authored Apr 30, 2024
1 parent 33af071 commit 6b4a332
Show file tree
Hide file tree
Showing 40 changed files with 1,591 additions and 2 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
8 changes: 7 additions & 1 deletion liquidity/lib/useBlockchain/useBlockchain.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ethers } from 'ethers';
import React from 'react';
import React, { useMemo } from 'react';
import {
BaseIcon,
EthereumIcon,
Expand Down Expand Up @@ -251,6 +251,12 @@ export function useWallet() {
};
}

export function useGetNetwork(chainId: string) {
return useMemo(() => {
return NETWORKS.find((n) => n.hexId === chainId);
}, [chainId]);
}

export function useNetwork() {
const [{ connectedChain }, setChain] = useSetChain();

Expand Down
1 change: 1 addition & 0 deletions oracle-manager/ui/.env.example
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
NEXT_PUBLIC_WC_PROJECT_ID=xxx
NEXT_PUBLIC_INFURA_KEY=xxx
3 changes: 3 additions & 0 deletions ultrasound/ui/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
INFURA_KEY=xxx
PYTH_MAINNET_ENDPOINT=https://hermes.pyth.network/
PYTH_TESTNET_ENDPOINT=https://hermes.pyth.network/
1 change: 1 addition & 0 deletions ultrasound/ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# ULTRASOUND HOMES
68 changes: 68 additions & 0 deletions ultrasound/ui/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const path = require('path');
require.resolve('core-js');
require.resolve('@babel/runtime-corejs3/core-js/date/now');

module.exports = {
presets: [
require.resolve('@babel/preset-typescript'),
[require.resolve('@babel/preset-react'), { runtime: 'automatic' }],
],

plugins: [[require.resolve('@babel/plugin-transform-runtime'), { corejs: 3 }]],

env: {
production: {
presets: [
[
require.resolve('@babel/preset-env'),
{
useBuiltIns: 'usage',
corejs: { version: 3, proposals: true },
modules: false,
targets: {
browsers: require('./package.json').browserslist,
},
},
],
],
},

development: {
presets: [
[
require.resolve('@babel/preset-env'),
{
modules: false,
targets: { browsers: ['last 1 Chrome version'] },
},
],
],
plugins: [require.resolve('react-refresh/babel')],
},

test: {
presets: [
[
require.resolve('@babel/preset-env'),
{
modules: 'commonjs',
targets: { node: 'current' },
},
],
],
plugins: [
[
require.resolve('babel-plugin-istanbul'),
{
cwd: path.resolve('../..'),
all: true,
excludeNodeModules: false,
include: ['v3'],
exclude: ['**/*.test.*', '**/*.cy.*', '**/*.e2e.*'],
},
'istanbul',
],
],
},
},
};
62 changes: 62 additions & 0 deletions ultrasound/ui/components/BurnSNX.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Button, Flex, Image, Link, Text, Tooltip, useDisclosure } from '@chakra-ui/react';
import { BurnSNXModal } from './BurnSNXModal';
import { isBaseAndromeda } from '@snx-v3/isBaseAndromeda';
import { useNetwork } from '@snx-v3/useBlockchain';
import { useSNXPrice } from '../hooks/useSNXPrice';

export function BurnSNX() {
const { network } = useNetwork();
const { isOpen, onOpen, onClose } = useDisclosure();
const { data: SNXPrice } = useSNXPrice();

return (
<Flex
border="1px solid"
borderColor="gray.900"
rounded="base"
flexDir="column"
bg="navy.700"
w="415px"
>
<Image src="/burn-snx.svg" h="284px" />
<Flex flexDir="column" gap="6" p="4">
<Text fontWeight={700} fontSize="18px" color="white">
Sell SNX at premium and watch it burn
</Text>
<Text fontSize="16px">
Sell your SNX at a <b>premium</b> price to the Buyback and Burn contract and get USDC on
Base
</Text>
<Text fontWeight={700} fontSize="20px">
{SNXPrice?.eq(0) ? (
'refecthing...'
) : (
<>
Buyback Price: <s>$ {SNXPrice?.toNumber().toFixed(2)}</s> $
{SNXPrice ? (SNXPrice?.toNumber() + SNXPrice?.toNumber() * 0.01).toFixed(2) : 0}
</>
)}
</Text>
<Flex gap="4" mt="65px">
{!isBaseAndromeda(network?.id, network?.preset) ? (
<Tooltip label="Please conect to the Base network">
<Button isDisabled={true}>Burn SNX</Button>
</Tooltip>
) : (
<Button onClick={() => onOpen()}>Burn SNX</Button>
)}
<Link
href="https://blog.synthetix.io/the-andromeda-release-buyback-and-burn/"
target="_blank"
rel="noopener"
>
<Button variant="outline" colorScheme="gray" color="white">
Lean More
</Button>
</Link>
</Flex>
</Flex>
<BurnSNXModal isOpen={isOpen} onClose={onClose} />
</Flex>
);
}
205 changes: 205 additions & 0 deletions ultrasound/ui/components/BurnSNXModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import {
Button,
Divider,
Flex,
Image,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
Spinner,
Text,
} from '@chakra-ui/react';
import { useWallet } from '@snx-v3/useBlockchain';
import { useTokenBalance } from '@snx-v3/useTokenBalance';
import { SNXUSDBalanceOfBuyBackContract } from '../hooks/SNXUSDBalanceOfBuyBackContract';
import { useApprove } from '@snx-v3/useApprove';
import Wei from '@synthetixio/wei';
import { useState } from 'react';
import { useSellSNX } from '../mutations/useSellSNX';
import { useBurnEvents } from '../hooks/useBurnEvents';
import { useSNXPrice } from '../hooks/useSNXPrice';

export function BurnSNXModal({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) {
const [amount, setAmount] = useState<Wei | undefined>(new Wei(0));
const [receivingUSDCAmount, setReceivingUSDCAmount] = useState(0);
const { data: events } = useBurnEvents();
const { connect, activeWallet } = useWallet();
const { data: SNXPrice } = useSNXPrice();

const { data: snxBalance } = useTokenBalance('0x22e6966B799c4D5B13BE962E1D117b56327FDa66');
const { data: usdcBalance } = useTokenBalance('0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913');
const { data: contractBalance } = SNXUSDBalanceOfBuyBackContract(
'0x632cAa10A56343C5e6C0c066735840c096291B18'
);

const { requireApproval, approve, refetchAllowance } = useApprove({
contractAddress: '0x22e6966B799c4D5B13BE962E1D117b56327FDa66',
amount: amount ? amount.toBN() : 0,
spender: '0x632cAa10A56343C5e6C0c066735840c096291B18',
});
const { mutateAsync, isPending } = useSellSNX();

return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent bg="navy.700" border="1px solid" borderColor="gray.900" rounded="base">
<ModalHeader color="white">
Burn your SNX
<Divider mt="2" />
</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Flex flexDir="column" gap="4">
<Text fontWeight={700} color="white">
Burn
</Text>
<Flex border="1px solid" borderColor="gray.900" rounded="base" flexDir="column" p="4">
<Flex justifyContent="space-between" w="100%">
<Flex
alignItems="center"
border="1px solid"
borderColor="gray.900"
p="2"
rounded="base"
justifyContent="center"
w="90px"
gap="2"
>
<Image src="/snx-input.svg" />
<Text fontWeight={700} fontSize="16px">
SNX
</Text>
</Flex>
<Input
variant="unstyled"
placeholder="0.00"
textAlign="end"
fontSize="24px"
color="white"
type="number"
overflow="scroll"
fontWeight={700}
value={amount ? amount.toNumber() : ''}
onChange={(e) => {
try {
if (SNXPrice) {
const snxAmount = new Wei(e.target.value);
setAmount(snxAmount);
setReceivingUSDCAmount(
snxAmount.mul(SNXPrice).add(SNXPrice.mul(0.01)).toNumber()
);
}
} catch (error) {
console.error('failed to parse input: ', Error);
setAmount(undefined);
}
}}
/>
</Flex>
<Flex w="100%" justifyContent="space-between">
<Text
color="gray.500"
fontSize="12px"
mt="2"
cursor="pointer"
onClick={() => {
if (SNXPrice && snxBalance) {
setAmount(snxBalance);
setReceivingUSDCAmount(
snxBalance.mul(SNXPrice).add(SNXPrice.mul(0.01)).toNumber()
);
}
}}
>
Balance: {snxBalance ? snxBalance.toNumber().toFixed(2) : '-'}
</Text>
<Text color="gray.500" fontSize="12px" mt="2">
$
</Text>
</Flex>
<Text color="gray.500" fontSize="12px">
max burnable:{' '}
{contractBalance &&
events?.SNXPrice &&
(
new Wei(contractBalance, 18).toNumber() /
(events.SNXPrice + events.SNXPrice * 0.01)
).toFixed(2)}
</Text>
</Flex>
<Text fontWeight={700}>Receive</Text>
<Flex border="1px solid" borderColor="gray.900" rounded="base" flexDir="column" p="4">
<Flex justifyContent="space-between" w="100%">
<Flex
alignItems="center"
border="1px solid"
borderColor="gray.900"
p="2"
rounded="base"
justifyContent="center"
w="120px"
gap="2"
>
<Image src="/usdc.svg" />
<Text fontWeight={700} fontSize="16px">
USDC
</Text>
</Flex>
<Input
variant="unstyled"
placeholder="0.00"
textAlign="end"
fontSize="24px"
color="white"
type="number"
isDisabled={true}
overflow="scroll"
fontWeight={700}
_disabled={{ color: 'white' }}
value={receivingUSDCAmount}
/>
</Flex>
<Flex w="100%" justifyContent="space-between" gap="2">
<Text color="gray.500" fontSize="12px" mt="2">
Balance: {usdcBalance ? usdcBalance.toNumber().toFixed(2) : '-'}
</Text>
</Flex>
</Flex>
{isPending ? (
<Spinner colorScheme="black" alignSelf="center" />
) : (
<Button
my="4"
onClick={async () => {
if (activeWallet?.address) {
if (requireApproval) {
await approve(false);
await refetchAllowance();
}
if (amount) {
await mutateAsync(amount);
onClose();
}
} else {
onClose();
connect();
}
}}
>
{activeWallet?.address
? requireApproval
? 'Approve SNX'
: 'Burn SNX'
: 'Connect Wallet'}
</Button>
)}
</Flex>
</ModalBody>
</ModalContent>
</Modal>
);
}
Loading

0 comments on commit 6b4a332

Please sign in to comment.