mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
merge main
This commit is contained in:
commit
2632e7ed0f
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
@ -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 }}
|
||||
|
||||
|
@ -50,6 +50,8 @@ cd market
|
||||
nvm use
|
||||
|
||||
npm install
|
||||
# in case of dependency errors, rather use:
|
||||
# npm install --legacy-peer-deps
|
||||
npm start
|
||||
```
|
||||
|
||||
|
@ -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
44
package-lock.json
generated
@ -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"
|
||||
}
|
||||
},
|
||||
|
@ -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",
|
||||
|
@ -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" \
|
||||
|
1
src/@types/aquarius/BaseQueryParams.d.ts
vendored
1
src/@types/aquarius/BaseQueryParams.d.ts
vendored
@ -9,6 +9,7 @@ interface BaseQueryParams {
|
||||
nestedQuery?: any
|
||||
esPaginationOptions?: EsPaginationOptions
|
||||
sortOptions?: SortOptions
|
||||
aggs?: any
|
||||
filters?: FilterTerm[]
|
||||
ignorePurgatory?: boolean
|
||||
}
|
||||
|
1
src/@types/aquarius/PagedAssets.d.ts
vendored
1
src/@types/aquarius/PagedAssets.d.ts
vendored
@ -3,4 +3,5 @@ interface PagedAssets {
|
||||
page: number
|
||||
totalPages: number
|
||||
totalResults: number
|
||||
aggregations: any
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
})
|
||||
|
||||
|
24
src/components/@shared/AccountList/index.module.css
Normal file
24
src/components/@shared/AccountList/index.module.css
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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}>
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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"
|
||||
/>
|
||||
|
@ -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'] {
|
||||
|
@ -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);
|
||||
}
|
@ -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>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
@ -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;
|
||||
}
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
@ -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;
|
||||
}
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 (
|
||||
<>
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
@ -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} />
|
||||
</>
|
||||
)
|
||||
}
|
@ -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.
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
@ -3,9 +3,6 @@ export interface StatsValue {
|
||||
}
|
||||
|
||||
export interface StatsTotal {
|
||||
totalValueLockedInOcean: number
|
||||
totalOceanLiquidity: number
|
||||
pools: number
|
||||
nfts: number
|
||||
datatokens: number
|
||||
orders: number
|
||||
|
@ -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} />
|
||||
}
|
||||
/>
|
||||
</>
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -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
|
||||
/>
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user