mirror of
https://github.com/oceanprotocol/market.git
synced 2024-11-15 09:44:53 +01:00
Merge branch 'main' into feature/history-compute
Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>
This commit is contained in:
commit
6db26e3a69
@ -2,6 +2,5 @@
|
|||||||
GATSBY_NETWORK="rinkeby"
|
GATSBY_NETWORK="rinkeby"
|
||||||
|
|
||||||
#GATSBY_INFURA_PROJECT_ID="xxx"
|
#GATSBY_INFURA_PROJECT_ID="xxx"
|
||||||
#GATSBY_METADATA_STORE_URI="xxx"
|
#GATSBY_METADATA_CACHE_URI="xxx"
|
||||||
#GATSBY_MARKET_FEE_ADDRESS="0xxx"
|
#GATSBY_MARKET_FEE_ADDRESS="0xxx"
|
||||||
#GATSBY_MARKET_FEE_AMOUNT="xxx"
|
|
@ -1,11 +1,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
network: process.env.GATSBY_NETWORK || 'rinkeby',
|
network: process.env.GATSBY_NETWORK || 'rinkeby',
|
||||||
infuraProjectId: process.env.GATSBY_INFURA_PROJECT_ID || 'xxx',
|
infuraProjectId: process.env.GATSBY_INFURA_PROJECT_ID || 'xxx',
|
||||||
metadataStoreUri: process.env.GATSBY_METADATA_STORE_URI,
|
metadataCacheUri: process.env.GATSBY_METADATA_CACHE_URI,
|
||||||
|
// The ETH address the marketplace fee will be sent to.
|
||||||
marketFeeAddress:
|
marketFeeAddress:
|
||||||
process.env.GATSBY_MARKET_FEE_ADDRESS ||
|
process.env.GATSBY_MARKET_FEE_ADDRESS ||
|
||||||
'0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7',
|
'0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7',
|
||||||
marketFeeAmount: process.env.GATSBY_MARKET_FEE_AMOUNT || '0.1', // in %
|
|
||||||
// Used for conversion display, can be whatever coingecko API supports
|
// Used for conversion display, can be whatever coingecko API supports
|
||||||
// see: https://api.coingecko.com/api/v3/simple/supported_vs_currencies
|
// see: https://api.coingecko.com/api/v3/simple/supported_vs_currencies
|
||||||
currencies: ['EUR', 'USD', 'ETH', 'BTC']
|
currencies: ['EUR', 'USD', 'ETH', 'BTC']
|
||||||
|
26
content/price.json
Normal file
26
content/price.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"pool": {
|
||||||
|
"tooltips": {
|
||||||
|
"price": "Explain how this price is determined...",
|
||||||
|
"liquidity": "Explain what this represents, advantage of providing liquidity..."
|
||||||
|
},
|
||||||
|
"add": {
|
||||||
|
"title": "Add Liquidity",
|
||||||
|
"output": {
|
||||||
|
"titleIn": "You will receive",
|
||||||
|
"titleOut": "You will earn"
|
||||||
|
},
|
||||||
|
"action": "Approve & Supply"
|
||||||
|
},
|
||||||
|
"remove": {
|
||||||
|
"title": "Remove Liquidity",
|
||||||
|
"simple": "Set the amount of your pool shares to spend. You will get the equivalent value in OCEAN, limited to maximum amount for pool protection. If you have Datatokens left in your wallet, you can add them to the pool to increase the maximum amount.",
|
||||||
|
"advanced": "Set the amount of your pool shares to spend. You will get OCEAN and Datatokens equivalent to your pool share, without any limit. You can use these Datatokens in other DeFi tools.",
|
||||||
|
"output": {
|
||||||
|
"titleIn": "You will spend",
|
||||||
|
"titleOut": "You will receive"
|
||||||
|
},
|
||||||
|
"action": "Approve & Remove"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4938
package-lock.json
generated
4938
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
66
package.json
66
package.json
@ -22,15 +22,15 @@
|
|||||||
"@coingecko/cryptoformat": "^0.4.2",
|
"@coingecko/cryptoformat": "^0.4.2",
|
||||||
"@loadable/component": "5.13.1",
|
"@loadable/component": "5.13.1",
|
||||||
"@oceanprotocol/art": "^3.0.0",
|
"@oceanprotocol/art": "^3.0.0",
|
||||||
"@oceanprotocol/lib": "^0.5.6",
|
"@oceanprotocol/lib": "^0.6.5",
|
||||||
"@oceanprotocol/react": "^0.1.2",
|
"@oceanprotocol/react": "^0.2.2",
|
||||||
"@oceanprotocol/typographies": "^0.1.0",
|
"@oceanprotocol/typographies": "^0.1.0",
|
||||||
"@sindresorhus/slugify": "^1.0.0",
|
"@sindresorhus/slugify": "^1.0.0",
|
||||||
"@tippyjs/react": "^4.2.0",
|
"@tippyjs/react": "^4.2.0",
|
||||||
"@toruslabs/torus-embed": "^1.8.5",
|
"@toruslabs/torus-embed": "^1.8.6",
|
||||||
"@types/classnames": "^2.2.10",
|
"@types/classnames": "^2.2.10",
|
||||||
"@vercel/node": "^1.8.3",
|
"@vercel/node": "^1.8.4",
|
||||||
"@walletconnect/web3-provider": "^1.2.2",
|
"@walletconnect/web3-provider": "^1.3.1",
|
||||||
"axios": "^0.20.0",
|
"axios": "^0.20.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"date-fns": "^2.16.1",
|
"date-fns": "^2.16.1",
|
||||||
@ -39,29 +39,29 @@
|
|||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"ethereum-blockies": "github:MyEtherWallet/blockies",
|
"ethereum-blockies": "github:MyEtherWallet/blockies",
|
||||||
"filesize": "^6.1.0",
|
"filesize": "^6.1.0",
|
||||||
"formik": "^2.1.7",
|
"formik": "^2.2.0",
|
||||||
"gatsby": "^2.24.67",
|
"gatsby": "^2.24.80",
|
||||||
"gatsby-image": "^2.4.20",
|
"gatsby-image": "^2.4.21",
|
||||||
"gatsby-plugin-manifest": "^2.4.33",
|
"gatsby-plugin-manifest": "^2.4.35",
|
||||||
"gatsby-plugin-react-helmet": "^3.3.12",
|
"gatsby-plugin-react-helmet": "^3.3.14",
|
||||||
"gatsby-plugin-remove-trailing-slashes": "^2.3.13",
|
"gatsby-plugin-remove-trailing-slashes": "^2.3.13",
|
||||||
"gatsby-plugin-sharp": "^2.6.38",
|
"gatsby-plugin-sharp": "^2.6.42",
|
||||||
"gatsby-plugin-svgr": "^2.0.2",
|
"gatsby-plugin-svgr": "^2.0.2",
|
||||||
"gatsby-plugin-webpack-size": "^1.0.0",
|
"gatsby-plugin-webpack-size": "^1.0.0",
|
||||||
"gatsby-source-filesystem": "^2.3.32",
|
"gatsby-source-filesystem": "^2.3.35",
|
||||||
"gatsby-source-graphql": "^2.7.5",
|
"gatsby-source-graphql": "^2.7.6",
|
||||||
"gatsby-transformer-json": "^2.4.13",
|
"gatsby-transformer-json": "^2.4.14",
|
||||||
"gatsby-transformer-remark": "^2.8.37",
|
"gatsby-transformer-remark": "^2.8.42",
|
||||||
"gatsby-transformer-sharp": "^2.5.16",
|
"gatsby-transformer-sharp": "^2.5.18",
|
||||||
"intersection-observer": "^0.11.0",
|
"intersection-observer": "^0.11.0",
|
||||||
"is-url-superb": "^4.0.0",
|
"is-url-superb": "^4.0.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.omit": "^4.5.0",
|
"lodash.omit": "^4.5.0",
|
||||||
"query-string": "^6.13.5",
|
"query-string": "^6.13.6",
|
||||||
"react": "^16.13.1",
|
"react": "^16.14.0",
|
||||||
"react-data-table-component": "^6.11.5",
|
"react-data-table-component": "^6.11.5",
|
||||||
"react-datepicker": "^3.2.2",
|
"react-datepicker": "^3.3.0",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.14.0",
|
||||||
"react-dotdotdot": "^1.3.1",
|
"react-dotdotdot": "^1.3.1",
|
||||||
"react-dropzone": "^11.2.0",
|
"react-dropzone": "^11.2.0",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
@ -70,7 +70,7 @@
|
|||||||
"react-responsive-modal": "^5.1.1",
|
"react-responsive-modal": "^5.1.1",
|
||||||
"react-spring": "^8.0.27",
|
"react-spring": "^8.0.27",
|
||||||
"react-tabs": "^3.1.1",
|
"react-tabs": "^3.1.1",
|
||||||
"react-toastify": "^6.0.8",
|
"react-toastify": "^6.0.9",
|
||||||
"remove-markdown": "^0.3.0",
|
"remove-markdown": "^0.3.0",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
"slugify": "^1.4.5",
|
"slugify": "^1.4.5",
|
||||||
@ -78,39 +78,39 @@
|
|||||||
"yup": "^0.29.3"
|
"yup": "^0.29.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.11.6",
|
"@babel/core": "^7.12.3",
|
||||||
"@babel/preset-typescript": "^7.10.1",
|
"@babel/preset-typescript": "^7.12.1",
|
||||||
"@storybook/addon-actions": "^6.0.26",
|
"@storybook/addon-actions": "^6.0.26",
|
||||||
"@storybook/addon-storyshots": "^6.0.26",
|
"@storybook/addon-storyshots": "^6.0.26",
|
||||||
"@storybook/react": "^6.0.26",
|
"@storybook/react": "^6.0.26",
|
||||||
"@svgr/webpack": "^5.4.0",
|
"@svgr/webpack": "^5.4.0",
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.0.4",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@types/jest": "^26.0.14",
|
"@types/jest": "^26.0.14",
|
||||||
"@types/loadable__component": "^5.13.1",
|
"@types/loadable__component": "^5.13.1",
|
||||||
"@types/lodash.debounce": "^4.0.3",
|
"@types/lodash.debounce": "^4.0.3",
|
||||||
"@types/lodash.omit": "^4.5.6",
|
"@types/lodash.omit": "^4.5.6",
|
||||||
"@types/node": "^14.11.2",
|
"@types/node": "^14.11.10",
|
||||||
"@types/react": "^16.9.50",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-datepicker": "^3.1.1",
|
"@types/react-datepicker": "^3.1.1",
|
||||||
"@types/react-helmet": "^6.1.0",
|
"@types/react-helmet": "^6.1.0",
|
||||||
"@types/react-paginate": "^6.2.1",
|
"@types/react-paginate": "^6.2.1",
|
||||||
"@types/react-tabs": "^2.3.2",
|
"@types/react-tabs": "^2.3.2",
|
||||||
"@types/remove-markdown": "^0.1.1",
|
"@types/remove-markdown": "^0.1.1",
|
||||||
"@types/shortid": "0.0.29",
|
"@types/shortid": "0.0.29",
|
||||||
"@types/yup": "^0.29.7",
|
"@types/yup": "^0.29.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.3.0",
|
"@typescript-eslint/eslint-plugin": "^4.4.1",
|
||||||
"@typescript-eslint/parser": "^4.3.0",
|
"@typescript-eslint/parser": "^4.4.1",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"babel-preset-react-app": "^9.1.2",
|
"babel-preset-react-app": "^9.1.2",
|
||||||
"eslint": "^7.10.0",
|
"eslint": "^7.11.0",
|
||||||
"eslint-config-oceanprotocol": "^1.5.0",
|
"eslint-config-oceanprotocol": "^1.5.0",
|
||||||
"eslint-config-prettier": "^6.12.0",
|
"eslint-config-prettier": "^6.13.0",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-react": "^7.21.3",
|
"eslint-plugin-react": "^7.21.4",
|
||||||
"eslint-plugin-react-hooks": "^4.1.2",
|
"eslint-plugin-react-hooks": "^4.1.2",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "^26.5.0",
|
"jest": "^26.5.3",
|
||||||
"prettier": "^2.1.2",
|
"prettier": "^2.1.2",
|
||||||
"serve": "^11.3.2",
|
"serve": "^11.3.2",
|
||||||
"source-map-explorer": "^2.5.0",
|
"source-map-explorer": "^2.5.0",
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
transition: 0.2s ease-out;
|
transition: 0.2s ease-out;
|
||||||
min-height: 43px;
|
height: 43px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
display: block;
|
display: block;
|
||||||
@ -49,6 +49,11 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textarea {
|
||||||
|
composes: input;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.select {
|
.select {
|
||||||
composes: input;
|
composes: input;
|
||||||
height: 43px;
|
height: 43px;
|
||||||
@ -179,15 +184,16 @@
|
|||||||
.prefix,
|
.prefix,
|
||||||
.postfix {
|
.postfix {
|
||||||
border: 1px solid var(--brand-grey-lighter);
|
border: 1px solid var(--brand-grey-lighter);
|
||||||
min-height: 43px;
|
height: 43px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: calc(var(--spacer) / 4);
|
padding-left: calc(var(--spacer) / 4);
|
||||||
padding-right: calc(var(--spacer) / 4);
|
padding-right: calc(var(--spacer) / 4);
|
||||||
color: var(--color-secondary);
|
color: var(--brand-grey);
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
transition: border 0.2s ease-out;
|
transition: border 0.2s ease-out;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prefix {
|
.prefix {
|
||||||
@ -204,6 +210,34 @@
|
|||||||
border-color: var(--brand-grey);
|
border-color: var(--brand-grey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type='range'] {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='range']:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='range']::-webkit-slider-thumb,
|
||||||
|
input[type='range']::-moz-range-thumb {
|
||||||
|
appearance: none;
|
||||||
|
background: var(--brand-gradient);
|
||||||
|
border: 2px solid var(--brand-grey-lighter);
|
||||||
|
width: var(--font-size-large);
|
||||||
|
height: var(--font-size-large);
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 2px 9px 0 rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='range']::-webkit-slider-runnable-track,
|
||||||
|
input[type='range']::-moz-range-track {
|
||||||
|
background: var(--brand-grey-lighter);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
height: 0.3rem;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Size modifiers */
|
/* Size modifiers */
|
||||||
|
|
||||||
.small {
|
.small {
|
||||||
|
@ -57,7 +57,12 @@ export default function InputElement({
|
|||||||
)
|
)
|
||||||
case 'textarea':
|
case 'textarea':
|
||||||
return (
|
return (
|
||||||
<textarea name={name} id={name} className={styles.input} {...props} />
|
<textarea
|
||||||
|
name={name}
|
||||||
|
id={name}
|
||||||
|
className={styles.textarea}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
case 'radio':
|
case 'radio':
|
||||||
case 'checkbox':
|
case 'checkbox':
|
||||||
|
@ -13,12 +13,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
font-size: var(--font-size-small);
|
display: inline-block;
|
||||||
color: var(--brand-alert-red);
|
font-size: var(--font-size-mini);
|
||||||
|
line-height: 1.2;
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
color: var(--brand-white);
|
||||||
|
background: var(--brand-alert-red);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
text-align: right;
|
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 85%;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hasError label {
|
.hasError label {
|
||||||
@ -26,7 +32,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hasError input,
|
.hasError input,
|
||||||
|
.hasError input:focus,
|
||||||
.hasError select,
|
.hasError select,
|
||||||
.hasError textarea {
|
.hasError textarea,
|
||||||
|
.hasError [class*='prefix'],
|
||||||
|
.hasError [class*='postfix'] {
|
||||||
border-color: var(--brand-alert-red);
|
border-color: var(--brand-alert-red);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import InputElement from './InputElement'
|
|||||||
import Help from './Help'
|
import Help from './Help'
|
||||||
import Label from './Label'
|
import Label from './Label'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { ErrorMessage } from 'formik'
|
import { ErrorMessage, FieldInputProps } from 'formik'
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
|
|
||||||
const cx = classNames.bind(styles)
|
const cx = classNames.bind(styles)
|
||||||
@ -33,7 +33,7 @@ export interface InputProps {
|
|||||||
max?: string
|
max?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
readOnly?: boolean
|
readOnly?: boolean
|
||||||
field?: any
|
field?: FieldInputProps<any>
|
||||||
form?: any
|
form?: any
|
||||||
prefix?: string | ReactElement
|
prefix?: string | ReactElement
|
||||||
postfix?: string | ReactElement
|
postfix?: string | ReactElement
|
||||||
@ -71,7 +71,7 @@ export default function Input(props: Partial<InputProps>): ReactElement {
|
|||||||
</Label>
|
</Label>
|
||||||
<InputElement small={small} {...field} {...props} />
|
<InputElement small={small} {...field} {...props} />
|
||||||
|
|
||||||
{field && field.name !== 'price' && (
|
{field && field.name !== 'price' && hasError && (
|
||||||
<div className={styles.error}>
|
<div className={styles.error}>
|
||||||
<ErrorMessage name={field.name} />
|
<ErrorMessage name={field.name} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { useMetadata, useOcean } from '@oceanprotocol/react'
|
import { useMetadata } from '@oceanprotocol/react'
|
||||||
import { DDO } from '@oceanprotocol/lib'
|
import { DDO } from '@oceanprotocol/lib'
|
||||||
import Loader from '../Loader'
|
import Loader from '../Loader'
|
||||||
import Tooltip from '../Tooltip'
|
import Tooltip from '../Tooltip'
|
||||||
|
4
src/components/atoms/SuccessConfetti.module.css
Normal file
4
src/components/atoms/SuccessConfetti.module.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.action {
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
import Alert from '../../atoms/Alert'
|
import Alert from './Alert'
|
||||||
import Button from '../../atoms/Button'
|
import React, { ReactElement, ReactNode, useEffect } from 'react'
|
||||||
import React, { ReactElement, useEffect } from 'react'
|
|
||||||
import { confetti } from 'dom-confetti'
|
import { confetti } from 'dom-confetti'
|
||||||
import styles from './Success.module.css'
|
import styles from './SuccessConfetti.module.css'
|
||||||
|
|
||||||
const confettiConfig = {
|
const confettiConfig = {
|
||||||
angle: 90,
|
angle: 90,
|
||||||
@ -24,33 +23,29 @@ const confettiConfig = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Success({
|
export default function SuccessConfetti({
|
||||||
success,
|
success,
|
||||||
did
|
action
|
||||||
}: {
|
}: {
|
||||||
success: string
|
success: string
|
||||||
did: string
|
action: ReactNode
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
// Have some confetti upon success
|
// Have some confetti upon success
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!success || typeof window === 'undefined') return
|
if (!success || typeof window === 'undefined') return
|
||||||
|
|
||||||
const startElement: HTMLElement = document.querySelector('a[data-confetti]')
|
const startElement: HTMLElement = document.querySelector(
|
||||||
|
'span[data-confetti]'
|
||||||
|
)
|
||||||
confetti(startElement, confettiConfig)
|
confetti(startElement, confettiConfig)
|
||||||
}, [success])
|
}, [success])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Alert text={success} state="success" />
|
<Alert text={success} state="success" />
|
||||||
<Button
|
<span className={styles.action} data-confetti>
|
||||||
style="primary"
|
{action}
|
||||||
size="small"
|
</span>
|
||||||
href={`/asset/${did}`}
|
|
||||||
className={styles.action}
|
|
||||||
data-confetti
|
|
||||||
>
|
|
||||||
Go to data set →
|
|
||||||
</Button>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -11,18 +11,18 @@
|
|||||||
|
|
||||||
.balance {
|
.balance {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small) !important;
|
||||||
border: 1px solid var(--brand-grey-lighter);
|
border: 1px solid var(--brand-grey-lighter);
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
margin-right: -3px;
|
margin-right: -3px;
|
||||||
padding: calc(var(--spacer) / 4.5) calc(var(--spacer) / 2);
|
height: 35px;
|
||||||
|
padding: calc(var(--spacer) / 3) calc(var(--spacer) / 2)
|
||||||
|
calc(var(--spacer) / 4.5) calc(var(--spacer) / 2);
|
||||||
border-top-left-radius: var(--border-radius);
|
border-top-left-radius: var(--border-radius);
|
||||||
border-bottom-left-radius: var(--border-radius);
|
border-bottom-left-radius: var(--border-radius);
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
}
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
.balance strong {
|
|
||||||
color: var(--brand-grey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { DataTokenOptions, useOcean } from '@oceanprotocol/react'
|
import { DataTokenOptions, useOcean } from '@oceanprotocol/react'
|
||||||
|
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import { PriceOptionsMarket } from '../../../../@types/MetaData'
|
import { PriceOptionsMarket } from '../../../../@types/MetaData'
|
||||||
import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
|
import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
|
||||||
@ -66,9 +67,12 @@ export default function Dynamic({
|
|||||||
|
|
||||||
<aside className={styles.wallet}>
|
<aside className={styles.wallet}>
|
||||||
{balance?.ocean && (
|
{balance?.ocean && (
|
||||||
<div className={styles.balance}>
|
<PriceUnit
|
||||||
OCEAN <strong>{balance.ocean}</strong>
|
className={styles.balance}
|
||||||
</div>
|
price={balance.ocean}
|
||||||
|
symbol="OCEAN"
|
||||||
|
small
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<Wallet />
|
<Wallet />
|
||||||
</aside>
|
</aside>
|
||||||
|
@ -55,7 +55,7 @@ export default function Fees({
|
|||||||
<Tooltip content={tooltips.marketplaceFee} />
|
<Tooltip content={tooltips.marketplaceFee} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
value={appConfig.marketFeeAmount}
|
value="0.1"
|
||||||
name="marketplaceFee"
|
name="marketplaceFee"
|
||||||
postfix="%"
|
postfix="%"
|
||||||
readOnly
|
readOnly
|
||||||
|
@ -15,6 +15,7 @@ import styles from './Compute.module.css'
|
|||||||
import Button from '../../atoms/Button'
|
import Button from '../../atoms/Button'
|
||||||
import Input from '../../atoms/Input'
|
import Input from '../../atoms/Input'
|
||||||
import Alert from '../../atoms/Alert'
|
import Alert from '../../atoms/Alert'
|
||||||
|
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||||
|
|
||||||
export default function Compute({
|
export default function Compute({
|
||||||
ddo,
|
ddo,
|
||||||
@ -25,6 +26,7 @@ export default function Compute({
|
|||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { ocean } = useOcean()
|
const { ocean } = useOcean()
|
||||||
const { compute, isLoading, computeStepText, computeError } = useCompute()
|
const { compute, isLoading, computeStepText, computeError } = useCompute()
|
||||||
|
const { marketFeeAddress } = useSiteMetadata()
|
||||||
const computeService = ddo.findServiceByType('compute')
|
const computeService = ddo.findServiceByType('compute')
|
||||||
const metadataService = ddo.findServiceByType('metadata')
|
const metadataService = ddo.findServiceByType('metadata')
|
||||||
|
|
||||||
@ -73,7 +75,8 @@ export default function Compute({
|
|||||||
computeService,
|
computeService,
|
||||||
ddo.dataToken,
|
ddo.dataToken,
|
||||||
algorithmRawCode,
|
algorithmRawCode,
|
||||||
computeContainer
|
computeContainer,
|
||||||
|
marketFeeAddress
|
||||||
)
|
)
|
||||||
|
|
||||||
setIsPublished(true)
|
setIsPublished(true)
|
||||||
|
@ -8,6 +8,7 @@ import Web3Feedback from '../../molecules/Wallet/Feedback'
|
|||||||
import styles from './Consume.module.css'
|
import styles from './Consume.module.css'
|
||||||
import Loader from '../../atoms/Loader'
|
import Loader from '../../atoms/Loader'
|
||||||
import { useOcean, useConsume } from '@oceanprotocol/react'
|
import { useOcean, useConsume } from '@oceanprotocol/react'
|
||||||
|
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||||
|
|
||||||
export default function Consume({
|
export default function Consume({
|
||||||
ddo,
|
ddo,
|
||||||
@ -19,6 +20,7 @@ export default function Consume({
|
|||||||
isBalanceSufficient: boolean
|
isBalanceSufficient: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { ocean } = useOcean()
|
const { ocean } = useOcean()
|
||||||
|
const { marketFeeAddress } = useSiteMetadata()
|
||||||
const { consumeStepText, consume, consumeError } = useConsume()
|
const { consumeStepText, consume, consumeError } = useConsume()
|
||||||
|
|
||||||
const isDisabled = !ocean || !isBalanceSufficient
|
const isDisabled = !ocean || !isBalanceSufficient
|
||||||
@ -34,7 +36,9 @@ export default function Consume({
|
|||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
style="primary"
|
style="primary"
|
||||||
onClick={() => consume(ddo.id, ddo.dataToken, 'access')}
|
onClick={() =>
|
||||||
|
consume(ddo.id, ddo.dataToken, 'access', marketFeeAddress)
|
||||||
|
}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
>
|
>
|
||||||
Buy
|
Buy
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import Loader from '../../../atoms/Loader'
|
import Loader from '../../../atoms/Loader'
|
||||||
import Button from '../../../atoms/Button'
|
import Button from '../../../atoms/Button'
|
||||||
import Alert from '../../../atoms/Alert'
|
|
||||||
import styles from './Actions.module.css'
|
import styles from './Actions.module.css'
|
||||||
import EtherscanLink from '../../../atoms/EtherscanLink'
|
import EtherscanLink from '../../../atoms/EtherscanLink'
|
||||||
|
import SuccessConfetti from '../../../atoms/SuccessConfetti'
|
||||||
|
|
||||||
export default function Actions({
|
export default function Actions({
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -30,15 +30,14 @@ export default function Actions({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{txId && (
|
{txId && (
|
||||||
<>
|
<SuccessConfetti
|
||||||
<Alert
|
success="Successfully added liquidity."
|
||||||
text={`Successfully added liquidity. Transaction ID: ${txId}`}
|
action={
|
||||||
state="success"
|
|
||||||
/>
|
|
||||||
<EtherscanLink network="rinkeby" path={`/tx/${txId}`}>
|
<EtherscanLink network="rinkeby" path={`/tx/${txId}`}>
|
||||||
Etherscan
|
See on Etherscan
|
||||||
</EtherscanLink>
|
</EtherscanLink>
|
||||||
</>
|
}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
.addInput {
|
.addInput {
|
||||||
margin: 0 auto calc(var(--spacer) / 1.5) auto;
|
margin: 0 auto calc(var(--spacer) / 1.5) auto;
|
||||||
background: var(--brand-grey-dimmed);
|
background: var(--brand-grey-dimmed);
|
||||||
padding: var(--spacer) calc(var(--spacer) * 3) calc(var(--spacer) * 1.2)
|
padding: var(--spacer) calc(var(--spacer) * 2.5) calc(var(--spacer) * 1.2)
|
||||||
calc(var(--spacer) * 3);
|
calc(var(--spacer) * 2.5);
|
||||||
border-bottom: 1px solid var(--brand-grey-lighter);
|
border-bottom: 1px solid var(--brand-grey-lighter);
|
||||||
margin-top: -2rem;
|
margin-top: -2rem;
|
||||||
margin-left: -2rem;
|
margin-left: -2rem;
|
||||||
@ -14,45 +14,34 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.addInput div[class*='field'] {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.buttonMax {
|
.buttonMax {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: var(--font-size-mini);
|
font-size: var(--font-size-mini);
|
||||||
bottom: calc(var(--spacer) / 2);
|
bottom: calc(var(--spacer) / 2);
|
||||||
right: calc(var(--spacer) * 3);
|
right: calc(var(--spacer) * 2.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.userLiquidity {
|
.userLiquidity > div {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: var(--font-size-mini);
|
font-size: var(--font-size-mini);
|
||||||
margin-bottom: calc(var(--spacer) / 4);
|
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.userLiquidity > div:last-child {
|
||||||
|
margin-bottom: calc(var(--spacer) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
.userLiquidity span + div {
|
.userLiquidity span + div {
|
||||||
transform: scale(0.8);
|
transform: scale(0.8);
|
||||||
transform-origin: right center;
|
transform-origin: right center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coinswitch,
|
|
||||||
.coinPopover li {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coinswitch svg {
|
|
||||||
width: 0.6em;
|
|
||||||
height: 0.6em;
|
|
||||||
display: inline-block;
|
|
||||||
fill: currentColor;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
margin-left: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coinPopover li {
|
|
||||||
padding: calc(var(--spacer) / 4) calc(var(--spacer) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.output {
|
.output {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--spacer);
|
gap: var(--spacer);
|
||||||
|
@ -1,17 +1,49 @@
|
|||||||
import React, { ReactElement, useState, ChangeEvent, useEffect } from 'react'
|
import React, { ReactElement, useState, useEffect } from 'react'
|
||||||
import styles from './Add.module.css'
|
import styles from './Add.module.css'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import Header from './Header'
|
import Header from './Header'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import InputElement from '../../../atoms/Input/InputElement'
|
|
||||||
import Button from '../../../atoms/Button'
|
import Button from '../../../atoms/Button'
|
||||||
import Token from './Token'
|
import Token from './Token'
|
||||||
import { Balance } from './'
|
import { Balance } from './'
|
||||||
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
||||||
import Actions from './Actions'
|
import Actions from './Actions'
|
||||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
import Tooltip from '../../../atoms/Tooltip'
|
import * as Yup from 'yup'
|
||||||
import { ReactComponent as Caret } from '../../../../images/caret.svg'
|
import { Field, FieldInputProps, Formik } from 'formik'
|
||||||
|
import Input from '../../../atoms/Input'
|
||||||
|
import CoinSelect from './CoinSelect'
|
||||||
|
|
||||||
|
const contentQuery = graphql`
|
||||||
|
query PoolAddQuery {
|
||||||
|
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
childContentJson {
|
||||||
|
pool {
|
||||||
|
add {
|
||||||
|
title
|
||||||
|
output {
|
||||||
|
titleIn
|
||||||
|
titleOut
|
||||||
|
}
|
||||||
|
action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
interface FormAddLiquidity {
|
||||||
|
amount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialValues: FormAddLiquidity = {
|
||||||
|
amount: undefined
|
||||||
|
}
|
||||||
|
|
||||||
export default function Add({
|
export default function Add({
|
||||||
setShowAdd,
|
setShowAdd,
|
||||||
@ -30,108 +62,162 @@ export default function Add({
|
|||||||
dtSymbol: string
|
dtSymbol: string
|
||||||
dtAddress: string
|
dtAddress: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { debug } = useUserPreferences()
|
const data = useStaticQuery(contentQuery)
|
||||||
|
const content = data.content.edges[0].node.childContentJson.pool.add
|
||||||
|
|
||||||
const { ocean, accountId, balance } = useOcean()
|
const { ocean, accountId, balance } = useOcean()
|
||||||
const [amount, setAmount] = useState('')
|
const [txId, setTxId] = useState<string>()
|
||||||
const [txId, setTxId] = useState<string>('')
|
const [coin, setCoin] = useState('OCEAN')
|
||||||
const [isLoading, setIsLoading] = useState<boolean>()
|
|
||||||
const [coin, setCoin] = useState<string>('OCEAN')
|
|
||||||
const [dtBalance, setDtBalance] = useState<string>()
|
const [dtBalance, setDtBalance] = useState<string>()
|
||||||
|
const [amountMax, setAmountMax] = useState<string>()
|
||||||
|
|
||||||
const newPoolTokens =
|
// Live validation rules
|
||||||
totalBalance &&
|
// https://github.com/jquense/yup#number
|
||||||
((Number(amount) / Number(totalBalance.ocean)) * 100).toFixed(2)
|
const validationSchema = Yup.object().shape<FormAddLiquidity>({
|
||||||
|
amount: Yup.number()
|
||||||
const newPoolShare =
|
.min(1, 'Must be more or equal to 1')
|
||||||
totalBalance &&
|
.max(
|
||||||
((Number(newPoolTokens) / Number(totalPoolTokens)) * 100).toFixed(2)
|
Number(amountMax),
|
||||||
|
`Maximum you can add is ${Number(amountMax).toFixed(2)} ${coin}`
|
||||||
|
)
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get datatoken balance when datatoken selected
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ocean) return
|
if (!ocean || coin === 'OCEAN') return
|
||||||
|
|
||||||
async function getDtBalance() {
|
async function getDtBalance() {
|
||||||
const dtBalance = await ocean.datatokens.balance(dtAddress, accountId)
|
const dtBalance = await ocean.datatokens.balance(dtAddress, accountId)
|
||||||
setDtBalance(dtBalance)
|
setDtBalance(dtBalance)
|
||||||
}
|
}
|
||||||
getDtBalance()
|
getDtBalance()
|
||||||
}, [ocean, accountId, dtAddress])
|
}, [ocean, accountId, dtAddress, coin])
|
||||||
|
|
||||||
async function handleAddLiquidity() {
|
// Get maximum amount for either OCEAN or datatoken
|
||||||
setIsLoading(true)
|
useEffect(() => {
|
||||||
|
if (!ocean) return
|
||||||
|
|
||||||
|
async function getMaximum() {
|
||||||
|
const amountMaxPool =
|
||||||
|
coin === 'OCEAN'
|
||||||
|
? await ocean.pool.getOceanMaxAddLiquidity(poolAddress)
|
||||||
|
: await ocean.pool.getDTMaxAddLiquidity(poolAddress)
|
||||||
|
|
||||||
|
const amountMax =
|
||||||
|
coin === 'OCEAN'
|
||||||
|
? Number(balance.ocean) > Number(amountMaxPool)
|
||||||
|
? amountMaxPool
|
||||||
|
: balance.ocean
|
||||||
|
: Number(dtBalance) > Number(amountMaxPool)
|
||||||
|
? amountMaxPool
|
||||||
|
: dtBalance
|
||||||
|
setAmountMax(amountMax)
|
||||||
|
}
|
||||||
|
getMaximum()
|
||||||
|
}, [ocean, poolAddress, coin, dtBalance, balance.ocean])
|
||||||
|
|
||||||
|
// Submit
|
||||||
|
async function handleAddLiquidity(amount: number, resetForm: () => void) {
|
||||||
try {
|
try {
|
||||||
const result =
|
const result =
|
||||||
coin === 'OCEAN'
|
coin === 'OCEAN'
|
||||||
? await ocean.pool.addOceanLiquidity(accountId, poolAddress, amount)
|
? await ocean.pool.addOceanLiquidity(
|
||||||
: await ocean.pool.addDTLiquidity(accountId, poolAddress, amount)
|
accountId,
|
||||||
|
poolAddress,
|
||||||
|
`${amount}`
|
||||||
|
)
|
||||||
|
: await ocean.pool.addDTLiquidity(accountId, poolAddress, `${amount}`)
|
||||||
|
|
||||||
setTxId(result?.transactionHash)
|
setTxId(result?.transactionHash)
|
||||||
|
resetForm()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.message)
|
console.error(error.message)
|
||||||
toast.error(error.message)
|
toast.error(error.message)
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAmountChange(e: ChangeEvent<HTMLInputElement>) {
|
|
||||||
setAmount(e.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMax() {
|
|
||||||
setAmount(coin === 'OCEAN' ? balance.ocean : dtBalance)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: this is only a prototype and is an accessibility nightmare.
|
|
||||||
// Needs to be refactored to either use custom select element instead of tippy.js,
|
|
||||||
// or use <button> in this implementation.
|
|
||||||
// Also needs to be closed when users click an option.
|
|
||||||
const CoinSelect = () => (
|
|
||||||
<ul className={styles.coinPopover}>
|
|
||||||
<li onClick={() => setCoin('OCEAN')}>OCEAN</li>
|
|
||||||
<li onClick={() => setCoin(dtSymbol)}>{dtSymbol}</li>
|
|
||||||
</ul>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header title="Add Liquidity" backAction={() => setShowAdd(false)} />
|
<Header title={content.title} backAction={() => setShowAdd(false)} />
|
||||||
|
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
onSubmit={async (values, { setSubmitting, resetForm }) => {
|
||||||
|
await handleAddLiquidity(values.amount, resetForm)
|
||||||
|
setSubmitting(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({
|
||||||
|
values,
|
||||||
|
touched,
|
||||||
|
setTouched,
|
||||||
|
isSubmitting,
|
||||||
|
setFieldValue,
|
||||||
|
submitForm,
|
||||||
|
handleChange
|
||||||
|
}) => {
|
||||||
|
const newPoolTokens =
|
||||||
|
totalBalance &&
|
||||||
|
((values.amount / Number(totalBalance.ocean)) * 100).toFixed(2)
|
||||||
|
|
||||||
|
const newPoolShare =
|
||||||
|
totalBalance &&
|
||||||
|
((Number(newPoolTokens) / Number(totalPoolTokens)) * 100).toFixed(2)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
<div className={styles.addInput}>
|
<div className={styles.addInput}>
|
||||||
<div className={styles.userLiquidity}>
|
<div className={styles.userLiquidity}>
|
||||||
<span>Available: </span>
|
<div>
|
||||||
|
<span>Available:</span>
|
||||||
{coin === 'OCEAN' ? (
|
{coin === 'OCEAN' ? (
|
||||||
<PriceUnit price={balance.ocean} symbol="OCEAN" small />
|
<PriceUnit price={balance.ocean} symbol="OCEAN" small />
|
||||||
) : (
|
) : (
|
||||||
<PriceUnit price={dtBalance} symbol={dtSymbol} small />
|
<PriceUnit price={dtBalance} symbol={dtSymbol} small />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Maximum:</span>
|
||||||
|
<PriceUnit price={amountMax} symbol={coin} small />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<InputElement
|
<Field name="amount">
|
||||||
value={amount}
|
{({
|
||||||
name="coin"
|
field,
|
||||||
|
form
|
||||||
|
}: {
|
||||||
|
field: FieldInputProps<FormAddLiquidity>
|
||||||
|
form: any
|
||||||
|
}) => (
|
||||||
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
|
max={amountMax}
|
||||||
|
value={`${values.amount}`}
|
||||||
prefix={
|
prefix={
|
||||||
<Tooltip
|
<CoinSelect dtSymbol={dtSymbol} setCoin={setCoin} />
|
||||||
content={<CoinSelect />}
|
|
||||||
trigger="click focus"
|
|
||||||
className={styles.coinswitch}
|
|
||||||
placement="bottom"
|
|
||||||
>
|
|
||||||
{coin}
|
|
||||||
<Caret aria-hidden="true" />
|
|
||||||
</Tooltip>
|
|
||||||
}
|
}
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
onChange={handleAmountChange}
|
field={field}
|
||||||
|
form={form}
|
||||||
|
onChange={(e) => {
|
||||||
|
// Workaround so validation kicks in on first touch
|
||||||
|
!touched?.amount && setTouched({ amount: true })
|
||||||
|
handleChange(e)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
|
||||||
{(balance.ocean || dtBalance) > amount && (
|
{(Number(balance.ocean) || dtBalance) >
|
||||||
|
(values.amount || 0) && (
|
||||||
<Button
|
<Button
|
||||||
className={styles.buttonMax}
|
className={styles.buttonMax}
|
||||||
style="text"
|
style="text"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={handleMax}
|
onClick={() => setFieldValue('amount', amountMax)}
|
||||||
>
|
>
|
||||||
Use Max
|
Use Max
|
||||||
</Button>
|
</Button>
|
||||||
@ -140,23 +226,27 @@ export default function Add({
|
|||||||
|
|
||||||
<div className={styles.output}>
|
<div className={styles.output}>
|
||||||
<div>
|
<div>
|
||||||
<p>You will receive</p>
|
<p>{content.output.titleIn}</p>
|
||||||
{debug === true && <Token symbol="BPT" balance={newPoolTokens} />}
|
<Token symbol="pool shares" balance={newPoolTokens} />
|
||||||
<Token symbol="% of pool" balance={newPoolShare} />
|
<Token symbol="% of pool" balance={newPoolShare} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p>You will earn</p>
|
<p>{content.output.titleOut}</p>
|
||||||
<Token symbol="% swap fee" balance={swapFee} />
|
<Token symbol="% swap fee" balance={swapFee} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Actions
|
<Actions
|
||||||
isLoading={isLoading}
|
isLoading={isSubmitting}
|
||||||
loaderMessage="Adding Liquidity..."
|
loaderMessage="Adding Liquidity..."
|
||||||
actionName="Supply"
|
actionName={content.action}
|
||||||
action={handleAddLiquidity}
|
action={submitForm}
|
||||||
txId={txId}
|
txId={txId}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
.coinSelect {
|
||||||
|
composes: select from '../../../atoms/Input/InputElement.module.css';
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
font-weight: var(--font-weight-base);
|
||||||
|
border: none;
|
||||||
|
margin-left: -0.5rem;
|
||||||
|
margin-right: -0.5rem;
|
||||||
|
background-color: var(--brand-grey-dimmed);
|
||||||
|
width: auto;
|
||||||
|
padding: 0 1.25rem 0 0.25rem;
|
||||||
|
height: 41px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
/* custom arrow, without the divider line */
|
||||||
|
background-image: linear-gradient(
|
||||||
|
45deg,
|
||||||
|
transparent 50%,
|
||||||
|
var(--brand-purple) 50%
|
||||||
|
),
|
||||||
|
linear-gradient(135deg, var(--brand-grey) 50%, transparent 50%);
|
||||||
|
background-position: calc(100% - 14px) 1.2rem, calc(100% - 9px) 1.2rem, 100% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
color: var(--brand-grey-dark);
|
||||||
|
}
|
24
src/components/organisms/AssetActions/Pool/CoinSelect.tsx
Normal file
24
src/components/organisms/AssetActions/Pool/CoinSelect.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import styles from './CoinSelect.module.css'
|
||||||
|
|
||||||
|
export default function CoinSelect({
|
||||||
|
dtSymbol,
|
||||||
|
setCoin
|
||||||
|
}: {
|
||||||
|
dtSymbol: string
|
||||||
|
setCoin: (coin: string) => void
|
||||||
|
}): ReactElement {
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
className={styles.coinSelect}
|
||||||
|
onChange={(e) => setCoin(e.target.value)}
|
||||||
|
>
|
||||||
|
<option className={styles.option} value="OCEAN">
|
||||||
|
OCEAN
|
||||||
|
</option>
|
||||||
|
<option className={styles.option} value={dtSymbol}>
|
||||||
|
{dtSymbol}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
)
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
.statistics {
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
composes: title from './index.module.css';
|
|
||||||
}
|
|
||||||
|
|
||||||
.totalLiquidity {
|
|
||||||
composes: totalLiquidity from './index.module.css';
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
|
||||||
import React, { ReactElement } from 'react'
|
|
||||||
import { Balance } from '.'
|
|
||||||
import styles from './PoolStatistics.module.css'
|
|
||||||
import Token from './Token'
|
|
||||||
import Conversion from '../../../atoms/Price/Conversion'
|
|
||||||
|
|
||||||
export default function PoolStatistics({
|
|
||||||
price,
|
|
||||||
dtSymbol,
|
|
||||||
totalBalance,
|
|
||||||
totalPoolTokens,
|
|
||||||
swapFee
|
|
||||||
}: {
|
|
||||||
price: string
|
|
||||||
dtSymbol: string
|
|
||||||
totalBalance: Balance
|
|
||||||
totalPoolTokens: string
|
|
||||||
swapFee: string
|
|
||||||
}): ReactElement {
|
|
||||||
const { debug } = useUserPreferences()
|
|
||||||
|
|
||||||
const totalLiquidityInOcean =
|
|
||||||
totalBalance.ocean + totalBalance.datatoken * Number(price)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.statistics}>
|
|
||||||
<h3 className={styles.title}>Pool Statistics</h3>
|
|
||||||
<Token symbol="OCEAN" balance={`${totalBalance.ocean}`} />
|
|
||||||
<Token symbol={dtSymbol} balance={`${totalBalance.datatoken}`} />
|
|
||||||
{debug === true && <Token symbol="BPT" balance={totalPoolTokens} />}
|
|
||||||
<Conversion
|
|
||||||
price={`${totalLiquidityInOcean}`}
|
|
||||||
className={styles.totalLiquidity}
|
|
||||||
/>
|
|
||||||
<Token symbol="% swap fee" balance={swapFee} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,11 +1,71 @@
|
|||||||
.removeInput {
|
.removeInput {
|
||||||
composes: addInput from './Add.module.css';
|
composes: addInput from './Add.module.css';
|
||||||
}
|
padding-left: calc(var(--spacer) * 2);
|
||||||
|
padding-right: calc(var(--spacer) * 2);
|
||||||
.buttonMax {
|
|
||||||
composes: buttonMax from './Add.module.css';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.userLiquidity {
|
.userLiquidity {
|
||||||
composes: userLiquidity from './Add.module.css';
|
composes: userLiquidity from './Add.module.css';
|
||||||
|
max-width: 12rem;
|
||||||
|
margin-top: -1rem;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-bottom: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.range {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range h3 {
|
||||||
|
margin-bottom: calc(var(--spacer) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.range input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range button {
|
||||||
|
margin-top: calc(var(--spacer) / 4);
|
||||||
|
margin-bottom: 0;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1rem;
|
||||||
|
right: 2rem;
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maximum {
|
||||||
|
position: absolute;
|
||||||
|
right: -1.5rem;
|
||||||
|
bottom: 1.5rem;
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
z-index: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output {
|
||||||
|
composes: output from './Add.module.css';
|
||||||
|
}
|
||||||
|
|
||||||
|
.output [class*='token'] {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output [class*='token'] > figure {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output figure[class*='pool shares'] {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,91 @@
|
|||||||
import React, { ReactElement, useState, ChangeEvent } from 'react'
|
import React, {
|
||||||
|
ReactElement,
|
||||||
|
useState,
|
||||||
|
ChangeEvent,
|
||||||
|
useEffect,
|
||||||
|
FormEvent
|
||||||
|
} from 'react'
|
||||||
import styles from './Remove.module.css'
|
import styles from './Remove.module.css'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import Header from './Header'
|
import Header from './Header'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import InputElement from '../../../atoms/Input/InputElement'
|
|
||||||
import Actions from './Actions'
|
import Actions from './Actions'
|
||||||
import { Logger } from '@oceanprotocol/lib'
|
import { Logger } from '@oceanprotocol/lib'
|
||||||
|
import Token from './Token'
|
||||||
|
import FormHelp from '../../../atoms/Input/Help'
|
||||||
import Button from '../../../atoms/Button'
|
import Button from '../../../atoms/Button'
|
||||||
|
import { getMaxValuesRemove } from './utils'
|
||||||
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
||||||
import { Balance } from '.'
|
|
||||||
|
const contentQuery = graphql`
|
||||||
|
query PoolRemoveQuery {
|
||||||
|
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
childContentJson {
|
||||||
|
pool {
|
||||||
|
remove {
|
||||||
|
title
|
||||||
|
simple
|
||||||
|
advanced
|
||||||
|
output {
|
||||||
|
titleIn
|
||||||
|
titleOut
|
||||||
|
}
|
||||||
|
action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export default function Remove({
|
export default function Remove({
|
||||||
setShowRemove,
|
setShowRemove,
|
||||||
poolAddress,
|
poolAddress,
|
||||||
totalPoolTokens,
|
poolTokens,
|
||||||
userLiquidity
|
dtSymbol
|
||||||
}: {
|
}: {
|
||||||
setShowRemove: (show: boolean) => void
|
setShowRemove: (show: boolean) => void
|
||||||
poolAddress: string
|
poolAddress: string
|
||||||
totalPoolTokens: string
|
poolTokens: string
|
||||||
userLiquidity: Balance
|
dtSymbol: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
const data = useStaticQuery(contentQuery)
|
||||||
|
const content = data.content.edges[0].node.childContentJson.pool.remove
|
||||||
|
|
||||||
const { ocean, accountId } = useOcean()
|
const { ocean, accountId } = useOcean()
|
||||||
const [amount, setAmount] = useState('')
|
const [amountPercent, setAmountPercent] = useState('0')
|
||||||
|
const [amountMaxPercent, setAmountMaxPercent] = useState('100')
|
||||||
|
const [amountPoolShares, setAmountPoolShares] = useState('0')
|
||||||
|
const [amountOcean, setAmountOcean] = useState('0')
|
||||||
|
const [amountDatatoken, setAmountDatatoken] = useState('0')
|
||||||
|
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>()
|
||||||
|
|
||||||
async function handleRemoveLiquidity() {
|
async function handleRemoveLiquidity() {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await ocean.pool.removeOceanLiquidity(
|
const result =
|
||||||
|
isAdvanced === true
|
||||||
|
? await ocean.pool.removePoolLiquidity(
|
||||||
accountId,
|
accountId,
|
||||||
poolAddress,
|
poolAddress,
|
||||||
amount,
|
amountPoolShares
|
||||||
totalPoolTokens
|
|
||||||
)
|
)
|
||||||
setTxId(result.transactionHash)
|
: await ocean.pool.removeOceanLiquidity(
|
||||||
|
accountId,
|
||||||
|
poolAddress,
|
||||||
|
amountDatatoken,
|
||||||
|
amountPoolShares
|
||||||
|
)
|
||||||
|
|
||||||
|
setTxId(result?.transactionHash)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error(error.message)
|
Logger.error(error.message)
|
||||||
toast.error(error.message)
|
toast.error(error.message)
|
||||||
@ -45,55 +94,103 @@ export default function Remove({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAmountChange(e: ChangeEvent<HTMLInputElement>) {
|
function handleAmountPercentChange(e: ChangeEvent<HTMLInputElement>) {
|
||||||
setAmount(e.target.value)
|
setAmountPercent(e.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMax() {
|
function handleAdvancedButton(e: FormEvent<HTMLButtonElement>) {
|
||||||
setAmount(`${userLiquidity.ocean}`)
|
e.preventDefault()
|
||||||
|
setIsAdvanced(!isAdvanced)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check and set outputs when percentage changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ocean || !poolTokens) return
|
||||||
|
|
||||||
|
async function getValues() {
|
||||||
|
const amountPoolShares =
|
||||||
|
(Number(amountPercent) / 100) * Number(poolTokens)
|
||||||
|
setAmountPoolShares(`${amountPoolShares}`)
|
||||||
|
|
||||||
|
if (isAdvanced === true) {
|
||||||
|
setAmountMaxPercent('100')
|
||||||
|
|
||||||
|
const tokens = await ocean.pool.getTokensRemovedforPoolShares(
|
||||||
|
poolAddress,
|
||||||
|
`${amountPoolShares}`
|
||||||
|
)
|
||||||
|
setAmountOcean(tokens?.oceanAmount)
|
||||||
|
setAmountDatatoken(tokens?.dtAmount)
|
||||||
|
} else {
|
||||||
|
const { amountMaxPercent, amountOcean } = await getMaxValuesRemove(
|
||||||
|
ocean,
|
||||||
|
poolAddress,
|
||||||
|
poolTokens,
|
||||||
|
`${amountPoolShares}`
|
||||||
|
)
|
||||||
|
setAmountMaxPercent(amountMaxPercent)
|
||||||
|
setAmountOcean(amountOcean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getValues()
|
||||||
|
}, [amountPercent, isAdvanced, ocean, poolTokens, poolAddress])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.remove}>
|
<div className={styles.remove}>
|
||||||
<Header
|
<Header title={content.title} backAction={() => setShowRemove(false)} />
|
||||||
title="Remove Liquidity"
|
|
||||||
backAction={() => setShowRemove(false)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<form className={styles.removeInput}>
|
<form className={styles.removeInput}>
|
||||||
<div className={styles.userLiquidity}>
|
<div className={styles.userLiquidity}>
|
||||||
<span>Your pool liquidity: </span>
|
<div>
|
||||||
<PriceUnit price={`${userLiquidity.ocean}`} symbol="OCEAN" small />
|
<span>Available:</span>
|
||||||
|
<PriceUnit price={poolTokens} symbol="pool shares" small />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<InputElement
|
|
||||||
value={amount}
|
|
||||||
name="ocean"
|
|
||||||
type="number"
|
|
||||||
prefix="OCEAN"
|
|
||||||
placeholder="0"
|
|
||||||
onChange={handleAmountChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{userLiquidity.ocean > Number(amount) && (
|
<div className={styles.range}>
|
||||||
<Button
|
<h3>{amountPercent}%</h3>
|
||||||
className={styles.buttonMax}
|
<div className={styles.slider}>
|
||||||
style="text"
|
<input
|
||||||
size="small"
|
type="range"
|
||||||
onClick={handleMax}
|
min="0"
|
||||||
>
|
max={amountMaxPercent}
|
||||||
Use Max
|
value={amountPercent}
|
||||||
</Button>
|
onChange={handleAmountPercentChange}
|
||||||
|
/>
|
||||||
|
{isAdvanced === false && (
|
||||||
|
<span
|
||||||
|
className={styles.maximum}
|
||||||
|
>{`${amountMaxPercent}% max.`}</span>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormHelp>
|
||||||
|
{isAdvanced === true ? content.advanced : content.simple}
|
||||||
|
</FormHelp>
|
||||||
|
<Button style="text" size="small" onClick={handleAdvancedButton}>
|
||||||
|
{isAdvanced === true ? 'Simple' : 'Advanced'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* <Input name="dt" label={dtSymbol} type="number" placeholder="0" /> */}
|
<div className={styles.output}>
|
||||||
|
<div>
|
||||||
<p>You will receive</p>
|
<p>{content.output.titleIn}</p>
|
||||||
|
<Token symbol="pool shares" balance={amountPoolShares} noIcon />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>{content.output.titleOut}</p>
|
||||||
|
<Token symbol="OCEAN" balance={amountOcean} />
|
||||||
|
{isAdvanced === true && (
|
||||||
|
<Token symbol={dtSymbol} balance={amountDatatoken} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Actions
|
<Actions
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
loaderMessage="Removing Liquidity..."
|
loaderMessage="Removing Liquidity..."
|
||||||
actionName="Remove"
|
actionName={content.action}
|
||||||
action={handleRemoveLiquidity}
|
action={handleRemoveLiquidity}
|
||||||
txId={txId}
|
txId={txId}
|
||||||
/>
|
/>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.token {
|
.token {
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
margin-bottom: calc(var(--spacer) / 3);
|
margin-bottom: calc(var(--spacer) / 4);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,7 +17,7 @@
|
|||||||
padding: 0.3rem;
|
padding: 0.3rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: calc(var(--spacer) / 8);
|
margin-right: calc(var(--spacer) / 8);
|
||||||
margin-top: -0.3rem;
|
margin-top: -0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon svg {
|
.icon svg {
|
||||||
@ -30,7 +30,6 @@
|
|||||||
fill: var(--brand-violet);
|
fill: var(--brand-violet);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon[class*='%'],
|
.noIcon {
|
||||||
.icon[class*='BPT'] {
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,18 @@ import PriceUnit from '../../../atoms/Price/PriceUnit'
|
|||||||
|
|
||||||
export default function Token({
|
export default function Token({
|
||||||
symbol,
|
symbol,
|
||||||
balance
|
balance,
|
||||||
|
noIcon
|
||||||
}: {
|
}: {
|
||||||
symbol: string
|
symbol: string
|
||||||
balance: string
|
balance: string
|
||||||
|
noIcon?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return (
|
return (
|
||||||
<div className={styles.token}>
|
<div className={styles.token}>
|
||||||
<figure className={`${styles.icon} ${symbol}`}>
|
<figure
|
||||||
|
className={`${styles.icon} ${symbol} ${noIcon ? styles.noIcon : ''}`}
|
||||||
|
>
|
||||||
<Logo />
|
<Logo />
|
||||||
</figure>
|
</figure>
|
||||||
<PriceUnit price={balance} symbol={symbol} small />
|
<PriceUnit price={balance} symbol={symbol} small />
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
.tokeninfo {
|
||||||
|
padding-top: calc(var(--spacer) / 1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tokens {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* visually tweak the order so tokens are underneath each other */
|
||||||
|
.tokens > *:nth-child(1) {
|
||||||
|
grid-row: 1 / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tokens > *:nth-child(2) {
|
||||||
|
grid-row: 2 / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
margin-bottom: calc(var(--spacer) / 3);
|
||||||
|
color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
background: var(--brand-grey-dimmed);
|
||||||
|
padding: calc(var(--spacer) / 1.5) var(--spacer) calc(var(--spacer) / 2)
|
||||||
|
var(--spacer);
|
||||||
|
border-bottom: 1px solid var(--brand-grey-lighter);
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.totalLiquidity {
|
||||||
|
composes: token from './Token.module.css';
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: var(--font-weight-base) !important;
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
padding-left: var(--font-size-base);
|
||||||
|
padding-top: calc(var(--spacer) / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.totalLiquidity strong {
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
color: var(--brand-grey-dark);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
44
src/components/organisms/AssetActions/Pool/TokenList.tsx
Normal file
44
src/components/organisms/AssetActions/Pool/TokenList.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import Conversion from '../../../atoms/Price/Conversion'
|
||||||
|
import React, { ReactElement, ReactNode } from 'react'
|
||||||
|
import Token from './Token'
|
||||||
|
import styles from './TokenList.module.css'
|
||||||
|
|
||||||
|
export default function TokenList({
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
ocean,
|
||||||
|
dt,
|
||||||
|
dtSymbol,
|
||||||
|
poolShares,
|
||||||
|
conversion,
|
||||||
|
highlight
|
||||||
|
}: {
|
||||||
|
title: string | ReactNode
|
||||||
|
children: ReactNode
|
||||||
|
ocean: string
|
||||||
|
dt: string
|
||||||
|
dtSymbol: string
|
||||||
|
poolShares: string
|
||||||
|
conversion: number
|
||||||
|
highlight?: boolean
|
||||||
|
}): ReactElement {
|
||||||
|
return (
|
||||||
|
<div className={`${styles.tokeninfo} ${highlight ? styles.highlight : ''}`}>
|
||||||
|
<h3 className={styles.title}>{title}</h3>
|
||||||
|
<div className={styles.tokens}>
|
||||||
|
<Token symbol="OCEAN" balance={ocean} />
|
||||||
|
<Token symbol={dtSymbol} balance={dt} />
|
||||||
|
<Token symbol="pool shares" balance={poolShares} noIcon />
|
||||||
|
|
||||||
|
{children}
|
||||||
|
|
||||||
|
{conversion > 0 && (
|
||||||
|
<Conversion
|
||||||
|
price={`${conversion}`}
|
||||||
|
className={styles.totalLiquidity}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
.dataToken {
|
.dataToken {
|
||||||
margin-bottom: var(--spacer);
|
|
||||||
padding-bottom: calc(var(--spacer) / 1.5);
|
padding-bottom: calc(var(--spacer) / 1.5);
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
border-bottom: 1px solid var(--brand-grey-lighter);
|
border-bottom: 1px solid var(--brand-grey-lighter);
|
||||||
margin-left: -2rem;
|
margin-left: -2rem;
|
||||||
margin-right: -2rem;
|
margin-right: -2rem;
|
||||||
padding-left: var(--spacer);
|
padding-left: calc(var(--spacer) / 1.5);
|
||||||
padding-right: var(--spacer);
|
padding-right: calc(var(--spacer) / 1.5);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,27 +20,3 @@
|
|||||||
margin-left: calc(var(--spacer) / 3);
|
margin-left: calc(var(--spacer) / 3);
|
||||||
margin-right: calc(var(--spacer) / 3);
|
margin-right: calc(var(--spacer) / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.poolTokens {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--spacer);
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: var(--font-size-base);
|
|
||||||
margin-bottom: calc(var(--spacer) / 1.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.totalLiquidity {
|
|
||||||
composes: token from './Token.module.css';
|
|
||||||
font-weight: var(--font-weight-base) !important;
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
padding-left: var(--font-size-base);
|
|
||||||
}
|
|
||||||
|
|
||||||
.totalLiquidity strong {
|
|
||||||
font-size: var(--font-size-base);
|
|
||||||
color: var(--brand-grey-dark);
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
@ -3,7 +3,6 @@ import { useOcean, useMetadata } from '@oceanprotocol/react'
|
|||||||
import { DDO, Logger } from '@oceanprotocol/lib'
|
import { DDO, Logger } from '@oceanprotocol/lib'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import stylesActions from './Actions.module.css'
|
import stylesActions from './Actions.module.css'
|
||||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
|
||||||
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
||||||
import Loader from '../../../atoms/Loader'
|
import Loader from '../../../atoms/Loader'
|
||||||
import Button from '../../../atoms/Button'
|
import Button from '../../../atoms/Button'
|
||||||
@ -12,20 +11,38 @@ import Remove from './Remove'
|
|||||||
import Tooltip from '../../../atoms/Tooltip'
|
import Tooltip from '../../../atoms/Tooltip'
|
||||||
import Conversion from '../../../atoms/Price/Conversion'
|
import Conversion from '../../../atoms/Price/Conversion'
|
||||||
import EtherscanLink from '../../../atoms/EtherscanLink'
|
import EtherscanLink from '../../../atoms/EtherscanLink'
|
||||||
import PoolStatistics from './PoolStatistics'
|
|
||||||
import Token from './Token'
|
import Token from './Token'
|
||||||
|
import TokenList from './TokenList'
|
||||||
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
|
|
||||||
export interface Balance {
|
export interface Balance {
|
||||||
ocean: number
|
ocean: number
|
||||||
datatoken: number
|
datatoken: number
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
const contentQuery = graphql`
|
||||||
TODO: create tooltip copy
|
query PoolQuery {
|
||||||
*/
|
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
childContentJson {
|
||||||
|
pool {
|
||||||
|
tooltips {
|
||||||
|
price
|
||||||
|
liquidity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
||||||
const { debug } = useUserPreferences()
|
const data = useStaticQuery(contentQuery)
|
||||||
|
const content = data.content.edges[0].node.childContentJson.pool
|
||||||
|
|
||||||
const { ocean, accountId } = useOcean()
|
const { ocean, accountId } = useOcean()
|
||||||
const { price } = useMetadata(ddo)
|
const { price } = useMetadata(ddo)
|
||||||
|
|
||||||
@ -39,6 +56,8 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
const [showRemove, setShowRemove] = useState(false)
|
const [showRemove, setShowRemove] = useState(false)
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
|
||||||
|
// TODO: put all these variables behind some useEffect
|
||||||
|
// to prevent unneccessary updating on every render
|
||||||
const hasAddedLiquidity =
|
const hasAddedLiquidity =
|
||||||
userLiquidity && (userLiquidity.ocean > 0 || userLiquidity.datatoken > 0)
|
userLiquidity && (userLiquidity.ocean > 0 || userLiquidity.datatoken > 0)
|
||||||
|
|
||||||
@ -51,6 +70,8 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
const totalUserLiquidityInOcean =
|
const totalUserLiquidityInOcean =
|
||||||
userLiquidity?.ocean + userLiquidity?.datatoken * price?.value
|
userLiquidity?.ocean + userLiquidity?.datatoken * price?.value
|
||||||
|
|
||||||
|
const totalLiquidityInOcean = price?.ocean + price?.datatoken * price?.value
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ocean || !accountId || !price || !price.value) return
|
if (!ocean || !accountId || !price || !price.value) return
|
||||||
|
|
||||||
@ -67,7 +88,9 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
//
|
//
|
||||||
// Get everything which is in the pool
|
// Get everything which is in the pool
|
||||||
//
|
//
|
||||||
const totalPoolTokens = await ocean.pool.totalSupply(price.address)
|
const totalPoolTokens = await ocean.pool.getPoolSharesTotalSupply(
|
||||||
|
price.address
|
||||||
|
)
|
||||||
setTotalPoolTokens(totalPoolTokens)
|
setTotalPoolTokens(totalPoolTokens)
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -124,8 +147,8 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
<Remove
|
<Remove
|
||||||
setShowRemove={setShowRemove}
|
setShowRemove={setShowRemove}
|
||||||
poolAddress={price.address}
|
poolAddress={price.address}
|
||||||
totalPoolTokens={totalPoolTokens}
|
poolTokens={poolTokens}
|
||||||
userLiquidity={userLiquidity}
|
dtSymbol={dtSymbol}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@ -133,7 +156,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
<PriceUnit price="1" symbol={dtSymbol} /> ={' '}
|
<PriceUnit price="1" symbol={dtSymbol} /> ={' '}
|
||||||
<PriceUnit price={`${price.value}`} />
|
<PriceUnit price={`${price.value}`} />
|
||||||
<Conversion price={`${price.value}`} />
|
<Conversion price={`${price.value}`} />
|
||||||
<Tooltip content="Explain how this price is determined..." />
|
<Tooltip content={content.tooltips.price} />
|
||||||
<div className={styles.dataTokenLinks}>
|
<div className={styles.dataTokenLinks}>
|
||||||
<EtherscanLink
|
<EtherscanLink
|
||||||
network="rinkeby"
|
network="rinkeby"
|
||||||
@ -147,30 +170,33 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.poolTokens}>
|
<TokenList
|
||||||
<div className={styles.tokens}>
|
title={
|
||||||
<h3 className={styles.title}>
|
<>
|
||||||
Your Liquidity
|
Your Liquidity
|
||||||
<Tooltip content="Explain what this represents, advantage of providing liquidity..." />
|
<Tooltip content={content.tooltips.liquidity} />
|
||||||
</h3>
|
</>
|
||||||
<Token symbol="OCEAN" balance={`${userLiquidity.ocean}`} />
|
}
|
||||||
<Token symbol={dtSymbol} balance={`${userLiquidity.datatoken}`} />
|
ocean={`${userLiquidity.ocean}`}
|
||||||
{debug === true && <Token symbol="BPT" balance={poolTokens} />}
|
dt={`${userLiquidity.datatoken}`}
|
||||||
<Conversion
|
|
||||||
price={`${totalUserLiquidityInOcean}`}
|
|
||||||
className={styles.totalLiquidity}
|
|
||||||
/>
|
|
||||||
<Token symbol="% of pool" balance={poolShare} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<PoolStatistics
|
|
||||||
price={`${price.value}`}
|
|
||||||
totalPoolTokens={totalPoolTokens}
|
|
||||||
totalBalance={{ ocean: price.ocean, datatoken: price.datatoken }}
|
|
||||||
swapFee={swapFee}
|
|
||||||
dtSymbol={dtSymbol}
|
dtSymbol={dtSymbol}
|
||||||
/>
|
poolShares={poolTokens}
|
||||||
</div>
|
conversion={totalUserLiquidityInOcean}
|
||||||
|
highlight
|
||||||
|
>
|
||||||
|
<Token symbol="% of pool" balance={poolShare} noIcon />
|
||||||
|
</TokenList>
|
||||||
|
|
||||||
|
<TokenList
|
||||||
|
title="Pool Statistics"
|
||||||
|
ocean={`${price.ocean}`}
|
||||||
|
dt={`${price.datatoken}`}
|
||||||
|
dtSymbol={dtSymbol}
|
||||||
|
poolShares={totalPoolTokens}
|
||||||
|
conversion={totalLiquidityInOcean}
|
||||||
|
>
|
||||||
|
<Token symbol="% swap fee" balance={swapFee} noIcon />
|
||||||
|
</TokenList>
|
||||||
|
|
||||||
<div className={stylesActions.actions}>
|
<div className={stylesActions.actions}>
|
||||||
<Button
|
<Button
|
||||||
|
28
src/components/organisms/AssetActions/Pool/utils.ts
Normal file
28
src/components/organisms/AssetActions/Pool/utils.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Ocean } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
|
export async function getMaxValuesRemove(
|
||||||
|
ocean: Ocean,
|
||||||
|
poolAddress: string,
|
||||||
|
poolTokens: string,
|
||||||
|
amountPoolShares: string
|
||||||
|
): Promise<{ amountMaxPercent: string; amountOcean: string }> {
|
||||||
|
const amountMaxOcean = await ocean.pool.getOceanMaxRemoveLiquidity(
|
||||||
|
poolAddress
|
||||||
|
)
|
||||||
|
|
||||||
|
const amountMaxPoolShares = await ocean.pool.getPoolSharesRequiredToRemoveOcean(
|
||||||
|
poolAddress,
|
||||||
|
amountMaxOcean
|
||||||
|
)
|
||||||
|
|
||||||
|
const amountMaxPercent = `${Math.floor(
|
||||||
|
(Number(amountMaxPoolShares) / Number(poolTokens)) * 100
|
||||||
|
)}`
|
||||||
|
|
||||||
|
const amountOcean = await ocean.pool.getOceanRemovedforPoolShares(
|
||||||
|
poolAddress,
|
||||||
|
amountPoolShares
|
||||||
|
)
|
||||||
|
|
||||||
|
return { amountMaxPercent, amountOcean }
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import AssetTeaser from '../molecules/AssetTeaser'
|
import AssetTeaser from '../molecules/AssetTeaser'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatastore/MetadataStore'
|
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
import { useLocation, useNavigate } from '@reach/router'
|
import { useLocation, useNavigate } from '@reach/router'
|
||||||
import Pagination from '../molecules/Pagination'
|
import Pagination from '../molecules/Pagination'
|
||||||
import { updateQueryStringParameter } from '../../utils'
|
import { updateQueryStringParameter } from '../../utils'
|
||||||
@ -57,7 +57,7 @@ const AssetList: React.FC<AssetListProps> = ({ queryResult }) => {
|
|||||||
})
|
})
|
||||||
) : (
|
) : (
|
||||||
<div className={styles.empty}>
|
<div className={styles.empty}>
|
||||||
No results found in {config.metadataStoreUri}
|
No results found in {config.metadataCacheUri}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Logger } from '@oceanprotocol/lib'
|
import { Logger } from '@oceanprotocol/lib'
|
||||||
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatastore/MetadataStore'
|
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import Loader from '../../atoms/Loader'
|
import Loader from '../../atoms/Loader'
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import SearchBar from '../molecules/SearchBar'
|
import SearchBar from '../molecules/SearchBar'
|
||||||
import styles from './Home.module.css'
|
import styles from './Home.module.css'
|
||||||
import { MetadataStore, Logger } from '@oceanprotocol/lib'
|
import { MetadataCache, Logger } from '@oceanprotocol/lib'
|
||||||
import AssetList from '../organisms/AssetList'
|
import AssetList from '../organisms/AssetList'
|
||||||
import {
|
import {
|
||||||
QueryResult,
|
QueryResult,
|
||||||
SearchQuery
|
SearchQuery
|
||||||
} from '@oceanprotocol/lib/dist/node/metadatastore/MetadataStore'
|
} from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
import Container from '../atoms/Container'
|
import Container from '../atoms/Container'
|
||||||
import Loader from '../atoms/Loader'
|
import Loader from '../atoms/Loader'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
@ -15,7 +15,14 @@ const queryHighest = {
|
|||||||
page: 1,
|
page: 1,
|
||||||
offset: 3,
|
offset: 3,
|
||||||
query: { 'price.type': ['pool'] },
|
query: { 'price.type': ['pool'] },
|
||||||
sort: { 'price.value': 1 }
|
sort: { 'price.ocean': -1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryPoolsLatest = {
|
||||||
|
page: 1,
|
||||||
|
offset: 6,
|
||||||
|
query: { 'price.type': ['pool'] },
|
||||||
|
sort: { created: -1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryLatest = {
|
const queryLatest = {
|
||||||
@ -25,10 +32,10 @@ const queryLatest = {
|
|||||||
sort: { created: -1 }
|
sort: { created: -1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAssets(query: SearchQuery, metadataStoreUri: string) {
|
async function getAssets(query: SearchQuery, metadataCacheUri: string) {
|
||||||
try {
|
try {
|
||||||
const metadataStore = new MetadataStore(metadataStoreUri, Logger)
|
const metadataCache = new MetadataCache(metadataCacheUri, Logger)
|
||||||
const result = await metadataStore.queryMetadata(query)
|
const result = await metadataCache.queryMetadata(query)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -39,6 +46,9 @@ async function getAssets(query: SearchQuery, metadataStoreUri: string) {
|
|||||||
export default function HomePage(): ReactElement {
|
export default function HomePage(): ReactElement {
|
||||||
const { config } = useOcean()
|
const { config } = useOcean()
|
||||||
const [queryResultLatest, setQueryResultLatest] = useState<QueryResult>()
|
const [queryResultLatest, setQueryResultLatest] = useState<QueryResult>()
|
||||||
|
const [queryResultPoolsLatest, setQueryResultPoolsLatest] = useState<
|
||||||
|
QueryResult
|
||||||
|
>()
|
||||||
const [queryResultHighest, setQueryResultHighest] = useState<QueryResult>()
|
const [queryResultHighest, setQueryResultHighest] = useState<QueryResult>()
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
@ -46,19 +56,25 @@ export default function HomePage(): ReactElement {
|
|||||||
async function init() {
|
async function init() {
|
||||||
const queryResultHighest = await getAssets(
|
const queryResultHighest = await getAssets(
|
||||||
queryHighest,
|
queryHighest,
|
||||||
config.metadataStoreUri
|
config.metadataCacheUri
|
||||||
)
|
)
|
||||||
setQueryResultHighest(queryResultHighest)
|
setQueryResultHighest(queryResultHighest)
|
||||||
|
|
||||||
|
const queryResultPoolsLatest = await getAssets(
|
||||||
|
queryPoolsLatest,
|
||||||
|
config.metadataCacheUri
|
||||||
|
)
|
||||||
|
setQueryResultPoolsLatest(queryResultPoolsLatest)
|
||||||
|
|
||||||
const queryResultLatest = await getAssets(
|
const queryResultLatest = await getAssets(
|
||||||
queryLatest,
|
queryLatest,
|
||||||
config.metadataStoreUri
|
config.metadataCacheUri
|
||||||
)
|
)
|
||||||
setQueryResultLatest(queryResultLatest)
|
setQueryResultLatest(queryResultLatest)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
init()
|
init()
|
||||||
}, [config.metadataStoreUri])
|
}, [config.metadataCacheUri])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -67,7 +83,7 @@ export default function HomePage(): ReactElement {
|
|||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<section className={styles.latest}>
|
<section className={styles.latest}>
|
||||||
<h3>Highest Liquidity</h3>
|
<h3>Highest Liquidity Pools</h3>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Loader />
|
<Loader />
|
||||||
) : (
|
) : (
|
||||||
@ -76,7 +92,18 @@ export default function HomePage(): ReactElement {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className={styles.latest}>
|
<section className={styles.latest}>
|
||||||
<h3>Latest</h3>
|
<h3>New Liquidity Pools</h3>
|
||||||
|
{loading ? (
|
||||||
|
<Loader />
|
||||||
|
) : (
|
||||||
|
queryResultPoolsLatest && (
|
||||||
|
<AssetList queryResult={queryResultPoolsLatest} />
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className={styles.latest}>
|
||||||
|
<h3>New Data Sets</h3>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Loader />
|
<Loader />
|
||||||
) : (
|
) : (
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import Alert from '../../atoms/Alert'
|
import Alert from '../../atoms/Alert'
|
||||||
import Success from './Success'
|
|
||||||
import Button from '../../atoms/Button'
|
import Button from '../../atoms/Button'
|
||||||
import Loader from '../../atoms/Loader'
|
import Loader from '../../atoms/Loader'
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import styles from './Feedback.module.css'
|
import styles from './Feedback.module.css'
|
||||||
|
import SuccessConfetti from '../../atoms/SuccessConfetti'
|
||||||
|
|
||||||
export default function Feedback({
|
export default function Feedback({
|
||||||
error,
|
error,
|
||||||
@ -18,6 +18,17 @@ export default function Feedback({
|
|||||||
publishStepText: string
|
publishStepText: string
|
||||||
setError: (error: string) => void
|
setError: (error: string) => void
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
const SuccessAction = () => (
|
||||||
|
<Button
|
||||||
|
style="primary"
|
||||||
|
size="small"
|
||||||
|
href={`/asset/${did}`}
|
||||||
|
className={styles.action}
|
||||||
|
>
|
||||||
|
Go to data set →
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.feedback}>
|
<div className={styles.feedback}>
|
||||||
<div className={styles.box}>
|
<div className={styles.box}>
|
||||||
@ -35,7 +46,7 @@ export default function Feedback({
|
|||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
) : success ? (
|
) : success ? (
|
||||||
<Success success={success} did={did} />
|
<SuccessConfetti success={success} action={<SuccessAction />} />
|
||||||
) : (
|
) : (
|
||||||
<Loader message={publishStepText} />
|
<Loader message={publishStepText} />
|
||||||
)}
|
)}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { ReactElement, useEffect, FormEvent } from 'react'
|
import React, { ReactElement, useEffect, FormEvent } from 'react'
|
||||||
import styles from './PublishForm.module.css'
|
import styles from './PublishForm.module.css'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import { useFormikContext, Form, Field } from 'formik'
|
import { useFormikContext, Field } from 'formik'
|
||||||
import Input from '../../atoms/Input'
|
import Input from '../../atoms/Input'
|
||||||
import Button from '../../atoms/Button'
|
import Button from '../../atoms/Button'
|
||||||
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
||||||
@ -37,7 +37,7 @@ export default function PublishForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<form
|
||||||
className={styles.form}
|
className={styles.form}
|
||||||
// do we need this?
|
// do we need this?
|
||||||
onChange={() => status === 'empty' && setStatus(null)}
|
onChange={() => status === 'empty' && setStatus(null)}
|
||||||
@ -61,6 +61,6 @@ export default function PublishForm({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</footer>
|
</footer>
|
||||||
</Form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
.action {
|
|
||||||
margin-top: calc(var(--spacer) / 1.5);
|
|
||||||
}
|
|
@ -3,7 +3,7 @@ import { Router } from '@reach/router'
|
|||||||
import AssetContent from '../../components/organisms/AssetContent'
|
import AssetContent from '../../components/organisms/AssetContent'
|
||||||
import Layout from '../../components/Layout'
|
import Layout from '../../components/Layout'
|
||||||
import { MetadataMarket } from '../../@types/MetaData'
|
import { MetadataMarket } from '../../@types/MetaData'
|
||||||
import { MetadataStore, Logger, DDO } from '@oceanprotocol/lib'
|
import { MetadataCache, Logger, DDO } from '@oceanprotocol/lib'
|
||||||
import Alert from '../../components/atoms/Alert'
|
import Alert from '../../components/atoms/Alert'
|
||||||
import Loader from '../../components/atoms/Loader'
|
import Loader from '../../components/atoms/Loader'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
@ -24,12 +24,12 @@ export default function PageTemplateAssetDetails({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function init() {
|
async function init() {
|
||||||
try {
|
try {
|
||||||
const metadataStore = new MetadataStore(config.metadataStoreUri, Logger)
|
const metadataCache = new MetadataCache(config.metadataCacheUri, Logger)
|
||||||
const ddo = await metadataStore.retrieveDDO(did)
|
const ddo = await metadataCache.retrieveDDO(did)
|
||||||
|
|
||||||
if (!ddo) {
|
if (!ddo) {
|
||||||
setTitle('Could not retrieve asset')
|
setTitle('Could not retrieve asset')
|
||||||
setError('The DDO was not found in MetadataStore.')
|
setError('The DDO was not found in MetadataCache.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ export default function PageTemplateAssetDetails({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
init()
|
init()
|
||||||
}, [did, config.metadataStoreUri])
|
}, [did, config.metadataCacheUri])
|
||||||
|
|
||||||
return did && metadata ? (
|
return did && metadata ? (
|
||||||
<Layout title={title} uri={uri}>
|
<Layout title={title} uri={uri}>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { ReactElement, useState, useEffect } from 'react'
|
import React, { ReactElement, useState, useEffect } from 'react'
|
||||||
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatastore/MetadataStore'
|
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
import SearchBar from '../../molecules/SearchBar'
|
import SearchBar from '../../molecules/SearchBar'
|
||||||
import AssetList from '../../organisms/AssetList'
|
import AssetList from '../../organisms/AssetList'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
@ -28,12 +28,12 @@ export default function SearchPage({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function initSearch() {
|
async function initSearch() {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const queryResult = await getResults(parsed, config.metadataStoreUri)
|
const queryResult = await getResults(parsed, config.metadataCacheUri)
|
||||||
setQueryResult(queryResult)
|
setQueryResult(queryResult)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
initSearch()
|
initSearch()
|
||||||
}, [text, tag, page, config.metadataStoreUri])
|
}, [text, tag, page, config.metadataCacheUri])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.grid}>
|
<section className={styles.grid}>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
SearchQuery,
|
SearchQuery,
|
||||||
QueryResult
|
QueryResult
|
||||||
} from '@oceanprotocol/lib/dist/node/metadatastore/MetadataStore'
|
} from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
import { MetadataStore, Logger } from '@oceanprotocol/lib'
|
import { MetadataCache, Logger } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
export function getSearchQuery(
|
export function getSearchQuery(
|
||||||
page?: string | string[],
|
page?: string | string[],
|
||||||
@ -30,12 +30,12 @@ export function getSearchQuery(
|
|||||||
|
|
||||||
export async function getResults(
|
export async function getResults(
|
||||||
params: { text?: string; tag?: string; page?: string; offset?: string },
|
params: { text?: string; tag?: string; page?: string; offset?: string },
|
||||||
metadataStoreUri: string
|
metadataCacheUri: string
|
||||||
): Promise<QueryResult> {
|
): Promise<QueryResult> {
|
||||||
const { text, tag, page, offset } = params
|
const { text, tag, page, offset } = params
|
||||||
|
|
||||||
const metadataStore = new MetadataStore(metadataStoreUri, Logger)
|
const metadataCache = new MetadataCache(metadataCacheUri, Logger)
|
||||||
const queryResult = await metadataStore.queryMetadata(
|
const queryResult = await metadataCache.queryMetadata(
|
||||||
getSearchQuery(page, offset, text, tag)
|
getSearchQuery(page, offset, text, tag)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import appConfig from '../../app.config'
|
|||||||
import { Logger } from '@oceanprotocol/lib'
|
import { Logger } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
export function NetworkMonitor(): ReactElement {
|
export function NetworkMonitor(): ReactElement {
|
||||||
const { metadataStoreUri } = appConfig
|
const { metadataCacheUri } = appConfig
|
||||||
const { connect, web3Provider } = useOcean()
|
const { connect, web3Provider } = useOcean()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -16,8 +16,8 @@ export function NetworkMonitor(): ReactElement {
|
|||||||
|
|
||||||
const newConfig = {
|
const newConfig = {
|
||||||
...initialConfig,
|
...initialConfig,
|
||||||
// add metadataStoreUri only when defined
|
// add metadataCacheUri only when defined
|
||||||
...(metadataStoreUri && { metadataStoreUri })
|
...(metadataCacheUri && { metadataCacheUri })
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -32,7 +32,7 @@ export function NetworkMonitor(): ReactElement {
|
|||||||
return () => {
|
return () => {
|
||||||
web3Provider.removeListener('chainChanged', handleNetworkChanged)
|
web3Provider.removeListener('chainChanged', handleNetworkChanged)
|
||||||
}
|
}
|
||||||
}, [web3Provider, connect, metadataStoreUri])
|
}, [web3Provider, connect, metadataCacheUri])
|
||||||
|
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,13 @@ export default function wrapRootElement({
|
|||||||
}: {
|
}: {
|
||||||
element: ReactElement
|
element: ReactElement
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { metadataStoreUri, network } = appConfig
|
const { metadataCacheUri, network } = appConfig
|
||||||
const oceanInitialConfig = getOceanConfig(network)
|
const oceanInitialConfig = getOceanConfig(network)
|
||||||
|
|
||||||
const initialConfig = {
|
const initialConfig = {
|
||||||
...oceanInitialConfig,
|
...oceanInitialConfig,
|
||||||
// add metadataStoreUri only when defined
|
// add metadataCacheUri only when defined
|
||||||
...(metadataStoreUri && { metadataStoreUri })
|
...(metadataCacheUri && { metadataCacheUri })
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -17,7 +17,6 @@ const query = graphql`
|
|||||||
infuraProjectId
|
infuraProjectId
|
||||||
network
|
network
|
||||||
marketFeeAddress
|
marketFeeAddress
|
||||||
marketFeeAmount
|
|
||||||
currencies
|
currencies
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import loadable from '@loadable/component'
|
|
||||||
import { infuraProjectId, network } from '../../app.config'
|
import { infuraProjectId, network } from '../../app.config'
|
||||||
|
import WalletConnectProvider from '@walletconnect/web3-provider'
|
||||||
|
// import Torus from '@toruslabs/torus-embed'
|
||||||
|
|
||||||
const web3ModalTheme = {
|
const web3ModalTheme = {
|
||||||
background: 'var(--brand-white)',
|
background: 'var(--brand-white)',
|
||||||
@ -9,28 +10,23 @@ const web3ModalTheme = {
|
|||||||
hover: 'var(--brand-grey-dimmed)'
|
hover: 'var(--brand-grey-dimmed)'
|
||||||
}
|
}
|
||||||
|
|
||||||
const WalletConnectProvider = loadable(
|
|
||||||
() => import('@walletconnect/web3-provider') as any
|
|
||||||
)
|
|
||||||
const Torus = loadable(() => import('@toruslabs/torus-embed') as any)
|
|
||||||
|
|
||||||
const providerOptions = {
|
const providerOptions = {
|
||||||
walletconnect: {
|
walletconnect: {
|
||||||
package: WalletConnectProvider,
|
package: WalletConnectProvider,
|
||||||
options: {
|
options: {
|
||||||
infuraId: infuraProjectId
|
infuraId: infuraProjectId
|
||||||
}
|
}
|
||||||
},
|
|
||||||
torus: {
|
|
||||||
package: Torus,
|
|
||||||
options: {
|
|
||||||
networkParams: {
|
|
||||||
// host: oceanConfig.url // optional
|
|
||||||
// chainId: 1337, // optional
|
|
||||||
// networkId: 1337 // optional
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// torus: {
|
||||||
|
// package: Torus,
|
||||||
|
// options: {
|
||||||
|
// networkParams: {
|
||||||
|
// // host: oceanConfig.url // optional
|
||||||
|
// // chainId: 1337, // optional
|
||||||
|
// // networkId: 1337 // optional
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const web3ModalOpts = {
|
export const web3ModalOpts = {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import ddo from '../../__fixtures__/ddo'
|
import ddo from '../../__fixtures__/ddo'
|
||||||
|
|
||||||
const metadataStore = {
|
const metadataCache = {
|
||||||
queryMetadata: () => {
|
queryMetadata: () => {
|
||||||
return {
|
return {
|
||||||
results: [] as any[],
|
results: [] as any[],
|
||||||
@ -11,13 +11,13 @@ const metadataStore = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const libMock = {
|
const libMock = {
|
||||||
MetadataStore: () => metadataStore,
|
MetadataStore: () => metadataCache,
|
||||||
DDO: () => ddo,
|
DDO: () => ddo,
|
||||||
ocean: {
|
ocean: {
|
||||||
accounts: {
|
accounts: {
|
||||||
list: () => ['xxx', 'xxx']
|
list: () => ['xxx', 'xxx']
|
||||||
},
|
},
|
||||||
metadataStore,
|
metadataCache,
|
||||||
// compute: {
|
// compute: {
|
||||||
// status: (account: string) => {
|
// status: (account: string) => {
|
||||||
// return [job]
|
// return [job]
|
||||||
|
Loading…
Reference in New Issue
Block a user