1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

Merge branch 'main' into feature/compute

This commit is contained in:
Matthias Kretschmann 2021-03-26 12:24:09 +01:00
commit 6d14181d17
Signed by: m
GPG Key ID: 606EEEF3C479A91F
14 changed files with 195 additions and 58 deletions

View File

@ -5,3 +5,5 @@ GATSBY_NETWORK="rinkeby"
#GATSBY_MARKET_FEE_ADDRESS="0xxx" #GATSBY_MARKET_FEE_ADDRESS="0xxx"
#GATSBY_ANALYTICS_ID="xxx" #GATSBY_ANALYTICS_ID="xxx"
#GATSBY_PORTIS_ID="xxx" #GATSBY_PORTIS_ID="xxx"
#GATSBY_ALLOW_FIXED_PRICING="true"
#GATSBY_ALLOW_DYNAMIC_PRICING="true"

View File

@ -38,5 +38,10 @@ module.exports = {
}, },
// Wallets // Wallets
portisId: process.env.GATSBY_PORTIS_ID || 'xxx' portisId: process.env.GATSBY_PORTIS_ID || 'xxx',
// Used to show or hide the fixed and dynamic price options
// tab to publishers during the price creation.
allowFixedPricing: process.env.GATSBY_ALLOW_FIXED_PRICING || 'true',
allowDynamicPricing: process.env.GATSBY_ALLOW_DYNAMIC_PRICING || 'true'
} }

View File

@ -75,3 +75,12 @@
margin-top: calc(var(--spacer) / 4); margin-top: calc(var(--spacer) / 4);
min-width: 6rem; min-width: 6rem;
} }
.walletInfo{
display: flex;
flex-direction: column;
}
.walletInfo button{
margin-top: calc(var(--spacer) / 5) !important;
}

View File

