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

merge main

This commit is contained in:
Bogdan Fazakas 2022-07-22 06:41:40 +03:00
commit 2632e7ed0f
42 changed files with 273 additions and 819 deletions

View File

@ -14,7 +14,7 @@ jobs:
- uses: actions/setup-node@v2
- run: npm ci --legacy-peer-deps
- run: npm run build
- run: npm run build:static
env:
NEXT_PUBLIC_INFURA_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_INFURA_PROJECT_ID }}

View File

@ -50,6 +50,8 @@ cd market
nvm use
npm install
# in case of dependency errors, rather use:
# npm install --legacy-peer-deps
npm start
```

View File

@ -16,16 +16,6 @@
"marketplaceFee": "Goes to the marketplace owner that is hosting and providing the marketplace and is collected when downloading or using an asset in a compute job. In Ocean Market, it is treated as network revenue that goes to the Ocean community."
}
},
"dynamic": {
"title": "Dynamic",
"info": "Let's create a decentralized, automated market for your data set. The datatoken for this data set will be worth the entered amount of OCEAN. Additionally, you will provide liquidity into a Datatoken/OCEAN liquidity pool with Balancer.",
"tooltips": {
"poolInfo": "The liquidity pool provides the funds for traders to trade against. The price of the asset is determined by the ratio of OCEAN to datatokens.",
"swapFee": "Liquidity providers earn this fee on all pool trades, proportionally to their share of the pool. The fee is set by the creator of the pool and is used to incentivize liquidity providers to join the pool.",
"communityFee": "Goes to Ocean DAO for teams to improve the tools, build apps, do outreach, and more. A small fraction is used to burn OCEAN. This fee is collected when downloading or using an asset in a compute job.",
"marketplaceFee": "Goes to the marketplace owner that is hosting and providing the marketplace and is collected when downloading or using an asset in a compute job. In Ocean Market, it is treated as network revenue that goes to the Ocean community."
}
},
"free": {
"title": "Free",
"info": "Set your data set as free. The datatoken for this data set will be given for free via creating a faucet.",
@ -47,15 +37,6 @@
"approveSpecific": "Give the smart contract permission to spend your COIN which has to be done for each transaction. You can optionally set this to infinite in your user preferences.",
"approveInfinite": "Give the smart contract permission to spend infinte amounts of your COIN so you have to do this only once. You can disable allowing infinite amounts in your user preferences."
},
"add": {
"title": "Add Liquidity",
"output": {
"help": "Providing liquidity will earn you SWAPFEE% on every transaction in this pool, proportionally to your share of the pool.",
"titleIn": "You will receive",
"titleOut": "Pool conversion"
},
"action": "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.",

44
package-lock.json generated
View File

@ -13,7 +13,7 @@
"@coingecko/cryptoformat": "^0.5.4",
"@loadable/component": "^5.15.2",
"@oceanprotocol/art": "^3.2.0",
"@oceanprotocol/lib": "^1.1.5",
"@oceanprotocol/lib": "^1.1.6",
"@oceanprotocol/typographies": "^0.1.0",
"@tippyjs/react": "^4.2.6",
"@urql/exchange-refocus": "^0.2.5",
@ -4598,9 +4598,9 @@
"integrity": "sha512-rDCIooe1WHipLejuGhx2Wv/88SB7bWrN3+XHCWxXyPKTmmSQsgxKZPPzbIVBQ0ESChQZqGSBBJyqErqwwW4eBw=="
},
"node_modules/@oceanprotocol/lib": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-1.1.5.tgz",
"integrity": "sha512-quc2SGAr8G1v664ll3eOystA2v94OQleW6KGKhVWEPXDldnNAAhlG/QTi86XWRU9HmncGE7OghC5am+9DRGWcQ==",
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-1.1.6.tgz",
"integrity": "sha512-n1ync5LYBjJDg9Znq61zajnkeXFeFGOU8dN2LCeewArljCOdfYW/SEgQtiLALQb1dgqsYSjMHym40O2jPTUxoQ==",
"dependencies": {
"@oceanprotocol/contracts": "^1.0.0",
"bignumber.js": "^9.0.2",
@ -35024,9 +35024,9 @@
}
},
"node_modules/parse-path": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz",
"integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.4.tgz",
"integrity": "sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==",
"dev": true,
"dependencies": {
"is-ssh": "^1.3.0",
@ -35054,14 +35054,14 @@
}
},
"node_modules/parse-url": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz",
"integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz",
"integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==",
"dev": true,
"dependencies": {
"is-ssh": "^1.3.0",
"normalize-url": "^6.1.0",
"parse-path": "^4.0.0",
"parse-path": "^4.0.4",
"protocols": "^1.4.0"
}
},
@ -46660,16 +46660,15 @@
"integrity": "sha512-rDCIooe1WHipLejuGhx2Wv/88SB7bWrN3+XHCWxXyPKTmmSQsgxKZPPzbIVBQ0ESChQZqGSBBJyqErqwwW4eBw=="
},
"@oceanprotocol/lib": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-1.1.5.tgz",
"integrity": "sha512-quc2SGAr8G1v664ll3eOystA2v94OQleW6KGKhVWEPXDldnNAAhlG/QTi86XWRU9HmncGE7OghC5am+9DRGWcQ==",
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-1.1.6.tgz",
"integrity": "sha512-n1ync5LYBjJDg9Znq61zajnkeXFeFGOU8dN2LCeewArljCOdfYW/SEgQtiLALQb1dgqsYSjMHym40O2jPTUxoQ==",
"requires": {
"@oceanprotocol/contracts": "^1.0.0",
"bignumber.js": "^9.0.2",
"cross-fetch": "^3.1.5",
"crypto-js": "^4.1.1",
"decimal.js": "^10.3.1",
"web3": "^1.7.4",
"web3-core": "^1.7.1",
"web3-eth-contract": "^1.7.1"
}
@ -46721,7 +46720,6 @@
"integrity": "sha512-rmVKYEsKzurfRU0xJz+iHelbi1LGlihIWZ7Qvmb/CBz1EkhL7nOkW4SVXmG2dA5Ce0si2gr88i6q4eBOMRNJ1w==",
"dev": true,
"requires": {
"@oclif/config": "^1.18.2",
"@oclif/errors": "^1.3.5",
"@oclif/help": "^1.0.1",
"@oclif/parser": "^3.8.6",
@ -70390,9 +70388,9 @@
}
},
"parse-path": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz",
"integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.4.tgz",
"integrity": "sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==",
"dev": true,
"requires": {
"is-ssh": "^1.3.0",
@ -70416,14 +70414,14 @@
}
},
"parse-url": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz",
"integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz",
"integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==",
"dev": true,
"requires": {
"is-ssh": "^1.3.0",
"normalize-url": "^6.1.0",
"parse-path": "^4.0.0",
"parse-path": "^4.0.4",
"protocols": "^1.4.0"
}
},

View File

@ -7,6 +7,7 @@
"scripts": {
"start": "npm run pregenerate && next dev -p 8000",
"build": "npm run pregenerate && next build",
"build:static": "npm run build && next export",
"serve": "serve -s public/",
"pregenerate": "bash scripts/pregenerate.sh",
"test": "npm run pregenerate && npm run lint && npm run type-check && npm run jest",
@ -25,7 +26,7 @@
"@coingecko/cryptoformat": "^0.5.4",
"@loadable/component": "^5.15.2",
"@oceanprotocol/art": "^3.2.0",
"@oceanprotocol/lib": "^1.1.5",
"@oceanprotocol/lib": "^1.1.6",
"@oceanprotocol/typographies": "^0.1.0",
"@tippyjs/react": "^4.2.6",
"@urql/exchange-refocus": "^0.2.5",

View File

@ -10,7 +10,7 @@ AWS_S3_BUCKET="www-market"
set -e;
function s3sync {
aws s3 sync ./public s3://"$1" \
aws s3 sync ./out s3://"$1" \
--include "*" \
--exclude "*.html" \
--exclude "sw.js" \
@ -24,7 +24,7 @@ function s3sync {
--delete \
--acl public-read
aws s3 sync ./public s3://"$1" \
aws s3 sync ./out s3://"$1" \
--exclude "*" \
--include "*.html" \
--include "sw.js" \

View File

@ -9,6 +9,7 @@ interface BaseQueryParams {
nestedQuery?: any
esPaginationOptions?: EsPaginationOptions
sortOptions?: SortOptions
aggs?: any
filters?: FilterTerm[]
ignorePurgatory?: boolean
}

View File

@ -3,4 +3,5 @@ interface PagedAssets {
page: number
totalPages: number
totalResults: number
aggregations: any
}

View File

@ -5,7 +5,8 @@ export enum SortDirectionOptions {
export enum SortTermOptions {
Created = 'metadata.created',
Relevance = '_score'
Relevance = '_score',
Stats = 'stats.orders'
}
// Note: could not figure out how to get `enum` to be ambiant
@ -43,5 +44,6 @@ declare global {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
query: any
sort?: { [jsonPath: string]: SortDirectionOptions }
aggs?: any
}
}

View File

@ -55,6 +55,10 @@ export function generateBaseQuery(
}
} as SearchQuery
if (baseQueryParams.aggs !== undefined) {
generatedQuery.aggs = baseQueryParams.aggs
}
if (baseQueryParams.sortOptions !== undefined)
generatedQuery.sort = {
[baseQueryParams.sortOptions.sortBy]:
@ -74,12 +78,15 @@ export function transformQueryResult(
results: [],
page: 0,
totalPages: 0,
totalResults: 0
totalResults: 0,
aggregations: []
}
result.results = (queryResult.hits.hits || []).map(
(hit) => hit._source as Asset
)
result.aggregations = queryResult.aggregations
result.totalResults = queryResult.hits.total.value
result.totalPages =
result.totalResults / size < 1
@ -307,6 +314,14 @@ export async function getPublishedAssets(
sortBy: SortTermOptions.Created,
sortDirection: SortDirectionOptions.Descending
},
aggs: {
totalOrders: {
sum: {
field: SortTermOptions.Stats
}
}
},
ignorePurgatory: true,
esPaginationOptions: {
from: (Number(page) - 1 || 0) * 9,
size: 9
@ -314,6 +329,62 @@ export async function getPublishedAssets(
} as BaseQueryParams
const query = generateBaseQuery(baseQueryParams)
try {
const result = await queryMetadata(query, cancelToken)
return result
} catch (error) {
if (axios.isCancel(error)) {
LoggerInstance.log(error.message)
} else {
LoggerInstance.error(error.message)
}
}
}
export async function getTopPublishers(
chainIds: number[],
cancelToken: CancelToken,
page?: number,
type?: string,
accesType?: string
): Promise<PagedAssets> {
const filters: FilterTerm[] = []
accesType !== undefined &&
filters.push(getFilterTerm('services.type', accesType))
type !== undefined && filters.push(getFilterTerm('metadata.type', type))
const baseQueryParams = {
chainIds,
filters,
sortOptions: {
sortBy: SortTermOptions.Created,
sortDirection: SortDirectionOptions.Descending
},
aggs: {
topPublishers: {
terms: {
field: 'nft.owner.keyword',
order: { totalSales: 'desc' }
},
aggs: {
totalSales: {
sum: {
field: SortTermOptions.Stats
}
}
}
}
},
esPaginationOptions: {
from: (Number(page) - 1 || 0) * 9,
size: 9
}
} as BaseQueryParams
const query = generateBaseQuery(baseQueryParams)
try {
const result = await queryMetadata(query, cancelToken)
return result

View File

@ -26,6 +26,7 @@ import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
import { transformAssetToAssetSelection } from './assetConvertor'
import { AssetExtended } from 'src/@types/AssetExtended'
import { ComputeEditForm } from 'src/components/Asset/Edit/_types'
import { getFileDidInfo } from './provider'
const getComputeOrders = gql`
query ComputeOrders($user: String!) {
@ -352,12 +353,18 @@ export async function createTrustedAlgorithmList(
tag: selectedAlgorithm.metadata.algorithm.container.tag,
checksum: selectedAlgorithm.metadata.algorithm.container.checksum
}
const filesChecksum = await getFileDidInfo(
selectedAlgorithm?.id,
selectedAlgorithm?.services?.[0].id,
selectedAlgorithm?.services?.[0]?.serviceEndpoint,
true
)
const trustedAlgorithm = {
did: selectedAlgorithm.id,
containerSectionChecksum: getHash(
JSON.stringify(sanitizedAlgorithmContainer)
),
filesChecksum: getHash(selectedAlgorithm.services[0].files)
filesChecksum: filesChecksum?.[0]?.checksum
}
trustedAlgorithms.push(trustedAlgorithm)
}

