Skip to content

Commit

Permalink
feat: web3 integration
Browse files Browse the repository at this point in the history
- add providers for wagmi connected and prices
- add generic inputs WIP🚧
- integration in Swap module
- add token icons
- add infura key env
- eslint fix
  • Loading branch information
toniocodo committed Aug 27, 2023
1 parent 8c3f1cf commit c3a30f8
Show file tree
Hide file tree
Showing 50 changed files with 1,284 additions and 216 deletions.
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
VITE_WALLET_CONNECT_PROJECT_ID=
VITE_WALLET_CONNECT_PROJECT_ID=
VITE_INFURA_ID=
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
}
],
"react/react-in-jsx-scope": "off",
"no-empty": ["error", { "allowEmptyCatch": true }],
// Unused imports rules
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
Expand Down
5 changes: 5 additions & 0 deletions apps/oeth/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ import { Container, Stack } from '@mui/material';
import { HistoryView } from '@origin/oeth/history';
import { SwapView } from '@origin/oeth/swap';
import { WrapView } from '@origin/oeth/wrap';
import { usePrices } from '@origin/shared/providers';
import { Route, Routes } from 'react-router-dom';

import { ApyHeader } from './components/ApyHeader';
import { Topnav } from './components/Topnav';

export function App() {
const { data } = usePrices();

console.log('data', data);

return (
<Stack>
<Topnav />
Expand Down
9 changes: 5 additions & 4 deletions apps/oeth/src/clients/wagmi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ import {
} from '@rainbow-me/rainbowkit/wallets';
import { configureChains, createConfig } from 'wagmi';
import { goerli, localhost, mainnet } from 'wagmi/chains';
import { infuraProvider } from 'wagmi/providers/infura';
import { publicProvider } from 'wagmi/providers/public';

const VITE_WALLET_CONNECT_PROJECT_ID = import.meta.env[
'VITE_WALLET_CONNECT_PROJECT_ID'
];
const VITE_WALLET_CONNECT_PROJECT_ID = import.meta.env
.VITE_WALLET_CONNECT_PROJECT_ID;
const VITE_INFURA_ID = import.meta.env.VITE_INFURA_ID;

export const { chains, publicClient, webSocketPublicClient } = configureChains(
[mainnet, goerli, localhost],
[publicProvider()],
[infuraProvider({ apiKey: VITE_INFURA_ID }), publicProvider()],
);

const connectors = connectorsForWallets([
Expand Down
16 changes: 13 additions & 3 deletions apps/oeth/src/components/ApyHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,26 @@ import {
Typography,
} from '@mui/material';
import { Icon } from '@origin/shared/components';
import { tokens } from '@origin/shared/contracts';
import { useIntl } from 'react-intl';
import { useAccount, useBalance } from 'wagmi';

const days = [7, 30];

export function ApyHeader() {
const intl = useIntl();
const [selectedPeriod, setSelectedPeriod] = useState(30);
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const { address } = useAccount();
const { data: oethBalance } = useBalance({
address,
token: tokens.mainnet.OUSD.address,
watch: true,
});

function handleClose() {
const handleClose = () => {
setAnchorEl(null);
}
};

return (
<>
Expand Down Expand Up @@ -138,7 +146,9 @@ export function ApyHeader() {
<ValueContainer
icon="https://app.oeth.com/images/oeth.svg"
text={intl.formatMessage({ defaultMessage: 'OETH Balance' })}
value={intl.formatNumber(0, { minimumFractionDigits: 4 })}
value={intl.formatNumber(Number(oethBalance?.formatted ?? 0), {
minimumFractionDigits: 4,
})}
/>
<Box
sx={{
Expand Down
10 changes: 10 additions & 0 deletions apps/oeth/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// <reference types="vite/client" />

interface ImportMetaEnv {
readonly VITE_WALLET_CONNECT_PROJECT_ID: string;
readonly VITE_INFURA_ID: string;
}

interface ImportMeta {
readonly env: ImportMetaEnv;
}
2 changes: 1 addition & 1 deletion apps/oeth/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default defineConfig({
viteStaticCopy({
targets: [
{
src: path.resolve(__dirname, '../../libs/shared/assets/files/*'),
src: path.resolve(__dirname, '../../libs/shared/assets/files/**/*'),
dest: './images',
},
],
Expand Down
57 changes: 30 additions & 27 deletions libs/oeth/swap/src/components/GasPopover.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { useEffect, useState } from 'react';
import { useState } from 'react';

import {
alpha,
Box,
Button,
debounce,
FormControl,
FormHelperText,
IconButton,
Expand All @@ -15,12 +14,16 @@ import {
Stack,
useTheme,
} from '@mui/material';
import { isNumber } from 'lodash';
import { produce } from 'immer';
import { useIntl } from 'react-intl';
import { useFeeData } from 'wagmi';

import { useSwapState } from '../state';

import type { Theme } from '@mui/material';
import type { ChangeEvent } from 'react';

const defaultPriceTolerance = 0.01;
const defaultSlippage = 0.01;

const gridStyles = {
display: 'grid',
Expand All @@ -30,20 +33,14 @@ const gridStyles = {
alignItems: 'center',
};

interface Props {
gasPrice: number;
onPriceToleranceChange: (value: number) => void;
}

export function GasPopover({ gasPrice, onPriceToleranceChange }: Props) {
export function GasPopover() {
const theme = useTheme();
const intl = useIntl();
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const [priceTolerance, setPriceTolerance] = useState(defaultPriceTolerance);
const [{ slippage }, setSwapState] = useSwapState();
const { data: feeData } = useFeeData({ formatUnits: 'gwei' });

useEffect(() => {
onPriceToleranceChange(priceTolerance);
}, [priceTolerance, onPriceToleranceChange]);
const handleSlippageChange = (evt: ChangeEvent<HTMLInputElement>) => {};

return (
<>
Expand Down Expand Up @@ -89,13 +86,13 @@ export function GasPopover({ gasPrice, onPriceToleranceChange }: Props) {
>
<Stack gap={2} sx={{ '--origin-blue': '#0074F0' }}>
<FormControl variant="standard">
<InputLabel htmlFor="tolerance" shrink>
{intl.formatMessage({ defaultMessage: 'Price tolerance' })}
<InputLabel htmlFor="slippage" shrink>
{intl.formatMessage({ defaultMessage: 'Slippage' })}
</InputLabel>
<Box sx={gridStyles}>
<InputBase
id="tolerance"
defaultValue={priceTolerance}
id="slippage"
value={slippage}
fullWidth
sx={{
borderColor: 'var(--origin-blue)',
Expand All @@ -111,11 +108,7 @@ export function GasPopover({ gasPrice, onPriceToleranceChange }: Props) {
},
},
}}
onChange={debounce((e) => {
if (isNumber(parseFloat(e.target.value))) {
setPriceTolerance(Number(e.target.value));
}
}, 300)}
onChange={handleSlippageChange}
endAdornment={
<InputAdornment
position="end"
Expand All @@ -139,13 +132,19 @@ export function GasPopover({ gasPrice, onPriceToleranceChange }: Props) {
},
}}
fullWidth
disabled={priceTolerance === defaultPriceTolerance}
onClick={() => setPriceTolerance(defaultPriceTolerance)}
disabled={slippage === defaultSlippage}
onClick={() => {
setSwapState(
produce((draft) => {
draft.slippage = defaultSlippage;
}),
);
}}
>
{intl.formatMessage({ defaultMessage: 'Auto' })}
</Button>
</Box>
{priceTolerance > 1 ? (
{slippage > 1 ? (
<FormHelperText
sx={{
gridColumn: 'span 2',
Expand All @@ -169,7 +168,11 @@ export function GasPopover({ gasPrice, onPriceToleranceChange }: Props) {
<Box sx={gridStyles}>
<InputBase
id="gas"
defaultValue={gasPrice}
readOnly
defaultValue={intl.formatNumber(
parseFloat(feeData?.formatted.gasPrice),
{ maximumFractionDigits: 4 },
)}
fullWidth
sx={{
borderColor: 'var(--origin-blue)',
Expand Down
10 changes: 10 additions & 0 deletions libs/oeth/swap/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { tokens } from '@origin/shared/contracts';

export const swapTokens = [
tokens.mainnet.ETH,
tokens.mainnet.OETH,
tokens.mainnet.WETH,
tokens.mainnet.stETH,
tokens.mainnet.frxETH,
tokens.mainnet.sfrxETH,
];
33 changes: 33 additions & 0 deletions libs/oeth/swap/src/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useState } from 'react';

import { tokens } from '@origin/shared/contracts';
import { useDebouncedEffect } from '@react-hookz/web';
import { produce } from 'immer';
import { createContainer } from 'react-tracked';

import type { Token } from '@origin/shared/contracts';

export const { Provider: SwapProvider, useTracked: useSwapState } =
createContainer(() => {
const [state, setState] = useState({
amountIn: 0n,
tokenIn: tokens.mainnet.ETH as Token,
amountOut: 0n,
tokenOut: tokens.mainnet.OETH as Token,
slippage: 0.01,
});

useDebouncedEffect(
() => {
setState(
produce((draft) => {
draft.amountOut = draft.amountIn;
}),
);
},
[state.amountIn],
1e3,
);

return [state, setState];
});
Loading

0 comments on commit c3a30f8

Please sign in to comment.