@ -8,10 +8,11 @@ import Conversion from '../../atoms/Price/Conversion'
import { formatCurrency } from '@coingecko/cryptoformat' import { formatCurrency } from '@coingecko/cryptoformat'
import { useUserPreferences } from '../../../providers/UserPreferences' import { useUserPreferences } from '../../../providers/UserPreferences'
import { useWeb3 } from '../../../providers/Web3' import { useWeb3 } from '../../../providers/Web3'
import { Logger } from '@oceanprotocol/lib'
export default function Details(): ReactElement { export default function Details(): ReactElement {
const { web3Provider, connect, logout, networkData, networkId } = useWeb3() const { web3Provider, connect, logout, networkData } = useWeb3()
const { balance } = useOcean() const { balance, config } = useOcean()
const { locale } = useUserPreferences() const { locale } = useUserPreferences()
const [providerInfo, setProviderInfo] = useState<IProviderInfo>() const [providerInfo, setProviderInfo] = useState<IProviderInfo>()
@ -26,6 +27,39 @@ export default function Details(): ReactElement {
setProviderInfo(providerInfo) setProviderInfo(providerInfo)
}, [web3Provider]) }, [web3Provider])
async function addOceanToWallet() {
const tokenMetadata = {
type: 'ERC20',
options: {
address: config.oceanTokenAddress,
symbol: config.oceanTokenSymbol,
decimals: 18,
image:
'https://raw.githubusercontent.com/oceanprotocol/art/main/logo/token.png'
}
}
web3Provider.sendAsync(
{
method: 'wallet_watchAsset',
params: tokenMetadata,
id: Math.round(Math.random() * 100000)
},
(err: string, added: any) => {
if (err || 'error' in added) {
Logger.error(
`Couldn't add ${tokenMetadata.options.symbol} (${
tokenMetadata.options.address
}) to MetaMask, error: ${err || added.error}`
)
} else {
Logger.log(
`Added ${tokenMetadata.options.symbol} (${tokenMetadata.options.address}) to MetaMask`
)
}
}
)
}
useEffect(() => { useEffect(() => {
if (!networkData) return if (!networkData) return
@ -48,11 +82,7 @@ export default function Details(): ReactElement {
{Object.entries(balance).map(([key, value]) => ( {Object.entries(balance).map(([key, value]) => (
<li className={styles.balance} key={key}> <li className={styles.balance} key={key}>
<span className={styles.symbol}> <span className={styles.symbol}>
{key === 'eth' {key === 'eth' ? mainCurrency : config.oceanTokenSymbol}
? mainCurrency
: key === 'ocean' && networkId === 137
? 'mOCEAN'
: key.toUpperCase()}
</span>{' '} </span>{' '}
{formatCurrency(Number(value), '', locale, false, { {formatCurrency(Number(value), '', locale, false, {
significantFigures: 4 significantFigures: 4
@ -62,9 +92,11 @@ export default function Details(): ReactElement {
))} ))}
<li className={styles.actions}> <li className={styles.actions}>
<span title="Connected provider"> <div title="Connected provider" className={styles.walletInfo}>
<span>
<img className={styles.walletLogo} src={providerInfo?.logo} /> <img className={styles.walletLogo} src={providerInfo?.logo} />
{providerInfo?.name} {providerInfo?.name}
</span>
{/* {providerInfo?.name === 'Portis' && ( {/* {providerInfo?.name === 'Portis' && (
<InputElement <InputElement
name="network" name="network"
@ -75,7 +107,18 @@ export default function Details(): ReactElement {
onChange={handlePortisNetworkChange} onChange={handlePortisNetworkChange}
/> />
)} */} )} */}
</span> {providerInfo?.name === 'MetaMask' && (
<Button
style="text"
size="small"
onClick={() => {
addOceanToWallet()
}}
>
{`Add ${config.oceanTokenSymbol}`}
</Button>
)}
</div>
<p> <p>
{providerInfo?.name === 'Portis' && ( {providerInfo?.name === 'Portis' && (
<Button <Button

View File

@ -1,4 +1,4 @@
import React, { ReactElement } from 'react' import React, { ReactElement, useState } from 'react'
import Account from './Account' import Account from './Account'
import Details from './Details' import Details from './Details'
import Tooltip from '../../atoms/Tooltip' import Tooltip from '../../atoms/Tooltip'

View File

@ -8,6 +8,7 @@
.output p { .output p {
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
margin-bottom: calc(var(--spacer) / 8); margin-bottom: calc(var(--spacer) / 8);
font-size: var(--font-size-small);
} }
.output div:first-child [class*='token'] { .output div:first-child [class*='token'] {

View File

@ -60,3 +60,11 @@
.output figure[class*='pool shares'] { .output figure[class*='pool shares'] {
display: none; display: none;
} }
.output p {
font-size: var(--font-size-small);
}
.slippage {
composes: slippage from '../Trade/Slippage.module.css';
}

View File

@ -18,6 +18,7 @@ import { getMaxPercentRemove } from './utils'
import { graphql, useStaticQuery } from 'gatsby' import { graphql, useStaticQuery } from 'gatsby'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import UserLiquidity from '../../../atoms/UserLiquidity' import UserLiquidity from '../../../atoms/UserLiquidity'
import InputElement from '../../../atoms/Input/InputElement'
import { useOcean } from '../../../../providers/Ocean' import { useOcean } from '../../../../providers/Ocean'
import { useWeb3 } from '../../../../providers/Web3' import { useWeb3 } from '../../../../providers/Web3'
@ -64,6 +65,7 @@ export default function Remove({
const data = useStaticQuery(contentQuery) const data = useStaticQuery(contentQuery)
const content = data.content.edges[0].node.childContentJson.pool.remove const content = data.content.edges[0].node.childContentJson.pool.remove
const slippagePresets = ['5', '10', '15', '25', '50']
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { ocean } = useOcean() const { ocean } = useOcean()
const [amountPercent, setAmountPercent] = useState('0') const [amountPercent, setAmountPercent] = useState('0')
@ -74,23 +76,27 @@ export default function Remove({
const [isAdvanced, setIsAdvanced] = useState(false) const [isAdvanced, setIsAdvanced] = useState(false)
const [isLoading, setIsLoading] = useState<boolean>() const [isLoading, setIsLoading] = useState<boolean>()
const [txId, setTxId] = useState<string>() const [txId, setTxId] = useState<string>()
const [slippage, setSlippage] = useState<string>('5')
const [minOceanAmount, setMinOceanAmount] = useState<string>('0')
const [minDatatokenAmount, setMinDatatokenAmount] = useState<string>('0')
async function handleRemoveLiquidity() { async function handleRemoveLiquidity() {
setIsLoading(true) setIsLoading(true)
try { try {
const result = const result =
isAdvanced === true isAdvanced === true
? await ocean.pool.removePoolLiquidity( ? await ocean.pool.removePoolLiquidity(
accountId, accountId,
poolAddress, poolAddress,
amountPoolShares amountPoolShares,
minDatatokenAmount,
minOceanAmount
) )
: await ocean.pool.removeOceanLiquidity( : await ocean.pool.removeOceanLiquidityWithMinimum(
accountId, accountId,
poolAddress, poolAddress,
amountOcean, amountPoolShares,
amountPoolShares minOceanAmount
) )
setTxId(result?.transactionHash) setTxId(result?.transactionHash)
@ -149,6 +155,23 @@ export default function Remove({
totalPoolTokens totalPoolTokens
]) ])
async function calculateAmountOfOceansRemoved(amountPoolShares: string) {
const oceanAmount = await ocean.pool.getOceanRemovedforPoolShares(
poolAddress,
amountPoolShares
)
setAmountOcean(oceanAmount)
}
useEffect(() => {
const minOceanAmount =
(Number(amountOcean) * (100 - Number(slippage))) / 100
const minDatatokenAmount =
(Number(amountDatatoken) * (100 - Number(slippage))) / 100
setMinOceanAmount(`${minOceanAmount}`)
setMinDatatokenAmount(`${minDatatokenAmount}`)
}, [slippage, amountOcean, amountDatatoken, isAdvanced])
// Set amountPoolShares based on set slider value // Set amountPoolShares based on set slider value
function handleAmountPercentChange(e: ChangeEvent<HTMLInputElement>) { function handleAmountPercentChange(e: ChangeEvent<HTMLInputElement>) {
setAmountPercent(e.target.value) setAmountPercent(e.target.value)
@ -156,6 +179,7 @@ export default function Remove({
const amountPoolShares = (Number(e.target.value) / 100) * Number(poolTokens) const amountPoolShares = (Number(e.target.value) / 100) * Number(poolTokens)
setAmountPoolShares(`${amountPoolShares}`) setAmountPoolShares(`${amountPoolShares}`)
calculateAmountOfOceansRemoved(`${amountPoolShares}`)
} }
function handleMaxButton(e: ChangeEvent<HTMLInputElement>) { function handleMaxButton(e: ChangeEvent<HTMLInputElement>) {
@ -165,6 +189,7 @@ export default function Remove({
const amountPoolShares = const amountPoolShares =
(Number(amountMaxPercent) / 100) * Number(poolTokens) (Number(amountMaxPercent) / 100) * Number(poolTokens)
setAmountPoolShares(`${amountPoolShares}`) setAmountPoolShares(`${amountPoolShares}`)
calculateAmountOfOceansRemoved(`${amountPoolShares}`)
} }
function handleAdvancedButton(e: FormEvent<HTMLButtonElement>) { function handleAdvancedButton(e: FormEvent<HTMLButtonElement>) {
@ -174,19 +199,25 @@ export default function Remove({
setAmountPoolShares('0') setAmountPoolShares('0')
setAmountPercent('0') setAmountPercent('0')
setAmountOcean('0') setAmountOcean('0')
setSlippage('5')
setMinOceanAmount('0')
setMinDatatokenAmount('0')
if (isAdvanced === true) { if (isAdvanced === true) {
setAmountDatatoken('0') setAmountDatatoken('0')
} }
} }
function handleSlippageChange(e: ChangeEvent<HTMLSelectElement>) {
setSlippage(e.target.value)
}
return ( return (
<div className={styles.remove}> <div className={styles.remove}>
<Header title={content.title} backAction={() => setShowRemove(false)} /> <Header title={content.title} backAction={() => setShowRemove(false)} />
<form className={styles.removeInput}> <form className={styles.removeInput}>
<UserLiquidity amount={poolTokens} symbol="pool shares" /> <UserLiquidity amount={poolTokens} symbol="pool shares" />
<div className={styles.range}> <div className={styles.range}>
<h3>{amountPercent}%</h3> <h3>{amountPercent}%</h3>
<div className={styles.slider}> <div className={styles.slider}>
@ -220,21 +251,36 @@ export default function Remove({
</Button> </Button>
</div> </div>
</form> </form>
<div className={styles.output}> <div className={styles.output}>
<div> <div>
<p>{content.output.titleIn}</p> <p>{content.output.titleIn}</p>
<Token symbol="pool shares" balance={amountPoolShares} noIcon /> <Token symbol="pool shares" balance={amountPoolShares} noIcon />
</div> </div>
<div> <div>
<p>{content.output.titleOut}</p> <p>{content.output.titleOut} minimum</p>
<Token symbol="OCEAN" balance={amountOcean} /> {isAdvanced === true ? (
{isAdvanced === true && ( <>
<Token symbol={dtSymbol} balance={amountDatatoken} /> <Token symbol="OCEAN" balance={minOceanAmount} />
<Token symbol={dtSymbol} balance={minDatatokenAmount} />
</>
) : (
<Token symbol="OCEAN" balance={minOceanAmount} />
)} )}
</div> </div>
</div> </div>
<div className={styles.slippage}>
<strong>Expected price impact</strong>
<InputElement
name="slippage"
type="select"
size="mini"
postfix="%"
sortOptions={false}
options={slippagePresets}
value={slippage}
onChange={handleSlippageChange}
/>
</div>
<Actions <Actions
isLoading={isLoading} isLoading={isLoading}
loaderMessage="Removing Liquidity..." loaderMessage="Removing Liquidity..."

View File

@ -1,6 +1,7 @@
.output { .output {
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);
padding: var(--spacer); padding: var(--spacer);
padding-bottom: calc(var(--spacer) / 1.5);
display: grid; display: grid;
gap: var(--spacer); gap: var(--spacer);
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
@ -11,6 +12,7 @@
.output p { .output p {
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
margin-bottom: calc(var(--spacer) / 8); margin-bottom: calc(var(--spacer) / 8);
font-size: var(--font-size-small);
} }
.output [class*='token'] { .output [class*='token'] {

View File

@ -9,6 +9,7 @@ import { PriceOptionsMarket } from '../../../../../@types/MetaData'
import Button from '../../../../atoms/Button' import Button from '../../../../atoms/Button'
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import FormHelp from '../../../../atoms/Input/Help' import FormHelp from '../../../../atoms/Input/Help'
import { useSiteMetadata } from '../../../../../hooks/useSiteMetadata'
export default function FormPricing({ export default function FormPricing({
ddo, ddo,
@ -20,6 +21,7 @@ export default function FormPricing({
content: any content: any
}): ReactElement { }): ReactElement {
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { appConfig } = useSiteMetadata()
// Connect with form // Connect with form
const { values, setFieldValue, submitForm } = useFormikContext() const { values, setFieldValue, submitForm } = useFormikContext()
@ -49,15 +51,19 @@ export default function FormPricing({
}, [price, oceanAmount, weightOnOcean, weightOnDataToken, type]) }, [price, oceanAmount, weightOnOcean, weightOnDataToken, type])
const tabs = [ const tabs = [
{ appConfig.allowFixedPricing === 'true'
? {
title: content.fixed.title, title: content.fixed.title,
content: <Fixed content={content.fixed} ddo={ddo} /> content: <Fixed content={content.fixed} ddo={ddo} />
}, }
{ : undefined,
appConfig.allowDynamicPricing === 'true'
? {
title: content.dynamic.title, title: content.dynamic.title,
content: <Dynamic content={content.dynamic} ddo={ddo} /> content: <Dynamic content={content.dynamic} ddo={ddo} />
} }
] : undefined
].filter((tab) => tab !== undefined)
return ( return (
<> <>

View File

@ -22,6 +22,8 @@ const query = graphql`
marketFeeAddress marketFeeAddress
currencies currencies
portisId portisId
allowFixedPricing
allowDynamicPricing
} }
} }
} }

View File

@ -45,6 +45,7 @@ const freQuery = gql`
query FrePrice($datatoken: String) { query FrePrice($datatoken: String) {
fixedRateExchanges(orderBy: id, where: { datatoken: $datatoken }) { fixedRateExchanges(orderBy: id, where: { datatoken: $datatoken }) {
rate rate
id
} }
} }
` `
@ -79,7 +80,7 @@ function AssetProvider({
data: frePrice data: frePrice
} = useQuery<FrePrice>(freQuery, { } = useQuery<FrePrice>(freQuery, {
variables, variables,
skip: true skip: false
}) })
const { const {
refetch: refetchPool, refetch: refetchPool,
@ -87,31 +88,43 @@ function AssetProvider({
data: poolPrice data: poolPrice
} = useQuery<PoolPrice>(poolQuery, { } = useQuery<PoolPrice>(poolQuery, {
variables, variables,
skip: true skip: false
}) })
useEffect(() => { // this is not working as expected, thus we need to fetch both pool and fre
if (!ddo || !variables) return // useEffect(() => {
if (ddo.price.type === 'exchange') { // if (!ddo || !variables || variables === '') return
refetchFre(variables)
startPollingFre(refreshInterval) // if (ddo.price.type === 'exchange') {
} else { // refetchFre(variables)
refetchPool(variables) // startPollingFre(refreshInterval)
startPollingPool(refreshInterval) // } else {
} // refetchPool(variables)
}, [ddo, variables]) // startPollingPool(refreshInterval)
// }
// }, [ddo, variables])
useEffect(() => { useEffect(() => {
if (!frePrice || frePrice.fixedRateExchanges.length === 0) return if (
price.value = frePrice.fixedRateExchanges[0].rate !frePrice ||
setPrice(price) frePrice.fixedRateExchanges.length === 0 ||
price.type !== 'exchange'
)
return
setPrice((prevState) => ({
...prevState,
value: frePrice.fixedRateExchanges[0].rate,
address: frePrice.fixedRateExchanges[0].id
}))
}, [frePrice]) }, [frePrice])
useEffect(() => { useEffect(() => {
if (!poolPrice || poolPrice.pools.length === 0) return if (!poolPrice || poolPrice.pools.length === 0 || price.type !== 'pool')
price.value = poolPrice.pools[0].spotPrice return
price.value = 3222222 setPrice((prevState) => ({
setPrice(price) ...prevState,
value: poolPrice.pools[0].spotPrice
}))
}, [poolPrice]) }, [poolPrice])
const fetchDdo = async (token?: CancelToken) => { const fetchDdo = async (token?: CancelToken) => {

View File

@ -21,7 +21,7 @@ const refreshInterval = 20000 // 20 sec.
interface OceanProviderValue { interface OceanProviderValue {
ocean: Ocean ocean: Ocean
config: ConfigHelperConfig | Config config: ConfigHelperConfig
account: Account account: Account
balance: UserBalance balance: UserBalance
connect: (config?: Config) => Promise<void> connect: (config?: Config) => Promise<void>

View File

@ -1,4 +1,4 @@
import { Account, Config, Logger, Ocean } from '@oceanprotocol/lib' import { Account, Logger, Ocean } from '@oceanprotocol/lib'
import contractAddresses from '@oceanprotocol/contracts/artifacts/address.json' import contractAddresses from '@oceanprotocol/contracts/artifacts/address.json'
import { import {
ConfigHelper, ConfigHelper,
@ -10,11 +10,11 @@ import { UserBalance } from '../@types/TokenBalance'
export function getOceanConfig( export function getOceanConfig(
network: ConfigHelperNetworkName | ConfigHelperNetworkId network: ConfigHelperNetworkName | ConfigHelperNetworkId
): Config { ): ConfigHelperConfig {
return new ConfigHelper().getConfig( return new ConfigHelper().getConfig(
network, network,
process.env.GATSBY_INFURA_PROJECT_ID process.env.GATSBY_INFURA_PROJECT_ID
) ) as ConfigHelperConfig
} }
export function getDevelopmentConfig(): Partial<ConfigHelperConfig> { export function getDevelopmentConfig(): Partial<ConfigHelperConfig> {