View File

@ -67,13 +67,15 @@ export async function getEncryptedFiles(
export async function getFileDidInfo(
did: string,
serviceId: string,
providerUrl: string
providerUrl: string,
withChecksum = false
): Promise<FileInfo[]> {
try {
const response = await ProviderInstance.checkDidFiles(
did,
serviceId as any, // TODO: why does ocean.js want a number here?
providerUrl
serviceId,
providerUrl,
withChecksum
)
return response
} catch (error) {

View File

@ -18,7 +18,7 @@ import { OpcFeesQuery as OpcFeesData } from '../@types/subgraph/OpcFeesQuery'
import { calcSingleOutGivenPoolIn } from './pool'
import Decimal from 'decimal.js'
import { MAX_DECIMALS } from './constants'
import { getPublishedAssets, getTopPublishers } from '@utils/aquarius'
export interface UserLiquidity {
price: string
oceanBalance: string
@ -172,19 +172,11 @@ const UserSalesQuery = gql`
}
`
// TODO: figure out some way to get this
const TopSalesQuery = gql`
query TopSalesQuery {
users(
first: 20
orderBy: sharesOwned
orderDirection: desc
where: { tokenBalancesOwned_not: "0" }
) {
users(first: 20, orderBy: totalSales, orderDirection: desc) {
id
tokenBalancesOwned {
value
}
totalSales
}
}
`
@ -419,20 +411,10 @@ export async function getUserSales(
accountId: string,
chainIds: number[]
): Promise<number> {
const variables = { user: accountId?.toLowerCase() }
try {
const userSales = await fetchDataForMultipleChains(
UserSalesQuery,
variables,
chainIds
)
let salesSum = 0
for (let i = 0; i < userSales.length; i++) {
if (userSales[i].users.length > 0) {
salesSum += parseInt(userSales[i].users[0].totalSales)
}
}
return salesSum
const result = await getPublishedAssets(accountId, chainIds, null)
const { totalOrders } = result.aggregations
return totalOrders.value
} catch (error) {
LoggerInstance.error('Error getUserSales', error.message)
}
@ -442,33 +424,19 @@ export async function getTopAssetsPublishers(
chainIds: number[],
nrItems = 9
): Promise<AccountTeaserVM[]> {
const publisherSales: AccountTeaserVM[] = []
const publishers: AccountTeaserVM[] = []
for (const chain of chainIds) {
const queryContext = getQueryContext(Number(chain))
const fetchedUsers: OperationResult<UsersSalesList> = await fetchData(
TopSalesQuery,
null,
queryContext
)
for (let i = 0; i < fetchedUsers.data.users.length; i++) {
const publishersIndex = publisherSales.findIndex(
(user) => fetchedUsers.data.users[i].id === user.address
)
if (publishersIndex === -1) {
const publisher: AccountTeaserVM = {
address: fetchedUsers.data.users[i].id,
nrSales: fetchedUsers.data.users[i].totalSales
}
publisherSales.push(publisher)
} else {
publisherSales[publishersIndex].nrSales +=
publisherSales[publishersIndex].nrSales
}
}
const result = await getTopPublishers(chainIds, null)
const { topPublishers } = result.aggregations
for (let i = 0; i < topPublishers.buckets.length; i++) {
publishers.push({
address: topPublishers.buckets[i].key,
nrSales: parseInt(topPublishers.buckets[i].totalSales.value)
})
}
publisherSales.sort((a, b) => b.nrSales - a.nrSales)
publishers.sort((a, b) => b.nrSales - a.nrSales)
return publisherSales.slice(0, nrItems)
return publishers.slice(0, nrItems)
}

View File

@ -1,5 +1,5 @@
import React, { ReactElement } from 'react'
import styles from './AssetList.module.css'
import styles from './index.module.css'
import classNames from 'classnames/bind'
import Loader from '../atoms/Loader'
import { useUserPreferences } from '@context/UserPreferences'
@ -29,7 +29,7 @@ export default function AccountList({
const { chainIds } = useUserPreferences()
const styleClasses = cx({
assetList: true,
accountList: true,
[className]: className
})

View File

@ -0,0 +1,24 @@
.accountList {
display: grid;
grid-template-columns: 1fr;
gap: calc(var(--spacer) / 2);
}
@media screen and (min-width: 25rem) {
.accountList {
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
gap: var(--spacer);
}
}
.empty {
color: var(--color-secondary);
font-size: var(--font-size-small);
font-style: italic;
}
.loaderWrap {
display: flex;
justify-content: center;
align-items: center;
}

View File

@ -1,46 +1,39 @@
.blockies {
aspect-ratio: 1/1;
width: 13%;
height: 13%;
width: calc(var(--font-size-large) * 2) !important;
height: calc(var(--font-size-large) * 2) !important;
border-radius: 50%;
margin-left: 0;
margin-right: calc(var(--spacer) / 4);
margin-right: calc(var(--spacer) / 3);
}
.teaser {
max-width: 40rem;
height: 100%;
}
.link {
composes: box from '../atoms/Box.module.css';
padding: calc(var(--spacer) / 2) !important;
font-size: var(--font-size-mini);
height: 90%;
padding: calc(var(--spacer) / 3) calc(var(--spacer) / 2);
color: var(--color-secondary);
position: relative;
display: flex;
align-items: center;
}
.link span {
font-size: var(--font-size-large);
margin-right: calc(var(--spacer) / 3);
}
.name {
margin-bottom: 0;
font-size: var(--font-size-base) !important;
padding-top: calc(var(--spacer) / 4);
}
.header {
display: flex;
flex-direction: row;
align-items: center;
}
.sales {
font-size: small;
margin-top: -5px !important;
margin-bottom: clac(var(--spacer) / 2);
.place {
font-size: var(--font-size-large);
margin-right: calc(var(--spacer) / 2);
}
.name {
margin-bottom: 0;
font-size: var(--font-size-base);
padding-top: calc(var(--spacer) / 5);
color: var(--font-color-text);
}
.sales {
margin: 0;
}
.sales span {
font-weight: var(--font-weight-bold);
color: var(--font-color-text);
}

View File

@ -33,34 +33,26 @@ export default function AccountTeaser({
}, [accountTeaserVM, newCancelToken])
return (
<article className={styles.teaser}>
<Link href={`/profile/${accountTeaserVM.address}`}>
<header className={styles.header}>
{place && <span>{place}</span>}
{profile?.image ? (
<img src={profile.image} className={styles.blockies} />
) : (
<Blockies
accountId={accountTeaserVM.address}
className={styles.blockies}
/>
)}
<div>
<Dotdotdot clamp={3}>
<h3 className={styles.name}>
{profile?.name
? profile?.name
: accountTruncate(accountTeaserVM.address)}
</h3>
</Dotdotdot>
<p className={styles.sales}>
{`${accountTeaserVM.nrSales} ${
accountTeaserVM.nrSales === 1 ? 'sale' : 'sales'
}`}
</p>
</div>
</header>
</Link>
</article>
<Link href={`/profile/${accountTeaserVM.address}`}>
<a className={styles.teaser}>
{place && <span className={styles.place}>{place}</span>}
<Blockies
accountId={accountTeaserVM.address}
className={styles.blockies}
image={profile?.image}
/>
<div>
<Dotdotdot tagName="h4" clamp={2} className={styles.name}>
{profile?.name
? profile?.name
: accountTruncate(accountTeaserVM.address)}
</Dotdotdot>
<p className={styles.sales}>
<span>{accountTeaserVM.nrSales}</span>
{`${accountTeaserVM.nrSales === 1 ? ' sale' : ' sales'}`}
</p>
</div>
</a>
</Link>
)
}

View File

@ -24,14 +24,16 @@ export default function AssetTeaser({
const isCompute = Boolean(getServiceByName(asset, 'compute'))
const accessType = isCompute ? 'compute' : 'access'
const { owner } = asset.nft
const { orders } = asset.stats
return (
<article className={`${styles.teaser} ${styles[type]}`}>
<Link href={`/asset/${asset.id}`}>
<a className={styles.link}>
<header className={styles.header}>
<div className={styles.symbol}>{datatokens[0]?.symbol}</div>
<Dotdotdot clamp={3}>
<h1 className={styles.title}>{name}</h1>
<Dotdotdot tagName="h1" clamp={3} className={styles.title}>
{name}
</Dotdotdot>
{!noPublisher && (
<Publisher account={owner} minimal className={styles.publisher} />
@ -42,6 +44,7 @@ export default function AssetTeaser({
type={type}
accessType={accessType}
className={styles.typeDetails}
totalSales={orders}
/>
<div className={styles.content}>

View File

@ -1,26 +1,22 @@
import React, { ReactElement } from 'react'
import styles from './index.module.css'
import classNames from 'classnames/bind'
import Compute from '@images/compute.svg'
import Download from '@images/download.svg'
import Lock from '@images/lock.svg'
const cx = classNames.bind(styles)
export default function AssetType({
type,
accessType,
className
className,
totalSales
}: {
type: string
accessType: string
className?: string
totalSales?: number
}): ReactElement {
const styleClasses = cx({
[className]: className
})
return (
<div className={styleClasses}>
<div className={className || null}>
{accessType === 'access' ? (
<Download role="img" aria-label="Download" className={styles.icon} />
) : accessType === 'compute' && type === 'algorithm' ? (
@ -32,6 +28,12 @@ export default function AssetType({
<div className={styles.typeLabel}>
{type === 'dataset' ? 'data set' : 'algorithm'}
</div>
{totalSales ? (
<div className={styles.typeLabel}>
{`${totalSales} ${totalSales === 1 ? 'sale' : 'sales'}`}
</div>
) : null}
</div>
)
}

View File

@ -5,11 +5,13 @@ import styles from './index.module.css'
export interface BlockiesProps {
accountId: string
className?: string
image?: string
}
export default function Blockies({
accountId,
className
className,
image
}: BlockiesProps): ReactElement {
if (!accountId) return null
@ -18,7 +20,7 @@ export default function Blockies({
return (
<img
className={`${className || ''} ${styles.blockies} `}
src={blockies}
src={image || blockies}
alt="Blockies"
aria-hidden="true"
/>

View File

@ -3,7 +3,7 @@
margin-top: calc(var(--spacer) / 1.5);
padding: calc(var(--spacer) / 1.5);
background: var(--background-highlight);
margin-bottom: -2rem;
margin-bottom: -1rem;
}
.actions [class*='rdt_Pagination'] {

View File

@ -1,6 +0,0 @@
.buttonMax {
position: absolute;
font-size: var(--font-size-mini);
bottom: calc(var(--spacer) / 2.6);
right: calc(var(--spacer) * 2.5);
}

View File

@ -1,114 +0,0 @@
import React, { ReactElement, useEffect } from 'react'
import styles from './FormAdd.module.css'
import Input from '@shared/FormInput'
import Error from '@shared/FormInput/Error'
import { FormikContextType, useField, useFormikContext } from 'formik'
import Button from '@shared/atoms/Button'
import { FormAddLiquidity } from '.'
import UserLiquidity from '../../UserLiquidity'
import { useWeb3 } from '@context/Web3'
import { isValidNumber } from '@utils/numbers'
import Decimal from 'decimal.js'
import { useAsset } from '@context/Asset'
import { Pool } from '@oceanprotocol/lib'
import { usePool } from '@context/Pool'
export default function FormAdd({
amountMax,
setNewPoolTokens,
setNewPoolShare
}: {
amountMax: string
setNewPoolTokens: (value: string) => void
setNewPoolShare: (value: string) => void
}): ReactElement {
const { balance, web3 } = useWeb3()
const { isAssetNetwork } = useAsset()
const { poolData, poolInfo } = usePool()
// Connect with form
const {
setFieldValue,
values,
isSubmitting
}: FormikContextType<FormAddLiquidity> = useFormikContext()
const [field, meta] = useField('amount')
useEffect(() => {
async function calculatePoolShares() {
if (!web3 || !poolData?.id || !poolInfo?.totalPoolTokens) return
if (!values.amount || !poolInfo?.baseTokenAddress) {
setNewPoolTokens('0')
setNewPoolShare('0')
return
}
if (Number(values.amount) > Number(amountMax)) return
const poolInstance = new Pool(web3)
const poolTokens = await poolInstance.calcPoolOutGivenSingleIn(
poolData.id,
poolInfo.baseTokenAddress,
values.amount.toString(),
18,
poolInfo.baseTokenDecimals
)
setNewPoolTokens(poolTokens)
const newPoolShareDecimal =
isValidNumber(poolTokens) && isValidNumber(poolInfo.totalPoolTokens)
? new Decimal(poolTokens)
.dividedBy(
new Decimal(poolInfo.totalPoolTokens).plus(
new Decimal(poolTokens)
)
)
.mul(100)
.toString()
: '0'
setNewPoolShare(newPoolShareDecimal)
}
calculatePoolShares()
}, [
poolInfo?.baseTokenAddress,
poolInfo?.baseTokenDecimals,
web3,
values.amount,
poolInfo?.totalPoolTokens,
amountMax,
poolData?.id,
setNewPoolTokens,
setNewPoolShare
])
return (
<>
<UserLiquidity
amount={balance.ocean}
amountMax={amountMax}
symbol={poolInfo?.baseTokenSymbol}
/>
<Input
type="number"
min="0"
prefix={poolInfo?.baseTokenSymbol}
placeholder="0"
disabled={!isAssetNetwork || isSubmitting}
{...field}
additionalComponent={<Error meta={meta} />}
/>
{Number(balance.ocean) > 0 && (
<Button
className={styles.buttonMax}
style="text"
size="small"
disabled={!web3 || isSubmitting}
onClick={() => setFieldValue('amount', amountMax)}
>
Use Max
</Button>
)}
</>
)
}

View File

@ -1,13 +0,0 @@
.output {
padding-bottom: calc(var(--spacer) / 2);
}
.output p {
font-weight: var(--font-weight-bold);
margin-bottom: calc(var(--spacer) / 8);
font-size: var(--font-size-small);
}
.help {
text-align: center;
}

View File

@ -1,30 +0,0 @@
import React, { ReactElement } from 'react'
import FormHelp from '@shared/FormInput/Help'
import Token from '../../../../@shared/Token'
import styles from './Output.module.css'
import content from '../../../../../../content/price.json'
import { usePool } from '@context/Pool'
export default function Output({
newPoolTokens,
newPoolShare
}: {
newPoolTokens: string
newPoolShare: string
}): ReactElement {
const { help, titleIn } = content.pool.add.output
const { poolInfo } = usePool()
return (
<>
<FormHelp className={styles.help}>
{help.replace('SWAPFEE', poolInfo?.liquidityProviderSwapFee)}
</FormHelp>
<div className={styles.output}>
<p>{titleIn}</p>
<Token symbol="pool shares" balance={newPoolTokens} noIcon />
<Token symbol="% of pool" balance={newPoolShare} noIcon />
</div>
</>
)
}

View File

@ -1,24 +0,0 @@
.addInput {
margin: 0 auto calc(var(--spacer) / 1.5) auto;
background: var(--background-highlight);
padding: var(--spacer) calc(var(--spacer) * 2.5) calc(var(--spacer) * 1.2)
calc(var(--spacer) * 2.5);
border-bottom: 1px solid var(--border-color);
margin-top: -2rem;
margin-left: -2rem;
margin-right: -2rem;
position: relative;
}
.addInput input {
text-align: center;
}
.addInput div[class*='field'] {
margin-bottom: 0;
}
.warning {
margin-left: -3rem;
margin-right: -3rem;
}

View File

@ -1,174 +0,0 @@
import React, { ReactElement, useState, useEffect } from 'react'
import Header from '../Actions/Header'
import { toast } from 'react-toastify'
import Actions from '../Actions'
import * as Yup from 'yup'
import { Formik } from 'formik'
import FormAdd from './FormAdd'
import styles from './index.module.css'
import Alert from '@shared/atoms/Alert'
import { useUserPreferences } from '@context/UserPreferences'
import Output from './Output'
import DebugOutput from '@shared/DebugOutput'
import { useWeb3 } from '@context/Web3'
import { useAsset } from '@context/Asset'
import content from '../../../../../../content/price.json'
import { calcMaxExactIn, LoggerInstance, Pool } from '@oceanprotocol/lib'
import { usePool } from '@context/Pool'
import { MAX_DECIMALS } from '@utils/constants'
import { getMaxDecimalsValidation } from '@utils/numbers'
import Decimal from 'decimal.js'
export interface FormAddLiquidity {
amount: number
}
const initialValues: FormAddLiquidity = {
amount: 0
}
export default function Add({
setShowAdd
}: {
setShowAdd: (show: boolean) => void
}): ReactElement {
const { accountId, balance, web3 } = useWeb3()
const { isAssetNetwork } = useAsset()
const { poolData, poolInfo, fetchAllData } = usePool()
const { debug } = useUserPreferences()
const [txId, setTxId] = useState<string>()
const [amountMax, setAmountMax] = useState<string>()
const [newPoolTokens, setNewPoolTokens] = useState('0')
const [newPoolShare, setNewPoolShare] = useState('0')
// Live validation rules
// https://github.com/jquense/yup#number
const validationSchema: Yup.SchemaOf<FormAddLiquidity> = Yup.object().shape({
amount: Yup.number()
.min(0.00001, (param) => `Must be more or equal to ${param.min}`)
.max(
Number(amountMax),
`Maximum you can add is ${Number(amountMax).toFixed(2)} OCEAN`
)
.test(
'maxDigitsAfterDecimal',
`Must have maximum ${MAX_DECIMALS} decimal digits`,
(param) =>
getMaxDecimalsValidation(MAX_DECIMALS).test(param?.toString())
)
.required('Required')
})
// Get maximum amount for OCEAN
useEffect(() => {
if (
!web3 ||
!accountId ||
!isAssetNetwork ||
!poolData?.id ||
!poolInfo?.baseTokenAddress
)
return
async function getMaximum() {
try {
const poolInstance = new Pool(web3)
const poolReserve = await poolInstance.getReserve(
poolData.id,
poolInfo.baseTokenAddress,
poolInfo.baseTokenDecimals
)
const amountMaxPool = calcMaxExactIn(poolReserve)
const oceanDecimal = new Decimal(balance.ocean)
const amountMax = oceanDecimal.greaterThan(amountMaxPool)
? amountMaxPool
: oceanDecimal
setAmountMax(amountMax.toFixed(3, Decimal.ROUND_DOWN))
} catch (error) {
LoggerInstance.error(error.message)
}
}
getMaximum()
}, [
web3,
accountId,
isAssetNetwork,
poolData?.id,
poolInfo?.baseTokenAddress,
poolInfo?.baseTokenDecimals,
balance?.ocean
])
// Submit
async function handleAddLiquidity(amount: string, resetForm: () => void) {
const poolInstance = new Pool(web3)
const minPoolAmountOut = '0' // ? how to get? : you would get this value by using `calcPoolOutGivenSingleIn` and substracting slippage from that , like we don in trade. it is ok to be 0 here. We can change after we implement global slippage
try {
const result = await poolInstance.joinswapExternAmountIn(
accountId,
poolData?.id,
amount,
minPoolAmountOut
)
setTxId(result?.transactionHash)
fetchAllData()
resetForm()
} catch (error) {
LoggerInstance.error(error.message)
toast.error(error.message)
}
}
return (
<>
<Header
title={content.pool.add.title}
backAction={() => {
setShowAdd(false)
fetchAllData()
}}
/>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={async (values, { setSubmitting, resetForm }) => {
await handleAddLiquidity(values.amount.toString(), resetForm)
setSubmitting(false)
}}
>
{({ isSubmitting, setSubmitting, submitForm, values, isValid }) => (
<>
<div className={styles.addInput}>
<FormAdd
amountMax={amountMax}
setNewPoolTokens={setNewPoolTokens}
setNewPoolShare={setNewPoolShare}
/>
</div>
{/* TODO: will be fixed in #1481 <Output newPoolTokens={newPoolTokens} newPoolShare={newPoolShare} /> */}
<Actions
isDisabled={!isValid || !values.amount || values.amount === 0}
isLoading={isSubmitting}
loaderMessage="Adding Liquidity..."
successMessage="Successfully added liquidity."
actionName={content.pool.add.action}
action={submitForm}
amount={values.amount.toString()}
tokenAddress={poolInfo?.baseTokenAddress}
tokenSymbol={poolInfo?.baseTokenSymbol}
txId={txId}
setSubmitting={setSubmitting}
/>
{debug && <DebugOutput output={values} />}
</>
)}
</Formik>
</>
)
}

View File

@ -1,5 +1,12 @@
.removeInput {
composes: addInput from '../Add/index.module.css';
background: var(--background-highlight);
padding: var(--spacer) calc(var(--spacer) * 2.5) calc(var(--spacer) * 1.2)
calc(var(--spacer) * 2.5);
border-bottom: 1px solid var(--border-color);
margin-top: -2rem;
margin-left: -2rem;
margin-right: -2rem;
position: relative;
padding-left: calc(var(--spacer) * 2);
padding-right: calc(var(--spacer) * 2);
padding-bottom: calc(var(--spacer) / 2);

View File

@ -1,7 +1,6 @@
import React, { ReactElement, useState } from 'react'
import stylesActions from './Actions/index.module.css'
import Button from '@shared/atoms/Button'
import Add from './Add'
import Remove from './Remove'
import AssetActionHistoryTable from '../AssetActionHistoryTable'
import { useAsset } from '@context/Asset'
@ -12,43 +11,33 @@ import { usePool } from '@context/Pool'
import PoolSections from './Sections'
export default function Pool(): ReactElement {
const { isInPurgatory, asset, isAssetNetwork } = useAsset()
const { asset, isAssetNetwork } = useAsset()
const { hasUserAddedLiquidity } = usePool()
const { accountId } = useWeb3()
const [showAdd, setShowAdd] = useState(false)
const [showRemove, setShowRemove] = useState(false)
return (
<>
{showAdd ? (
<Add setShowAdd={setShowAdd} />
) : showRemove ? (
{showRemove ? (
<Remove setShowRemove={setShowRemove} />
) : (
<>
<PoolSections />
<div className={stylesActions.actions}>
<Button
style="primary"
size="small"
onClick={() => setShowAdd(true)}
disabled={isInPurgatory || !isAssetNetwork}
>
Add Liquidity
</Button>
{hasUserAddedLiquidity && (
{hasUserAddedLiquidity && (
<div className={stylesActions.actions}>
<Button
style="primary"
size="small"
onClick={() => setShowRemove(true)}
disabled={!isAssetNetwork}
>
Remove
Remove Liquidity
</Button>
)}
</div>
</div>
)}
{accountId && (
<AssetActionHistoryTable title="Your Pool Transactions">
<PoolTransactions

View File

@ -137,10 +137,7 @@ export default function AssetActions({
const tabs: TabsItem[] = [{ title: 'Use', content: UseContent }]
asset?.accessDetails?.type === 'dynamic' &&
tabs.push(
{ title: 'Pool', content: <Pool /> },
{ title: 'Trade', content: <Trade /> }
)
tabs.push({ title: 'Pool', content: <Pool /> })
return (
<>

View File

@ -51,7 +51,7 @@ export default function Edit({
const setPriceResp = await fixedRateInstance.setRate(
accountId,
asset.accessDetails.addressOrId,
newPrice
newPrice.toString()
)
LoggerInstance.log('[edit] setFixedRate result', setPriceResp)
if (!setPriceResp) {

View File

@ -1,26 +0,0 @@
.tooltipStats {
margin-bottom: calc(var(--spacer) / 3);
padding-bottom: calc(var(--spacer) / 3);
border-bottom: 1px solid var(--border-color);
}
.statsList {
composes: statsList from './index.module.css';
padding-bottom: 0;
}
.statsList,
.note {
padding: calc(var(--spacer) / 4);
}
.note {
margin-bottom: 0;
padding-top: 0;
font-size: var(--font-size-mini);
color: var(--color-secondary);
}
.network {
font-weight: var(--font-weight-bold);
}

View File

@ -1,47 +0,0 @@
import React, { ReactElement } from 'react'
import Conversion from '@shared/Price/Conversion'
import PriceUnit from '@shared/Price/PriceUnit'
import NetworkName from '@shared/NetworkName'
import styles from './Tooltip.module.css'
import { StatsValue } from './_types'
import content from '../../../../content/footer.json'
import Markdown from '@shared/Markdown'
export default function MarketStatsTooltip({
totalValueLockedInOcean,
poolCount,
totalOceanLiquidity,
mainChainIds
}: {
totalValueLockedInOcean: StatsValue
poolCount: StatsValue
totalOceanLiquidity: StatsValue
mainChainIds: number[]
}): ReactElement {
return (
<>
<ul className={styles.statsList}>
{mainChainIds?.map((chainId, key) => (
<li className={styles.tooltipStats} key={key}>
<NetworkName networkId={chainId} className={styles.network} />
<br />
<Conversion
price={totalValueLockedInOcean?.[chainId] || '0'}
hideApproximateSymbol
/>{' '}
<abbr title="Total Value Locked">TVL</abbr>
{' | '}
<strong>{poolCount?.[chainId] || '0'}</strong> pools
{' | '}
<PriceUnit
price={totalOceanLiquidity?.[chainId] || '0'}
symbol="OCEAN"
size="small"
/>
</li>
))}
</ul>
<Markdown className={styles.note} text={content.stats.note} />
</>
)
}

View File

@ -1,6 +1,4 @@
import React, { ReactElement } from 'react'
import Conversion from '@shared/Price/Conversion'
import PriceUnit from '@shared/Price/PriceUnit'
import { StatsTotal } from './_types'
export default function MarketStatsTotal({
@ -10,23 +8,9 @@ export default function MarketStatsTotal({
}): ReactElement {
return (
<>
<p>
<strong>{total.orders}</strong> orders across{' '}
<strong>{total.nfts}</strong> assets with{' '}
<strong>{total.datatokens}</strong> different datatokens.
</p>
<Conversion
price={`${total.totalValueLockedInOcean}`}
hideApproximateSymbol
/>{' '}
<abbr title="Total Value Locked">TVL</abbr> across{' '}
<strong>{total.pools}</strong> asset pools that contain{' '}
<PriceUnit
price={`${total.totalOceanLiquidity}`}
symbol="OCEAN"
size="small"
/>
, plus datatokens for each pool.
<strong>{total.orders}</strong> orders across{' '}
<strong>{total.nfts}</strong> assets with{' '}
<strong>{total.datatokens}</strong> different datatokens.
</>
)
}

View File

@ -3,18 +3,9 @@ import { gql } from 'urql'
export const queryGlobalStatistics = gql`
query FooterStatsValues {
globalStatistics {
poolCount
nftCount
datatokenCount
orderCount
totalLiquidity {
value
token {
address
name
symbol
}
}
}
}
`

View File

@ -3,9 +3,6 @@ export interface StatsValue {
}
export interface StatsTotal {
totalValueLockedInOcean: number
totalOceanLiquidity: number
pools: number
nfts: number
datatokens: number
orders: number

View File

@ -1,6 +1,5 @@
import React, { ReactElement, useCallback, useEffect, useState } from 'react'
import { OperationContext } from 'urql'
import Tooltip from '@shared/atoms/Tooltip'
import { fetchData, getSubgraphUri } from '@utils/subgraph'
import useNetworkMetadata, {
filterNetworksByType
@ -8,19 +7,15 @@ import useNetworkMetadata, {
import { LoggerInstance } from '@oceanprotocol/lib'
import styles from './index.module.css'
import { FooterStatsValues_globalStatistics as FooterStatsValuesGlobalStatistics } from 'src/@types/subgraph/FooterStatsValues'
import MarketStatsTooltip from './Tooltip'
import MarketStatsTotal from './Total'
import { queryGlobalStatistics } from './_queries'
import { usePrices } from '@context/Prices'
import { useUserPreferences } from '@context/UserPreferences'
import Decimal from 'decimal.js'
import { StatsTotal, StatsValue } from './_types'
import { StatsTotal } from './_types'
import { useMarketMetadata } from '@context/MarketMetadata'
import Tooltip from '@shared/atoms/Tooltip'
import Markdown from '@shared/Markdown'
import content from '../../../../content/footer.json'
const initialTotal: StatsTotal = {
totalValueLockedInOcean: 0,
totalOceanLiquidity: 0,
pools: 0,
nfts: 0,
datatokens: 0,
orders: 0
@ -29,17 +24,10 @@ const initialTotal: StatsTotal = {
export default function MarketStats(): ReactElement {
const { appConfig } = useMarketMetadata()
const { networksList } = useNetworkMetadata()
const { currency } = useUserPreferences()
const { prices } = usePrices()
const [mainChainIds, setMainChainIds] = useState<number[]>()
const [data, setData] = useState<{
[chainId: number]: FooterStatsValuesGlobalStatistics
}>()
const [totalValueLockedInOcean, setTotalValueLockedInOcean] =
useState<StatsValue>()
const [totalOceanLiquidity, setTotalOceanLiquidity] = useState<StatsValue>()
const [poolCount, setPoolCount] = useState<StatsValue>()
const [total, setTotal] = useState(initialTotal)
//
@ -98,34 +86,13 @@ export default function MarketStats(): ReactElement {
const newTotal: StatsTotal = {
...initialTotal // always start calculating beginning from initial 0 values
}
const newTVLInOcean: StatsValue = {}
const newTotalLiquidity: StatsValue = {}
const newPoolCount: StatsValue = {}
for (const chainId of mainChainIds) {
const baseTokenValue = data[chainId]?.totalLiquidity[0]?.value
try {
const totalValueLockedInOcean = baseTokenValue
? new Decimal(baseTokenValue).mul(2)
: new Decimal(0)
newTVLInOcean[chainId] = `${totalValueLockedInOcean}`
const totalOceanLiquidity = Number(baseTokenValue) || 0
newTotalLiquidity[chainId] = `${totalOceanLiquidity}`
const poolCount = data[chainId]?.poolCount || 0
newPoolCount[chainId] = `${poolCount}`
const nftCount = data[chainId]?.nftCount || 0
const datatokenCount = data[chainId]?.datatokenCount || 0
const orderCount = data[chainId]?.orderCount || 0
newTotal.totalValueLockedInOcean += totalValueLockedInOcean.toNumber()
newTotal.totalOceanLiquidity += totalOceanLiquidity
newTotal.pools += poolCount
newTotal.nfts += nftCount
newTotal.datatokens += datatokenCount
newTotal.orders += orderCount
@ -133,11 +100,9 @@ export default function MarketStats(): ReactElement {
LoggerInstance.error('Error data manipulation: ', error.message)
}
}
setTotalValueLockedInOcean(newTVLInOcean)
setTotalOceanLiquidity(newTotalLiquidity)
setPoolCount(newPoolCount)
setTotal(newTotal)
}, [data, mainChainIds, prices, currency])
}, [data, mainChainIds])
return (
<div className={styles.stats}>
@ -146,12 +111,7 @@ export default function MarketStats(): ReactElement {
<Tooltip
className={styles.info}
content={
<MarketStatsTooltip
totalValueLockedInOcean={totalValueLockedInOcean}
poolCount={poolCount}
totalOceanLiquidity={totalOceanLiquidity}
mainChainIds={mainChainIds}
/>
<Markdown className={styles.note} text={content.stats.note} />
}
/>
</>

View File

@ -1,8 +1,9 @@
import { useUserPreferences } from '@context/UserPreferences'
import { LoggerInstance } from '@oceanprotocol/lib'
import AccountList from '@shared/AccountList/AccountList'
import { getTopAssetsPublishers } from '@utils/subgraph'
import React, { ReactElement, useEffect, useState } from 'react'
import styles from './Home.module.css'
import styles from './index.module.css'
export default function PublishersWithMostSales({
title,
@ -17,18 +18,19 @@ export default function PublishersWithMostSales({
useEffect(() => {
async function init() {
setLoading(true)
if (chainIds.length === 0) {
const result: AccountTeaserVM[] = []
setResult(result)
setLoading(false)
} else {
try {
setLoading(true)
const publishers = await getTopAssetsPublishers(chainIds)
setResult(publishers)
setLoading(false)
} catch (error) {
// Logger.error(error.message)
LoggerInstance.error(error.message)
setLoading(false)
}
}
}

View File

@ -14,6 +14,7 @@ import styles from './index.module.css'
import { useIsMounted } from '@hooks/useIsMounted'
import { useCancelToken } from '@hooks/useCancelToken'
import { SortTermOptions } from '../../@types/aquarius/SearchQuery'
import PublishersWithMostSales from './PublishersWithMostSales'
async function getQueryHighest(
chainIds: number[]
@ -66,7 +67,8 @@ function SectionQueryResult({
results: [],
page: 0,
totalPages: 0,
totalResults: 0
totalResults: 0,
aggregations: undefined
}
setResult(result)
setLoading(false)
@ -153,6 +155,8 @@ export default function HomePage(): ReactElement {
</Button>
}
/>
<PublishersWithMostSales title="Publishers With Most Sales" />
</>
)
}

View File

@ -18,7 +18,7 @@ export default function PricingFields(): ReactElement {
// Connect with main publish form
const { values, setFieldValue } = useFormikContext<FormPublishData>()
const { pricing } = values
const { price, amountOcean, weightOnOcean, weightOnDataToken, type } = pricing
const { price, type } = pricing
// Switch type value upon tab change
function handleTabChange(tabName: string) {
@ -29,36 +29,11 @@ export default function PricingFields(): ReactElement {
type !== 'free' && setFieldValue('pricing.amountDataToken', 1000)
}
// Update ocean amount when price is changed
// Update price when price is changed
useEffect(() => {
if (type === 'fixed' || type === 'free') return
const amountOcean =
isValidNumber(weightOnOcean) && isValidNumber(price) && price > 0
? new Decimal(price).mul(new Decimal(weightOnOcean).mul(10)).mul(2)
: new Decimal(initialValues.pricing.amountOcean)
setFieldValue('pricing.amountOcean', amountOcean)
}, [price, weightOnOcean, type, setFieldValue])
// Update dataToken value when ocean amount is changed
useEffect(() => {
if (type === 'fixed' || type === 'free') return
const amountDataToken =
isValidNumber(amountOcean) &&
isValidNumber(weightOnOcean) &&
isValidNumber(price) &&
isValidNumber(weightOnDataToken) &&
price > 0
? new Decimal(amountOcean)
.dividedBy(new Decimal(weightOnOcean))
.dividedBy(new Decimal(price))
.mul(new Decimal(weightOnDataToken))
: new Decimal(initialValues.pricing.amountDataToken)
setFieldValue('pricing.amountDataToken', amountDataToken)
}, [amountOcean, weightOnOcean, weightOnDataToken, type, setFieldValue])
setFieldValue('pricing.price', price)
setFieldValue('pricing.type', type)
}, [price, setFieldValue, type])
const tabs = [
appConfig.allowFixedPricing === 'true'
@ -67,12 +42,6 @@ export default function PricingFields(): ReactElement {
content: <Fixed content={content.create.fixed} />
}
: undefined,
appConfig.allowDynamicPricing === 'true'
? {
title: content.create.dynamic.title,
content: <Dynamic content={content.create.dynamic} />
}
: undefined,
appConfig.allowFreePricing === 'true'
? {
title: content.create.free.title,
@ -85,7 +54,7 @@ export default function PricingFields(): ReactElement {
<Tabs
items={tabs}
handleTabChange={handleTabChange}
defaultIndex={type === 'dynamic' ? 1 : type === 'free' ? 2 : 0}
defaultIndex={type === 'free' ? 1 : 0}
className={styles.pricing}
showRadio
/>

View File

@ -82,13 +82,8 @@ export const initialValues: FormPublishData = {
],
pricing: {
price: 0,
type:
allowDynamicPricing === 'true'
? 'dynamic'
: allowFixedPricing === 'true'
? 'fixed'
: 'free',
amountDataToken: allowDynamicPricing === 'true' ? 100 : 1000,
type: allowFixedPricing === 'true' ? 'fixed' : 'free',
amountDataToken: 1000,
amountOcean: 100,
weightOnOcean: '5', // 50% on OCEAN
weightOnDataToken: '5', // 50% on datatoken

View File

@ -210,7 +210,7 @@ export async function createTokensAndPricing(
// TODO: cap is hardcoded for now to 1000, this needs to be discussed at some point
const ercParams: Erc20CreateParams = {
templateIndex: values.pricing.type === 'dynamic' ? 1 : 2,
templateIndex: 2,
minter: accountId,
paymentCollector: accountId,
mpFeeAddress: marketFeeAddress,
@ -228,63 +228,6 @@ export async function createTokensAndPricing(
// TODO: cleaner code for this huge switch !??!?
switch (values.pricing.type) {
case 'dynamic': {
// no vesting in market by default, maybe at a later time , vestingAmount and vestedBlocks are hardcoded
// we use only ocean as basetoken
// swapFeeLiquidityProvider is the swap fee of the liquidity providers
// swapFeeMarketRunner is the swap fee of the market where the swap occurs
const poolParams: PoolCreationParams = {
ssContract: config.sideStakingAddress,
baseTokenAddress: config.oceanTokenAddress,
baseTokenSender: config.erc721FactoryAddress,
publisherAddress: accountId,
marketFeeCollector: marketFeeAddress,
poolTemplateAddress: config.poolTemplateAddress,
rate: new Decimal(1).div(values.pricing.price).toString(),
baseTokenDecimals: 18,
vestingAmount: '0',
vestedBlocks: 2726000,
initialBaseTokenLiquidity: values.pricing.amountOcean.toString(),
swapFeeLiquidityProvider: (values.pricing.swapFee / 100).toString(),
swapFeeMarketRunner: publisherMarketPoolSwapFee
}
LoggerInstance.log(
'[publish] Creating dynamic pricing with poolParams',
poolParams
)
// the spender in this case is the erc721Factory because we are delegating
const txApprove = await approve(
web3,
accountId,
config.oceanTokenAddress,
config.erc721FactoryAddress,
values.pricing.amountOcean.toString(),
false
)
LoggerInstance.log('[publish] pool.approve tx', txApprove, nftFactory)
if (!txApprove) {
throw new Error(
'MetaMask Approve TX Signature: User denied transaction signature'
)
}
const result = await nftFactory.createNftErc20WithPool(
accountId,
nftCreateData,
ercParams,
poolParams
)
erc721Address = result.events.NFTCreated.returnValues[0]
datatokenAddress = result.events.TokenCreated.returnValues[0]
txHash = result.transactionHash
LoggerInstance.log('[publish] createNftErcWithPool tx', txHash)
break
}
case 'fixed': {
const freParams: FreCreationParams = {
fixedRateAddress: config.fixedRateExchangeAddress,