{amountPercent}%
diff --git a/src/components/organisms/AssetActions/Pool/index.module.css b/src/components/organisms/AssetActions/Pool/index.module.css
index 9049b29a0..9f103e74d 100644
--- a/src/components/organisms/AssetActions/Pool/index.module.css
+++ b/src/components/organisms/AssetActions/Pool/index.module.css
@@ -46,6 +46,7 @@
text-align: center;
border-top: 1px solid var(--border-color);
padding-top: calc(var(--spacer) / 4);
+ padding-bottom: calc(var(--spacer) / 4);
}
.update:before {
diff --git a/src/components/organisms/AssetActions/Pool/index.tsx b/src/components/organisms/AssetActions/Pool/index.tsx
index d9bee002f..39279afbd 100644
--- a/src/components/organisms/AssetActions/Pool/index.tsx
+++ b/src/components/organisms/AssetActions/Pool/index.tsx
@@ -17,15 +17,11 @@ import EtherscanLink from '../../../atoms/EtherscanLink'
import Token from './Token'
import TokenList from './TokenList'
import { graphql, useStaticQuery } from 'gatsby'
+import TokenBalance from '../../../../@types/TokenBalance'
import Transactions from './Transactions'
import Graph, { ChartDataLiqudity } from './Graph'
import axios from 'axios'
-export interface Balance {
- ocean: number
- datatoken: number
-}
-
const contentQuery = graphql`
query PoolQuery {
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
@@ -58,7 +54,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
const [poolTokens, setPoolTokens] = useState
()
const [totalPoolTokens, setTotalPoolTokens] = useState()
- const [userLiquidity, setUserLiquidity] = useState()
+ const [userLiquidity, setUserLiquidity] = useState()
const [swapFee, setSwapFee] = useState()
const [weightOcean, setWeightOcean] = useState()
const [weightDt, setWeightDt] = useState()
@@ -76,7 +72,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
creatorTotalLiquidityInOcean,
setCreatorTotalLiquidityInOcean
] = useState(0)
- const [creatorLiquidity, setCreatorLiquidity] = useState()
+ const [creatorLiquidity, setCreatorLiquidity] = useState()
const [creatorPoolTokens, setCreatorPoolTokens] = useState()
const [creatorPoolShare, setCreatorPoolShare] = useState()
const [graphData, setGraphData] = useState()
@@ -84,6 +80,12 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
// the purpose of the value is just to trigger the effect
const [refreshPool, setRefreshPool] = useState(false)
+ useEffect(() => {
+ // Re-fetch price periodically, triggering re-calculation of everything
+ const interval = setInterval(() => refreshPrice(), refreshInterval)
+ return () => clearInterval(interval)
+ }, [ddo, refreshPrice])
+
useEffect(() => {
setIsRemoveDisabled(isInPurgatory && owner === accountId)
}, [isInPurgatory, owner, accountId])
diff --git a/src/components/organisms/AssetActions/Trade/FormTrade.module.css b/src/components/organisms/AssetActions/Trade/FormTrade.module.css
new file mode 100644
index 000000000..996909b3b
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/FormTrade.module.css
@@ -0,0 +1,5 @@
+.alertWrap {
+ min-height: 320px;
+ display: flex;
+ align-items: center;
+}
diff --git a/src/components/organisms/AssetActions/Trade/FormTrade.tsx b/src/components/organisms/AssetActions/Trade/FormTrade.tsx
new file mode 100644
index 000000000..dea05197d
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/FormTrade.tsx
@@ -0,0 +1,155 @@
+import React, { ReactElement, useState } from 'react'
+import { useOcean } from '@oceanprotocol/react'
+import { BestPrice, DDO, Logger } from '@oceanprotocol/lib'
+import * as Yup from 'yup'
+import { Formik } from 'formik'
+import Actions from '../Pool/Actions'
+import { graphql, useStaticQuery } from 'gatsby'
+import { useUserPreferences } from '../../../../providers/UserPreferences'
+import { toast } from 'react-toastify'
+import Swap from './Swap'
+import TokenBalance from '../../../../@types/TokenBalance'
+import Alert from '../../../atoms/Alert'
+import styles from './FormTrade.module.css'
+import { FormTradeData, initialValues } from '../../../../models/FormTrade'
+
+const contentQuery = graphql`
+ query TradeQuery {
+ content: allFile(filter: { relativePath: { eq: "price.json" } }) {
+ edges {
+ node {
+ childContentJson {
+ trade {
+ action
+ warning
+ }
+ }
+ }
+ }
+ }
+ }
+`
+
+export default function FormTrade({
+ ddo,
+ balance,
+ maxDt,
+ maxOcean,
+ price
+}: {
+ ddo: DDO
+ balance: TokenBalance
+ maxDt: number
+ maxOcean: number
+ price: BestPrice
+}): ReactElement {
+ const data = useStaticQuery(contentQuery)
+ const content = data.content.edges[0].node.childContentJson.trade
+ const { ocean, accountId } = useOcean()
+ const { debug } = useUserPreferences()
+ const [txId, setTxId] = useState()
+
+ const [maximumOcean, setMaximumOcean] = useState(maxOcean)
+ const [maximumDt, setMaximumDt] = useState(maxDt)
+ const [isWarningAccepted, setIsWarningAccepted] = useState(false)
+
+ const validationSchema = Yup.object().shape({
+ ocean: Yup.number()
+ .max(maximumOcean, (param) => `Must be more or equal to ${param.max}`)
+ .min(0.001, (param) => `Must be more or equal to ${param.min}`)
+ .required('Required')
+ .nullable(),
+ datatoken: Yup.number()
+ .max(maxDt, `Must be less or equal than ${maximumDt}`)
+ .min(0.00001, (param) => `Must be more or equal to ${param.min}`)
+ .required('Required')
+ .nullable(),
+ type: Yup.string(),
+ slippage: Yup.string()
+ })
+
+ async function handleTrade(values: FormTradeData) {
+ try {
+ const tx =
+ values.type === 'buy'
+ ? // ? await ocean.pool.buyDT(
+ // accountId,
+ // price.address,
+ // values.datatoken.toString(),
+ // (values.ocean * 1.01).toString()
+ // )
+ await ocean.pool.buyDTWithExactOcean(
+ accountId,
+ price.address,
+ (values.datatoken * 0.99).toString(),
+ values.ocean.toString()
+ )
+ : await ocean.pool.sellDT(
+ accountId,
+ price.address,
+ values.datatoken.toString(),
+ (values.ocean * 0.99).toString()
+ )
+
+ setTxId(tx?.transactionHash)
+ } catch (error) {
+ Logger.error(error.message)
+ toast.error(error.message)
+ }
+ }
+
+ return (
+ {
+ await handleTrade(values)
+ resetForm()
+ setSubmitting(false)
+ }}
+ >
+ {({ isSubmitting, submitForm, values }) => (
+ <>
+ {isWarningAccepted ? (
+
+ ) : (
+
+
setIsWarningAccepted(true)
+ }}
+ />
+
+ )}
+
+
+ {debug && (
+
+ {JSON.stringify(values, null, 2)}
+
+ )}
+ >
+ )}
+
+ )
+}
diff --git a/src/components/organisms/AssetActions/Trade/Output.module.css b/src/components/organisms/AssetActions/Trade/Output.module.css
new file mode 100644
index 000000000..8e59b0f78
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/Output.module.css
@@ -0,0 +1,22 @@
+.output {
+ border-top: 1px solid var(--border-color);
+ padding: var(--spacer);
+ display: grid;
+ gap: var(--spacer);
+ grid-template-columns: 1fr 1fr;
+ margin-left: -2rem;
+ margin-right: -2rem;
+}
+
+.output p {
+ font-weight: var(--font-weight-bold);
+ margin-bottom: calc(var(--spacer) / 8);
+}
+
+.output [class*='token'] {
+ white-space: normal;
+}
+
+.output [class*='token'] > figure {
+ display: none;
+}
diff --git a/src/components/organisms/AssetActions/Trade/Output.tsx b/src/components/organisms/AssetActions/Trade/Output.tsx
new file mode 100644
index 000000000..dc6c99630
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/Output.tsx
@@ -0,0 +1,77 @@
+import { useOcean } from '@oceanprotocol/react'
+import { FormikContextType, useFormikContext } from 'formik'
+import React, { ReactElement, useEffect, useState } from 'react'
+import { FormTradeData } from '../../../../models/FormTrade'
+import Token from '../Pool/Token'
+import styles from './Output.module.css'
+
+export default function Output({
+ dtSymbol,
+ poolAddress
+}: {
+ dtSymbol: string
+ poolAddress: string
+}): ReactElement {
+ const { ocean } = useOcean()
+ const [maxOutput, setMaxOutput] = useState()
+ const [swapFee, setSwapFee] = useState()
+ const [swapFeeValue, setSwapFeeValue] = useState()
+ // Connect with form
+ const { values }: FormikContextType = useFormikContext()
+
+ // Get swap fee
+ useEffect(() => {
+ if (!ocean || !poolAddress) return
+
+ async function getSwapFee() {
+ const swapFee = await ocean.pool.getSwapFee(poolAddress)
+ // swapFee is tricky: to get 0.1% you need to convert from 0.001
+ setSwapFee(`${Number(swapFee) * 100}`)
+ const value =
+ values.type === 'buy'
+ ? Number(swapFee) * values.ocean
+ : Number(swapFee) * values.datatoken
+ setSwapFeeValue(value.toString())
+ }
+ getSwapFee()
+ }, [ocean, poolAddress, values])
+
+ // Get output values
+ useEffect(() => {
+ if (!ocean || !poolAddress) return
+
+ async function getOutput() {
+ // Minimum received
+ // TODO: check if this here is redundant cause we call some of that already in Swap.tsx
+ const maxImpact = 1 - Number(values.slippage) / 100
+ const maxPrice =
+ values.type === 'buy'
+ ? (values.datatoken * maxImpact).toString()
+ : (values.ocean * maxImpact).toString()
+
+ setMaxOutput(maxPrice)
+ }
+ getOutput()
+ }, [ocean, poolAddress, values])
+
+ return (
+
+ )
+}
diff --git a/src/components/organisms/AssetActions/Trade/Slippage.module.css b/src/components/organisms/AssetActions/Trade/Slippage.module.css
new file mode 100644
index 000000000..b27e26683
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/Slippage.module.css
@@ -0,0 +1,30 @@
+.slippage {
+ font-size: var(--font-size-small);
+ border-top: 1px solid var(--border-color);
+ margin-left: -2rem;
+ margin-right: -2rem;
+ padding: calc(var(--spacer) / 4) var(--spacer);
+ text-align: center;
+ color: var(--color-secondary);
+}
+
+.slippage strong {
+ font-weight: var(--font-weight-base);
+ color: var(--font-color-heading);
+}
+
+.title {
+ font-family: var(--font-family-base);
+ font-weight: var(--font-weight-base);
+ font-size: var(--font-size-mini);
+ text-align: center;
+ margin-bottom: calc(var(--spacer) / 4);
+ color: var(--color-secondary);
+}
+
+.slippage select {
+ width: fit-content;
+ display: inline-block;
+ margin-left: calc(var(--spacer) / 4);
+ margin-right: calc(var(--spacer) / 4);
+}
diff --git a/src/components/organisms/AssetActions/Trade/Slippage.tsx b/src/components/organisms/AssetActions/Trade/Slippage.tsx
new file mode 100644
index 000000000..7adc7bca8
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/Slippage.tsx
@@ -0,0 +1,35 @@
+import { FormikContextType, useFormikContext } from 'formik'
+import React, { ChangeEvent, ReactElement, useEffect, useState } from 'react'
+import { FormTradeData, slippagePresets } from '../../../../models/FormTrade'
+import InputElement from '../../../atoms/Input/InputElement'
+import styles from './Slippage.module.css'
+
+export default function Slippage(): ReactElement {
+ // Connect with form
+ const {
+ setFieldValue,
+ values
+ }: FormikContextType = useFormikContext()
+
+ function handleChange(e: ChangeEvent) {
+ setFieldValue('slippage', e.target.value)
+ }
+
+ return (
+ <>
+
+ Expected price impact
+
+
+ >
+ )
+}
diff --git a/src/components/organisms/AssetActions/Trade/Swap.module.css b/src/components/organisms/AssetActions/Trade/Swap.module.css
new file mode 100644
index 000000000..4909e595a
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/Swap.module.css
@@ -0,0 +1,24 @@
+.swap {
+ margin-top: -2rem;
+}
+
+.swapButton,
+.swapButton:hover {
+ padding: 0;
+ display: block;
+ width: calc(100% + 4rem);
+ text-align: center;
+ margin-left: -2rem;
+ margin-right: -2rem;
+ border-top: 1px solid var(--border-color);
+ border-bottom: 1px solid var(--border-color);
+ padding: calc(var(--spacer) / 3) 0 calc(var(--spacer) / 6) 0;
+}
+
+.swapButton svg {
+ display: inline-block;
+ width: var(--font-size-large);
+ height: var(--font-size-large);
+ fill: var(--brand-pink);
+ transform: rotate(90deg);
+}
diff --git a/src/components/organisms/AssetActions/Trade/Swap.tsx b/src/components/organisms/AssetActions/Trade/Swap.tsx
new file mode 100644
index 000000000..d1b58f939
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/Swap.tsx
@@ -0,0 +1,145 @@
+import React, { ReactElement, useEffect, useState } from 'react'
+import { useOcean } from '@oceanprotocol/react'
+import { BestPrice, DDO } from '@oceanprotocol/lib'
+import styles from './Swap.module.css'
+import TradeInput from './TradeInput'
+import Button from '../../../atoms/Button'
+import { ReactComponent as Arrow } from '../../../../images/arrow.svg'
+import { FormikContextType, useFormikContext } from 'formik'
+import TokenBalance from '../../../../@types/TokenBalance'
+import Output from './Output'
+import Slippage from './Slippage'
+import { FormTradeData, TradeItem } from '../../../../models/FormTrade'
+
+export default function Swap({
+ ddo,
+ maxDt,
+ maxOcean,
+ balance,
+ price,
+ setMaximumDt,
+ setMaximumOcean
+}: {
+ ddo: DDO
+ maxDt: number
+ maxOcean: number
+ balance: TokenBalance
+ price: BestPrice
+ setMaximumDt: (value: number) => void
+ setMaximumOcean: (value: number) => void
+}): ReactElement {
+ const { ocean } = useOcean()
+ const [oceanItem, setOceanItem] = useState({
+ amount: 0,
+ token: 'OCEAN',
+ maxAmount: 0
+ })
+ const [dtItem, setDtItem] = useState({
+ amount: 0,
+ token: ddo.dataTokenInfo.symbol,
+ maxAmount: 0
+ })
+
+ const {
+ setFieldValue,
+ values,
+ setErrors,
+ validateForm
+ }: FormikContextType = useFormikContext()
+
+ useEffect(() => {
+ if (!ddo || !balance || !values || !price) return
+
+ async function calculateMaximum() {
+ const dtAmount = values.type === 'buy' ? maxDt : balance.datatoken
+ const oceanAmount = values.type === 'buy' ? balance.ocean : maxOcean
+
+ const maxBuyOcean = await ocean.pool.getOceanReceived(
+ price.address,
+ dtAmount.toString()
+ )
+ const maxBuyDt = await ocean.pool.getDTReceived(
+ price.address,
+ oceanAmount.toString()
+ )
+
+ const maximumDt =
+ values.type === 'buy'
+ ? Number(dtAmount) > Number(maxBuyDt)
+ ? Number(maxBuyDt)
+ : Number(dtAmount)
+ : Number(dtAmount) > balance.datatoken
+ ? balance.datatoken
+ : Number(dtAmount)
+
+ const maximumOcean =
+ values.type === 'sell'
+ ? Number(oceanAmount) > Number(maxBuyOcean)
+ ? Number(maxBuyOcean)
+ : Number(oceanAmount)
+ : Number(oceanAmount) > balance.ocean
+ ? balance.ocean
+ : Number(oceanAmount)
+
+ setMaximumDt(maximumDt)
+ setMaximumOcean(maximumOcean)
+ setOceanItem({
+ ...oceanItem,
+ amount: oceanAmount,
+ maxAmount: maximumOcean
+ })
+ setDtItem({
+ ...dtItem,
+ amount: dtAmount,
+ maxAmount: maximumDt
+ })
+ }
+ calculateMaximum()
+ }, [ddo, maxOcean, maxDt, balance, price?.value, values.type])
+
+ const switchTokens = () => {
+ setFieldValue('type', values.type === 'buy' ? 'sell' : 'buy')
+ // don't reset form because we don't want to reset type
+ setFieldValue('datatoken', 0)
+ setFieldValue('ocean', 0)
+ setErrors({})
+ }
+
+ const handleValueChange = async (name: string, value: number) => {
+ const newValue =
+ name === 'ocean'
+ ? values.type === 'sell'
+ ? await ocean.pool.getDTNeeded(price.address, value.toString())
+ : await ocean.pool.getDTReceived(price.address, value.toString())
+ : values.type === 'sell'
+ ? await ocean.pool.getOceanReceived(price.address, value.toString())
+ : await ocean.pool.getOceanNeeded(price.address, value.toString())
+
+ setFieldValue(name === 'ocean' ? 'datatoken' : 'ocean', newValue)
+ validateForm()
+ }
+
+ return (
+
+ )
+}
diff --git a/src/components/organisms/AssetActions/Trade/TradeInput.module.css b/src/components/organisms/AssetActions/Trade/TradeInput.module.css
new file mode 100644
index 000000000..65dd567a0
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/TradeInput.module.css
@@ -0,0 +1,35 @@
+.tradeInput {
+ position: relative;
+ padding: var(--spacer) calc(var(--spacer) * 2);
+ margin-left: -2rem;
+ margin-right: -2rem;
+ background: var(--background-highlight);
+}
+
+.tradeInput input {
+ text-align: center;
+}
+
+.tradeInput div[class*='field'] {
+ margin-bottom: 0;
+}
+
+.tradeInput div[class*='prefix'] {
+ min-width: 6.5rem;
+ width: fit-content;
+ justify-content: center;
+}
+
+.label {
+ font-family: var(--font-family-heading);
+ font-size: var(--font-size-base);
+ text-align: center;
+ display: block;
+}
+
+.buttonMax {
+ position: absolute;
+ font-size: var(--font-size-mini);
+ bottom: calc(var(--spacer) / 2);
+ right: calc(var(--spacer) * 2);
+}
diff --git a/src/components/organisms/AssetActions/Trade/TradeInput.tsx b/src/components/organisms/AssetActions/Trade/TradeInput.tsx
new file mode 100644
index 000000000..7f033cfce
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/TradeInput.tsx
@@ -0,0 +1,86 @@
+import React, { ChangeEvent, ReactElement } from 'react'
+import styles from './TradeInput.module.css'
+
+import {
+ Field,
+ FieldInputProps,
+ FormikContextType,
+ useFormikContext
+} from 'formik'
+
+import { useOcean } from '@oceanprotocol/react'
+import Input from '../../../atoms/Input'
+import Button from '../../../atoms/Button'
+import UserLiquidity from '../../../atoms/UserLiquidity'
+import { FormTradeData, TradeItem } from '../../../../models/FormTrade'
+
+export default function TradeInput({
+ name,
+ item,
+ handleValueChange
+}: {
+ name: string
+ item: TradeItem
+ handleValueChange: (name: string, value: number) => void
+}): ReactElement {
+ const { ocean } = useOcean()
+
+ // Connect with form
+ const {
+ handleChange,
+ setFieldValue,
+ validateForm,
+ values
+ }: FormikContextType = useFormikContext()
+
+ const isTopField =
+ (name === 'ocean' && values.type === 'buy') ||
+ (name === 'datatoken' && values.type === 'sell')
+ const titleAvailable = isTopField ? `Balance` : `Available from pool`
+ const titleMaximum = isTopField ? `Maximum to spend` : `Maximum to receive`
+
+ return (
+
+ )
+}
diff --git a/src/components/organisms/AssetActions/Trade/index.tsx b/src/components/organisms/AssetActions/Trade/index.tsx
new file mode 100644
index 000000000..c97736d31
--- /dev/null
+++ b/src/components/organisms/AssetActions/Trade/index.tsx
@@ -0,0 +1,69 @@
+import React, { ReactElement, useEffect, useState } from 'react'
+import { useOcean, useMetadata } from '@oceanprotocol/react'
+import { DDO } from '@oceanprotocol/lib'
+import FormTrade from './FormTrade'
+import TokenBalance from '../../../../@types/TokenBalance'
+
+const refreshInterval = 6000 // 6 sec, if the interval is bellow 3-5 seconds the price will be 0 all the time
+
+export default function Trade({ ddo }: { ddo: DDO }): ReactElement {
+ const { ocean, balance, accountId, networkId, refreshBalance } = useOcean()
+ const [tokenBalance, setTokenBalance] = useState()
+ const { price, refreshPrice } = useMetadata(ddo)
+ const [maxDt, setMaxDt] = useState(0)
+ const [maxOcean, setMaxOcean] = useState(0)
+
+ // Get datatoken balance, and combine with OCEAN balance from hooks into one object
+ useEffect(() => {
+ if (!ocean || !balance?.ocean || !accountId || !ddo?.dataToken) return
+
+ async function getTokenBalance() {
+ const dtBalance = await ocean.datatokens.balance(ddo.dataToken, accountId)
+ setTokenBalance({
+ ocean: Number(balance.ocean),
+ datatoken: Number(dtBalance)
+ })
+ }
+ getTokenBalance()
+ }, [balance.ocean, ocean, accountId, ddo.dataToken])
+
+ // Re-fetch price & balance periodically, triggering re-calculation of everything
+ useEffect(() => {
+ if (!ocean || !networkId || !accountId) return
+
+ const interval = setInterval(async () => {
+ refreshPrice()
+ refreshBalance()
+ }, refreshInterval)
+
+ return () => clearInterval(interval)
+ }, [ocean, ddo, networkId, accountId, refreshPrice, refreshBalance])
+
+ // Get maximum amount for either OCEAN or datatoken
+ useEffect(() => {
+ if (!ocean || !price || price.value === 0) return
+
+ async function getMaximum() {
+ const maxTokensInPool = await ocean.pool.getDTMaxBuyQuantity(
+ price.address
+ )
+ setMaxDt(Number(maxTokensInPool))
+
+ const maxOceanInPool = await ocean.pool.getOceanMaxBuyQuantity(
+ price.address
+ )
+ setMaxOcean(Number(maxOceanInPool))
+ }
+ getMaximum()
+ }, [ocean, balance.ocean, price])
+
+ return (
+
+ )
+}
diff --git a/src/components/organisms/AssetActions/index.module.css b/src/components/organisms/AssetActions/index.module.css
index b841e2570..f0bd5fab7 100644
--- a/src/components/organisms/AssetActions/index.module.css
+++ b/src/components/organisms/AssetActions/index.module.css
@@ -5,8 +5,8 @@
padding: 0;
}
-.hasTokens {
+.help {
font-size: var(--font-size-mini);
color: var(--color-secondary);
- margin-top: calc(var(--spacer) / 12);
+ margin-top: calc(var(--spacer) / 3);
}
diff --git a/src/components/organisms/AssetActions/index.tsx b/src/components/organisms/AssetActions/index.tsx
index 900cf3dfb..1bc34c5ec 100644
--- a/src/components/organisms/AssetActions/index.tsx
+++ b/src/components/organisms/AssetActions/index.tsx
@@ -7,6 +7,7 @@ import Tabs from '../../atoms/Tabs'
import { useOcean, useMetadata } from '@oceanprotocol/react'
import compareAsBN from '../../../utils/compareAsBN'
import Pool from './Pool'
+import Trade from './Trade'
export default function AssetActions({ ddo }: { ddo: DDO }): ReactElement {
const { ocean, balance, accountId } = useOcean()
@@ -74,10 +75,16 @@ export default function AssetActions({ ddo }: { ddo: DDO }): ReactElement {
const hasPool = ddo.price?.type === 'pool'
hasPool &&
- tabs.push({
- title: 'Pool',
- content:
- })
+ tabs.push(
+ {
+ title: 'Pool',
+ content:
+ },
+ {
+ title: 'Trade',
+ content:
+ }
+ )
return
}
diff --git a/src/components/templates/Search/utils.ts b/src/components/templates/Search/utils.ts
index 13a379bde..cdb47f963 100644
--- a/src/components/templates/Search/utils.ts
+++ b/src/components/templates/Search/utils.ts
@@ -71,7 +71,6 @@ export async function getResults(
page,
offset
)
- console.log(searchQuery)
const queryResult = await metadataCache.queryMetadata(searchQuery)
return queryResult
diff --git a/src/global/styles.css b/src/global/styles.css
index 58d73fb32..8c5d89db3 100644
--- a/src/global/styles.css
+++ b/src/global/styles.css
@@ -122,8 +122,8 @@ ul li {
}
::selection {
- background: var(--brand-black);
- color: var(--brand-white);
+ background: var(--font-color-heading);
+ color: var(--background-body);
}
form,
diff --git a/src/images/arrow.svg b/src/images/arrow.svg
new file mode 100644
index 000000000..bea75d205
--- /dev/null
+++ b/src/images/arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/models/FormTrade.ts b/src/models/FormTrade.ts
new file mode 100644
index 000000000..e3fa55d14
--- /dev/null
+++ b/src/models/FormTrade.ts
@@ -0,0 +1,24 @@
+import TokenBalance from '../@types/TokenBalance'
+
+export interface FormTradeData extends TokenBalance {
+ // in reference to datatoken, buy = swap from ocean to dt ( buy dt) , sell = swap from dt to ocean (sell dt)
+ type: 'buy' | 'sell'
+ slippage: string
+}
+
+export interface TradeItem {
+ amount: number
+ token: string
+ maxAmount: number
+}
+
+export const initialValues: FormTradeData = {
+ ocean: undefined,
+ datatoken: undefined,
+ type: 'buy',
+ slippage: '5'
+}
+
+export const slippagePresets = ['5', '10', '15', '25', '50']
+
+// validationSchema lives in components/organisms/AssetActions/Trade/FormTrade.tsx
diff --git a/src/providers/Prices.tsx b/src/providers/Prices.tsx
index 53a961a81..3a8d88216 100644
--- a/src/providers/Prices.tsx
+++ b/src/providers/Prices.tsx
@@ -43,7 +43,7 @@ export default function PricesProvider({
// Fetch new prices periodically with swr
useSWR(url, fetchData, {
- refreshInterval: 30000, // 30 sec.
+ refreshInterval: 60000, // 60 sec.
onSuccess
})