This commit is contained in:
Matthias Kretschmann 2024-03-31 15:48:31 +01:00
parent 1ffaab23f5
commit 6123e5d182
Signed by: m
GPG Key ID: 606EEEF3C479A91F
13 changed files with 116 additions and 59 deletions

View File

@ -3,7 +3,7 @@
import { ratioOceanToAsi, ratioAgixToAsi, ratioFetToAsi } from '@/constants' import { ratioOceanToAsi, ratioAgixToAsi, ratioFetToAsi } from '@/constants'
import styles from './CalculationBase.module.css' import styles from './CalculationBase.module.css'
import { usePrices } from '@/hooks' import { usePrices } from '@/hooks'
import { Label } from '../Label' import { Label } from '@/components/Label'
export function CalculationBase() { export function CalculationBase() {
const { prices, isValidating } = usePrices() const { prices, isValidating } = usePrices()

View File

@ -2,7 +2,7 @@ import { InputAmount } from '@/components/FormAmount/Inputs/InputAmount'
import { InputToken } from './Inputs/InputToken' import { InputToken } from './Inputs/InputToken'
import styles from './FormAmount.module.css' import styles from './FormAmount.module.css'
import { Dispatch, SetStateAction } from 'react' import { Dispatch, SetStateAction } from 'react'
import { Token } from './types' import { TokenSymbol } from '@/types'
export function FormAmount({ export function FormAmount({
amount, amount,
@ -13,8 +13,8 @@ export function FormAmount({
}: { }: {
amount: number amount: number
setAmount: Dispatch<SetStateAction<number>> setAmount: Dispatch<SetStateAction<number>>
token: Token | string token: TokenSymbol | string
setToken?: Dispatch<SetStateAction<Token>> setToken?: Dispatch<SetStateAction<TokenSymbol>>
isFiat?: boolean isFiat?: boolean
}) { }) {
return ( return (

View File

@ -1,33 +1,35 @@
import { Dispatch, SetStateAction } from 'react' import { Dispatch, SetStateAction } from 'react'
import styles from './InputToken.module.css' import styles from './InputToken.module.css'
import { CaretDownIcon } from '@radix-ui/react-icons' import { CaretDownIcon } from '@radix-ui/react-icons'
import { Token } from '../types' import { TokenSymbol } from '@/types'
export function InputToken({ export function InputToken({
token, token,
setToken, setToken,
isFiat isFiat
}: { }: {
token: Token | string token: TokenSymbol | string
isFiat?: boolean isFiat?: boolean
setToken?: Dispatch<SetStateAction<Token>> setToken?: Dispatch<SetStateAction<TokenSymbol>>
}) { }) {
return ( return (
<span className={styles.selectWrapper}> <span className={styles.selectWrapper}>
<select <select
className={styles.select} className={styles.select}
onChange={(e) => (setToken ? setToken(e.target.value as Token) : null)} onChange={(e) =>
setToken ? setToken(e.target.value as TokenSymbol) : null
}
value={token} value={token}
disabled={!setToken} disabled={!setToken}
style={setToken ? { paddingRight: '1.25rem' } : {}} style={setToken ? { paddingRight: '1.25rem' } : {}}
> >
{isFiat ? ( {isFiat ? (
<option value="usd">USD</option> <option value="USD">USD</option>
) : ( ) : (
<> <>
<option value="ocean">OCEAN</option> <option value="OCEAN">OCEAN</option>
<option value="fet">FET</option> <option value="FET">FET</option>
<option value="agix">AGIX</option> <option value="AGIX">AGIX</option>
</> </>
)} )}
</select> </select>

View File

@ -1,2 +1 @@
export * from './FormAmount' export * from './FormAmount'
export * from './types'

View File

@ -1 +0,0 @@
export type Token = 'ocean' | 'fet' | 'agix' | undefined

View File

@ -1,58 +1,49 @@
'use client' import { Result } from '@/components/ResultRow'
import { import {
ratioOceanToAsi, ratioOceanToAsi,
ratioAgixToAsi, ratioAgixToAsi,
ratioFetToAsi, ratioFetToAsi,
tokens tokens
} from '@/constants' } from '@/constants'
import { fetcher } from '@/utils'
import { Result } from '@/components/ResultRow'
import stylesShared from './styles.module.css'
import { useState } from 'react'
import useSWR from 'swr'
import { useDebounce } from 'use-debounce'
import { usePrices } from '@/hooks' import { usePrices } from '@/hooks'
import { FormAmount, type Token } from '@/components/FormAmount' import { fetcher } from '@/utils'
import useSWR from 'swr'
import { TokenSymbol } from '@/types'
export function Swap() { export function SwapResults({
token,
amount
}: {
token: TokenSymbol
amount: number
}) {
const { prices, isValidating: isValidatingPrices } = usePrices() const { prices, isValidating: isValidatingPrices } = usePrices()
const [amount, setAmount] = useState(100)
const [debouncedAmount] = useDebounce(amount, 500)
const [token, setToken] = useState<Token>('ocean')
const { data: dataSwapOceanToAgix, isValidating: isValidatingOceanToAgix } = const { data: dataSwapOceanToAgix, isValidating: isValidatingOceanToAgix } =
useSWR( useSWR(
`/api/quote/?tokenIn=${tokens[0]}&tokenOut=${tokens[2]}&amountIn=${debouncedAmount}`, `/api/quote/?tokenIn=${tokens[0].address}&tokenOut=${tokens[2].address}&amountIn=${amount}`,
fetcher fetcher
) )
const { data: dataSwapOceanToFet, isValidating: isValidatingOceanToFet } = const { data: dataSwapOceanToFet, isValidating: isValidatingOceanToFet } =
useSWR( useSWR(
`/api/quote/?tokenIn=${tokens[0]}&tokenOut=${tokens[1]}&amountIn=${debouncedAmount}`, `/api/quote/?tokenIn=${tokens[0].address}&tokenOut=${tokens[1].address}&amountIn=${amount}`,
fetcher fetcher
) )
return ( return (
<div className={stylesShared.results}> <>
<h3 className={stylesShared.title}>
Holding or swapping{' '}
<FormAmount
amount={amount}
token={token}
setAmount={setAmount}
// setToken={setToken}
/>{' '}
right now gets you:
</h3>
<Result <Result
tokenSymbol="OCEAN" tokenSymbol="OCEAN"
tokenAddress="0x967da4048cd07ab37855c090aaf366e4ce1b9f48" tokenAddress="0x967da4048cd07ab37855c090aaf366e4ce1b9f48"
amount={debouncedAmount} amount={amount}
amountAsi={debouncedAmount * ratioOceanToAsi} amountAsi={amount * ratioOceanToAsi}
amountFiat={debouncedAmount * ratioOceanToAsi * prices.asi} amountFiat={amount * ratioOceanToAsi * prices.asi}
amountOriginalFiat={token ? debouncedAmount * prices[token] : undefined} amountOriginalFiat={
token
? amount *
prices[token.toLowerCase() as 'ocean' | 'agix' | 'fet' | 'asi']
: undefined
}
isValidating={ isValidating={
isValidatingOceanToAgix || isValidatingOceanToAgix ||
isValidatingOceanToFet || isValidatingOceanToFet ||
@ -105,6 +96,6 @@ export function Swap() {
} }
isValidating={isValidatingOceanToFet || isValidatingPrices} isValidating={isValidatingOceanToFet || isValidatingPrices}
/> />
</div> </>
) )
} }

View File

@ -0,0 +1,31 @@
'use client'
import stylesShared from '../styles.module.css'
import { useState } from 'react'
import { useDebounce } from 'use-debounce'
import { FormAmount } from '@/components/FormAmount'
import { SwapResults } from './Results'
import { TokenSymbol } from '@/types'
export function Swap() {
const [amount, setAmount] = useState(100)
const [debouncedAmount] = useDebounce(amount, 500)
const [token, setToken] = useState<TokenSymbol>('OCEAN')
return (
<div className={stylesShared.results}>
<h3 className={stylesShared.title}>
Holding or swapping{' '}
<FormAmount
amount={amount}
token={token}
setAmount={setAmount}
// setToken={setToken}
/>{' '}
right now gets you:
</h3>
<SwapResults token={token} amount={debouncedAmount} />
</div>
)
}

View File

@ -1,2 +1,2 @@
export * from './Buy' export * from './Buy'
export * from './Swap' export * from './Swap/Swap'

View File

@ -1,9 +1,11 @@
import { Token } from '@/types'
export const ratioOceanToAsi = 0.433226 export const ratioOceanToAsi = 0.433226
export const ratioAgixToAsi = 0.43335 export const ratioAgixToAsi = 0.43335
export const ratioFetToAsi = 1 export const ratioFetToAsi = 1
export const tokens: `0x${string}`[] = [ export const tokens: Token[] = [
'0x967da4048cd07ab37855c090aaf366e4ce1b9f48', // OCEAN { symbol: 'OCEAN', address: '0x967da4048cd07ab37855c090aaf366e4ce1b9f48' },
'0xaea46a60368a7bd060eec7df8cba43b7ef41ad85', // FET { symbol: 'FET', address: '0xaea46a60368a7bd060eec7df8cba43b7ef41ad85' },
'0x5b7533812759b45c2b44c19e320ba2cd2681b542' // AGIX { symbol: 'AGIX', address: '0x5b7533812759b45c2b44c19e320ba2cd2681b542' }
] ]

View File

@ -1,22 +1,33 @@
'use client'
import { tokens } from '@/constants' import { tokens } from '@/constants'
import { fetcher } from '@/utils' import { fetcher, getTokenAddressBySymbol } from '@/utils'
import useSWR from 'swr' import useSWR from 'swr'
const tokenAddresses = tokens.map((token) => token.address).toString()
export function usePrices(): { export function usePrices(): {
prices: { ocean: number; fet: number; agix: number; asi: number } prices: { ocean: number; fet: number; agix: number; asi: number }
isValidating: boolean isValidating: boolean
isLoading: boolean isLoading: boolean
} { } {
const { data, isValidating, isLoading } = useSWR( const { data, isValidating, isLoading } = useSWR(
`/api/prices/?tokens=${tokens.toString()}`, `/api/prices/?tokens=${tokenAddresses}`,
fetcher fetcher
) )
const ocean = data?.[tokens[0]]?.usd || 0 const oceanAddress = getTokenAddressBySymbol('OCEAN')
const fet = data?.[tokens[1]]?.usd || 0 const fetAddress = getTokenAddressBySymbol('FET')
const agix = data?.[tokens[2]]?.usd || 0 const agixAddress = getTokenAddressBySymbol('AGIX')
if (!oceanAddress || !fetAddress || !agixAddress)
return {
prices: { ocean: 0, fet: 0, agix: 0, asi: 0 },
isValidating,
isLoading
}
const ocean = data?.[oceanAddress]?.usd || 0
const fet = data?.[fetAddress]?.usd || 0
const agix = data?.[agixAddress]?.usd || 0
const asi = fet const asi = fet
return { prices: { ocean, fet, agix, asi }, isValidating, isLoading } return { prices: { ocean, fet, agix, asi }, isValidating, isLoading }

7
types/Token.ts Normal file
View File

@ -0,0 +1,7 @@
export type TokenSymbol = 'OCEAN' | 'FET' | 'AGIX' | 'ASI'
export type TokenAddress = `0x${string}`
export type Token = {
symbol: TokenSymbol
address: `0x${string}`
}

1
types/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './Token'

View File

@ -1,3 +1,5 @@
import { tokens } from '@/constants'
import type { TokenAddress, Token } from '@/types'
import { formatCurrency } from '@coingecko/cryptoformat' import { formatCurrency } from '@coingecko/cryptoformat'
export function formatNumber(price: number, currency: string) { export function formatNumber(price: number, currency: string) {
@ -12,3 +14,15 @@ export async function fetcher(url: string) {
if (!res.ok) throw new Error('Failed to fetch') if (!res.ok) throw new Error('Failed to fetch')
return await res.json() return await res.json()
} }
export function getTokenBySymbol(symbol: string): Token | undefined {
const token = tokens.find((t) => t.symbol === symbol)
return token
}
export function getTokenAddressBySymbol(
symbol: string
): TokenAddress | undefined {
const token = getTokenBySymbol(symbol)
return token?.address
}