mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Remove AMM Pools (#1614)
This commit is contained in:
parent
8edd61bfa7
commit
eb29c4ce3b
@ -1,10 +1,8 @@
|
|||||||
#NEXT_PUBLIC_INFURA_PROJECT_ID="xxx"
|
#NEXT_PUBLIC_INFURA_PROJECT_ID="xxx"
|
||||||
#NEXT_PUBLIC_MARKET_FEE_ADDRESS="0xxx"
|
#NEXT_PUBLIC_MARKET_FEE_ADDRESS="0xxx"
|
||||||
#NEXT_PUBLIC_PUBLISHER_MARKET_ORDER_FEE="1"
|
#NEXT_PUBLIC_PUBLISHER_MARKET_ORDER_FEE="1"
|
||||||
#NEXT_PUBLIC_PUBLISHER_MARKET_POOL_SWAP_FEE="1"
|
|
||||||
#NEXT_PUBLIC_PUBLISHER_MARKET_FIXED_SWAP_FEE="1"
|
#NEXT_PUBLIC_PUBLISHER_MARKET_FIXED_SWAP_FEE="1"
|
||||||
#NEXT_PUBLIC_CONSUME_MARKET_ORDER_FEE="1"
|
#NEXT_PUBLIC_CONSUME_MARKET_ORDER_FEE="1"
|
||||||
#NEXT_PUBLIC_CONSUME_MARKET_POOL_SWAP_FEE="1"
|
|
||||||
#NEXT_PUBLIC_CONSUME_MARKET_FIXED_SWAP_FEE="1"
|
#NEXT_PUBLIC_CONSUME_MARKET_FIXED_SWAP_FEE="1"
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -109,7 +109,7 @@ All displayed data in the app is presented around the concept of one data set, w
|
|||||||
- the actual data set files
|
- the actual data set files
|
||||||
- the NFT which represents the data set
|
- the NFT which represents the data set
|
||||||
- the datatokens representing access rights to the data set files
|
- the datatokens representing access rights to the data set files
|
||||||
- financial data connected to these datatokens
|
- financial data connected to these datatokens, either a fixed rate exchange contract or a dispenser for free assets
|
||||||
- calculations and conversions based on financial data
|
- calculations and conversions based on financial data
|
||||||
- metadata about publisher accounts
|
- metadata about publisher accounts
|
||||||
|
|
||||||
|
@ -33,9 +33,6 @@ module.exports = {
|
|||||||
// publisher market fee that is taken upon ordering an asset, it is an absolute value, it is declared on erc20 creation
|
// publisher market fee that is taken upon ordering an asset, it is an absolute value, it is declared on erc20 creation
|
||||||
publisherMarketOrderFee:
|
publisherMarketOrderFee:
|
||||||
process.env.NEXT_PUBLIC_PUBLISHER_MARKET_ORDER_FEE || '0',
|
process.env.NEXT_PUBLIC_PUBLISHER_MARKET_ORDER_FEE || '0',
|
||||||
// fee recieved by the publisher market when a dt is swaped from a pool, percent
|
|
||||||
publisherMarketPoolSwapFee:
|
|
||||||
process.env.NEXT_PUBLIC_PUBLISHER_MARKET_POOL_SWAP_FEE || '0',
|
|
||||||
// fee recieved by the publisher market when a dt is bought from a fixed rate exchange, percent
|
// fee recieved by the publisher market when a dt is bought from a fixed rate exchange, percent
|
||||||
publisherMarketFixedSwapFee:
|
publisherMarketFixedSwapFee:
|
||||||
process.env.NEXT_PUBLIC_PUBLISHER_MARKET_FIXED_SWAP_FEE || '0',
|
process.env.NEXT_PUBLIC_PUBLISHER_MARKET_FIXED_SWAP_FEE || '0',
|
||||||
@ -43,9 +40,6 @@ module.exports = {
|
|||||||
// consume market fee that is taken upon ordering an asset, it is an absolute value, it is specified on order
|
// consume market fee that is taken upon ordering an asset, it is an absolute value, it is specified on order
|
||||||
consumeMarketOrderFee:
|
consumeMarketOrderFee:
|
||||||
process.env.NEXT_PUBLIC_CONSUME_MARKET_ORDER_FEE || '0',
|
process.env.NEXT_PUBLIC_CONSUME_MARKET_ORDER_FEE || '0',
|
||||||
// fee recieved by the consume market when a dt is swaped from a pool, percent
|
|
||||||
consumeMarketPoolSwapFee:
|
|
||||||
process.env.NEXT_PUBLIC_CONSUME_MARKET_POOL_SWAP_FEE || '0',
|
|
||||||
// fee recieved by the consume market when a dt is bought from a fixed rate exchange, percent
|
// fee recieved by the consume market when a dt is bought from a fixed rate exchange, percent
|
||||||
consumeMarketFixedSwapFee:
|
consumeMarketFixedSwapFee:
|
||||||
process.env.NEXT_PUBLIC_CONSUME_MARKET_FIXED_SWAP_FEE || '0',
|
process.env.NEXT_PUBLIC_CONSUME_MARKET_FIXED_SWAP_FEE || '0',
|
||||||
@ -75,10 +69,9 @@ module.exports = {
|
|||||||
storageKey: 'oceanDarkMode'
|
storageKey: 'oceanDarkMode'
|
||||||
},
|
},
|
||||||
|
|
||||||
// Used to show or hide the fixed, dynamic or free price options
|
// Used to show or hide the fixed or free price options
|
||||||
// tab to publishers during the price creation.
|
// tab to publishers during the price creation.
|
||||||
allowFixedPricing: process.env.NEXT_PUBLIC_ALLOW_FIXED_PRICING || 'true',
|
allowFixedPricing: process.env.NEXT_PUBLIC_ALLOW_FIXED_PRICING || 'true',
|
||||||
allowDynamicPricing: process.env.NEXT_PUBLIC_ALLOW_DYNAMIC_PRICING || 'true',
|
|
||||||
allowFreePricing: process.env.NEXT_PUBLIC_ALLOW_FREE_PRICING || 'true',
|
allowFreePricing: process.env.NEXT_PUBLIC_ALLOW_FREE_PRICING || 'true',
|
||||||
|
|
||||||
// Set the default privacy policy to initially display
|
// Set the default privacy policy to initially display
|
||||||
|
@ -14,6 +14,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stats": {
|
"stats": {
|
||||||
"note": "Counted on-chain from our NFT and pool factories. Includes assets in all Ocean Market forks and [purgatory](https://github.com/oceanprotocol/list-purgatory)."
|
"note": "Counted on-chain from our NFT factories. Includes assets in all Ocean Market forks and [purgatory](https://github.com/oceanprotocol/list-purgatory)."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
{
|
{
|
||||||
"create": {
|
"create": {
|
||||||
"empty": {
|
|
||||||
"title": "No Price Created",
|
|
||||||
"info": "This data set has no price yet. As the publisher you can create a fixed price, or a dynamic price for it. Onwards!",
|
|
||||||
"action": {
|
|
||||||
"name": "Create Pricing",
|
|
||||||
"help": "Create Pricing will mint your datatokens, approve spending, and create either a pool or a fixed rate exchange in one process. You will need to approve those multiple steps in your wallet."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fixed": {
|
"fixed": {
|
||||||
"title": "Fixed",
|
"title": "Fixed",
|
||||||
"info": "Set your price for accessing this data set. The datatoken for this data set will be worth the entered amount of OCEAN.",
|
"info": "Set your price for accessing this data set. The datatoken for this data set will be worth the entered amount of OCEAN.",
|
||||||
@ -30,24 +22,10 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pool": {
|
"approval": {
|
||||||
"tooltips": {
|
"tooltips": {
|
||||||
"price": "The price is determined by an automated market maker, which is a type of decentralized exchange protocol that relies on a mathematical formula. It is an alternative to a traditional order book.",
|
|
||||||
"liquidity": "Providing liquidity will earn you SWAPFEE% on every transaction in this pool, proportionally to your share of the pool.",
|
|
||||||
"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.",
|
"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."
|
"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."
|
||||||
},
|
|
||||||
"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.",
|
|
||||||
"output": {
|
|
||||||
"titleOutExpected": "Expected output",
|
|
||||||
"titleOutMinimum": "Minimum received"
|
|
||||||
},
|
|
||||||
"action": "Remove"
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"trade": {
|
|
||||||
"action": "Swap"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@
|
|||||||
"label": "Algorithm Privacy",
|
"label": "Algorithm Privacy",
|
||||||
"type": "checkbox",
|
"type": "checkbox",
|
||||||
"options": ["Keep my algorithm private"],
|
"options": ["Keep my algorithm private"],
|
||||||
"help": "By default, your algorithm can be downloaded for a fixed or dynamic price in addition to running in compute jobs. Enabling this option will prevent downloading, so your algorithm can only be run as part of a compute job on a data set.",
|
"help": "By default, your algorithm can be downloaded for free or a fixed price, in addition to running in compute jobs. Enabling this option will prevent downloading, so your algorithm can only be run as part of a compute job on a data set.",
|
||||||
"required": false
|
"required": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"link": "/profile"
|
"link": "/profile"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"announcement": "Data NFTs, One-Sided Staking and more.",
|
"announcement": "Explore [OceanONDA V4](https://blog.oceanprotocol.com/how-to-publish-a-data-nft-f58ad2a622a9).",
|
||||||
"warning": {
|
"warning": {
|
||||||
"ctd": "Compute-to-Data is still in a testing phase, please use it only on test networks."
|
"ctd": "Compute-to-Data is still in a testing phase, please use it only on test networks."
|
||||||
}
|
}
|
||||||
|
46
package-lock.json
generated
46
package-lock.json
generated
@ -19,7 +19,6 @@
|
|||||||
"@urql/exchange-refocus": "^0.2.5",
|
"@urql/exchange-refocus": "^0.2.5",
|
||||||
"@walletconnect/web3-provider": "^1.7.8",
|
"@walletconnect/web3-provider": "^1.7.8",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"chart.js": "^3.8.0",
|
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"date-fns": "^2.29.1",
|
"date-fns": "^2.29.1",
|
||||||
"decimal.js": "^10.3.1",
|
"decimal.js": "^10.3.1",
|
||||||
@ -37,7 +36,6 @@
|
|||||||
"next": "^12.1.6",
|
"next": "^12.1.6",
|
||||||
"query-string": "^7.1.1",
|
"query-string": "^7.1.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-chartjs-2": "^4.2.0",
|
|
||||||
"react-clipboard.js": "^2.0.16",
|
"react-clipboard.js": "^2.0.16",
|
||||||
"react-data-table-component": "^7.5.2",
|
"react-data-table-component": "^7.5.2",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
@ -70,7 +68,6 @@
|
|||||||
"@svgr/webpack": "^6.2.1",
|
"@svgr/webpack": "^6.2.1",
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"@testing-library/react": "^13.3.0",
|
"@testing-library/react": "^13.3.0",
|
||||||
"@types/chart.js": "^2.9.37",
|
|
||||||
"@types/js-cookie": "^3.0.2",
|
"@types/js-cookie": "^3.0.2",
|
||||||
"@types/loadable__component": "^5.13.4",
|
"@types/loadable__component": "^5.13.4",
|
||||||
"@types/lodash.debounce": "^4.0.7",
|
"@types/lodash.debounce": "^4.0.7",
|
||||||
@ -17910,15 +17907,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/chart.js": {
|
|
||||||
"version": "2.9.37",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.37.tgz",
|
|
||||||
"integrity": "sha512-9bosRfHhkXxKYfrw94EmyDQcdjMaQPkU1fH2tDxu8DWXxf1mjzWQAV4laJF51ZbC2ycYwNDvIm1rGez8Bug0vg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"moment": "^2.10.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/clipboard": {
|
"node_modules/@types/clipboard": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.7.tgz",
|
||||||
@ -22298,11 +22286,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chart.js": {
|
|
||||||
"version": "3.8.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.8.0.tgz",
|
|
||||||
"integrity": "sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg=="
|
|
||||||
},
|
|
||||||
"node_modules/checkpoint-store": {
|
"node_modules/checkpoint-store": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/checkpoint-store/-/checkpoint-store-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/checkpoint-store/-/checkpoint-store-1.1.0.tgz",
|
||||||
@ -39429,15 +39412,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-chartjs-2": {
|
|
||||||
"version": "4.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.2.0.tgz",
|
|
||||||
"integrity": "sha512-9Vm9Sg9XAKiR579/FnBkesofjW9goaaFLfS7XlGTzUJlWFZGSE6A/pBI6+i/bP3pobKZoFcWJdFnjShytToqXw==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"chart.js": "^3.5.0",
|
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-clipboard.js": {
|
"node_modules/react-clipboard.js": {
|
||||||
"version": "2.0.16",
|
"version": "2.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/react-clipboard.js/-/react-clipboard.js-2.0.16.tgz",
|
"resolved": "https://registry.npmjs.org/react-clipboard.js/-/react-clipboard.js-2.0.16.tgz",
|
||||||
@ -60513,15 +60487,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/chart.js": {
|
|
||||||
"version": "2.9.37",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.37.tgz",
|
|
||||||
"integrity": "sha512-9bosRfHhkXxKYfrw94EmyDQcdjMaQPkU1fH2tDxu8DWXxf1mjzWQAV4laJF51ZbC2ycYwNDvIm1rGez8Bug0vg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"moment": "^2.10.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/clipboard": {
|
"@types/clipboard": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.7.tgz",
|
||||||
@ -64101,11 +64066,6 @@
|
|||||||
"integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==",
|
"integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"chart.js": {
|
|
||||||
"version": "3.8.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.8.0.tgz",
|
|
||||||
"integrity": "sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg=="
|
|
||||||
},
|
|
||||||
"checkpoint-store": {
|
"checkpoint-store": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/checkpoint-store/-/checkpoint-store-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/checkpoint-store/-/checkpoint-store-1.1.0.tgz",
|
||||||
@ -77612,12 +77572,6 @@
|
|||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-chartjs-2": {
|
|
||||||
"version": "4.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.2.0.tgz",
|
|
||||||
"integrity": "sha512-9Vm9Sg9XAKiR579/FnBkesofjW9goaaFLfS7XlGTzUJlWFZGSE6A/pBI6+i/bP3pobKZoFcWJdFnjShytToqXw==",
|
|
||||||
"requires": {}
|
|
||||||
},
|
|
||||||
"react-clipboard.js": {
|
"react-clipboard.js": {
|
||||||
"version": "2.0.16",
|
"version": "2.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/react-clipboard.js/-/react-clipboard.js-2.0.16.tgz",
|
"resolved": "https://registry.npmjs.org/react-clipboard.js/-/react-clipboard.js-2.0.16.tgz",
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
"@urql/exchange-refocus": "^0.2.5",
|
"@urql/exchange-refocus": "^0.2.5",
|
||||||
"@walletconnect/web3-provider": "^1.7.8",
|
"@walletconnect/web3-provider": "^1.7.8",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"chart.js": "^3.8.0",
|
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"date-fns": "^2.29.1",
|
"date-fns": "^2.29.1",
|
||||||
"decimal.js": "^10.3.1",
|
"decimal.js": "^10.3.1",
|
||||||
@ -50,7 +49,6 @@
|
|||||||
"next": "^12.1.6",
|
"next": "^12.1.6",
|
||||||
"query-string": "^7.1.1",
|
"query-string": "^7.1.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-chartjs-2": "^4.2.0",
|
|
||||||
"react-clipboard.js": "^2.0.16",
|
"react-clipboard.js": "^2.0.16",
|
||||||
"react-data-table-component": "^7.5.2",
|
"react-data-table-component": "^7.5.2",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
@ -83,7 +81,6 @@
|
|||||||
"@svgr/webpack": "^6.2.1",
|
"@svgr/webpack": "^6.2.1",
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"@testing-library/react": "^13.3.0",
|
"@testing-library/react": "^13.3.0",
|
||||||
"@types/chart.js": "^2.9.37",
|
|
||||||
"@types/js-cookie": "^3.0.2",
|
"@types/js-cookie": "^3.0.2",
|
||||||
"@types/loadable__component": "^5.13.4",
|
"@types/loadable__component": "^5.13.4",
|
||||||
"@types/lodash.debounce": "^4.0.7",
|
"@types/lodash.debounce": "^4.0.7",
|
||||||
|
@ -13,7 +13,6 @@ import { checkV3Asset, retrieveAsset } from '@utils/aquarius'
|
|||||||
import { useWeb3 } from './Web3'
|
import { useWeb3 } from './Web3'
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean'
|
import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { getAccessDetails } from '@utils/accessDetailsAndPricing'
|
import { getAccessDetails } from '@utils/accessDetailsAndPricing'
|
||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
import { useMarketMetadata } from './MarketMetadata'
|
import { useMarketMetadata } from './MarketMetadata'
|
||||||
@ -126,6 +125,7 @@ function AssetProvider({
|
|||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
const fetchAccessDetails = useCallback(async (): Promise<void> => {
|
const fetchAccessDetails = useCallback(async (): Promise<void> => {
|
||||||
if (!asset?.chainId || !asset?.services) return
|
if (!asset?.chainId || !asset?.services) return
|
||||||
|
|
||||||
const accessDetails = await getAccessDetails(
|
const accessDetails = await getAccessDetails(
|
||||||
asset.chainId,
|
asset.chainId,
|
||||||
asset.services[0].datatokenAddress,
|
asset.services[0].datatokenAddress,
|
||||||
|
@ -12,14 +12,11 @@ export interface AppConfig {
|
|||||||
chainIdsSupported: number[]
|
chainIdsSupported: number[]
|
||||||
marketFeeAddress: string
|
marketFeeAddress: string
|
||||||
publisherMarketOrderFee: string
|
publisherMarketOrderFee: string
|
||||||
publisherMarketPoolSwapFee: string
|
|
||||||
publisherMarketFixedSwapFee: string
|
publisherMarketFixedSwapFee: string
|
||||||
consumeMarketOrderFee: string
|
consumeMarketOrderFee: string
|
||||||
consumeMarketPoolSwapFee: string
|
|
||||||
consumeMarketFixedSwapFee: string
|
consumeMarketFixedSwapFee: string
|
||||||
currencies: string[]
|
currencies: string[]
|
||||||
allowFixedPricing: string
|
allowFixedPricing: string
|
||||||
allowDynamicPricing: string
|
|
||||||
allowFreePricing: string
|
allowFreePricing: string
|
||||||
defaultPrivacyPolicySlug: string
|
defaultPrivacyPolicySlug: string
|
||||||
privacyPreferenceCenter: string
|
privacyPreferenceCenter: string
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
import { gql } from 'urql'
|
|
||||||
|
|
||||||
export const poolDataQuery = gql`
|
|
||||||
query PoolData(
|
|
||||||
$pool: ID!
|
|
||||||
$poolAsString: String!
|
|
||||||
$owner: String!
|
|
||||||
$user: String
|
|
||||||
) {
|
|
||||||
poolData: pool(id: $pool) {
|
|
||||||
id
|
|
||||||
totalShares
|
|
||||||
liquidityProviderSwapFee
|
|
||||||
publishMarketSwapFee
|
|
||||||
spotPrice
|
|
||||||
baseToken {
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
baseTokenWeight
|
|
||||||
baseTokenLiquidity
|
|
||||||
datatoken {
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
datatokenWeight
|
|
||||||
datatokenLiquidity
|
|
||||||
shares(where: { user: $owner }) {
|
|
||||||
shares
|
|
||||||
}
|
|
||||||
}
|
|
||||||
poolDataUser: pool(id: $pool) {
|
|
||||||
shares(where: { user: $user }) {
|
|
||||||
shares
|
|
||||||
}
|
|
||||||
}
|
|
||||||
poolSnapshots(first: 1000, where: { pool: $poolAsString }, orderBy: date) {
|
|
||||||
date
|
|
||||||
spotPrice
|
|
||||||
baseTokenLiquidity
|
|
||||||
datatokenLiquidity
|
|
||||||
swapVolume
|
|
||||||
baseToken {
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
datatoken {
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
@ -1,35 +0,0 @@
|
|||||||
import {
|
|
||||||
PoolData_poolSnapshots as PoolDataPoolSnapshots,
|
|
||||||
PoolData_poolData as PoolDataPoolData
|
|
||||||
} from 'src/@types/subgraph/PoolData'
|
|
||||||
|
|
||||||
export interface PoolInfo {
|
|
||||||
liquidityProviderSwapFee: string
|
|
||||||
publishMarketSwapFee: string
|
|
||||||
weightBaseToken: string
|
|
||||||
weightDt: string
|
|
||||||
datatokenSymbol: string
|
|
||||||
datatokenAddress: string
|
|
||||||
datatokenDecimals: number
|
|
||||||
baseTokenSymbol: string
|
|
||||||
baseTokenAddress: string
|
|
||||||
baseTokenDecimals: number
|
|
||||||
totalPoolTokens: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PoolInfoUser {
|
|
||||||
liquidity: string
|
|
||||||
poolShares: string
|
|
||||||
poolSharePercentage: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PoolProviderValue {
|
|
||||||
poolData: PoolDataPoolData
|
|
||||||
poolInfo: PoolInfo
|
|
||||||
poolInfoOwner: PoolInfoUser
|
|
||||||
poolInfoUser: PoolInfoUser
|
|
||||||
poolSnapshots: PoolDataPoolSnapshots[]
|
|
||||||
hasUserAddedLiquidity: boolean
|
|
||||||
refreshInterval: number
|
|
||||||
fetchAllData: () => void
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
import { isValidNumber } from '@utils/numbers'
|
|
||||||
import { getQueryContext, fetchData } from '@utils/subgraph'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { PoolData } from 'src/@types/subgraph/PoolData'
|
|
||||||
import { OperationResult } from 'urql'
|
|
||||||
import { poolDataQuery } from './_queries'
|
|
||||||
|
|
||||||
export async function getPoolData(
|
|
||||||
chainId: number,
|
|
||||||
pool: string,
|
|
||||||
owner: string,
|
|
||||||
user: string
|
|
||||||
) {
|
|
||||||
const queryVariables = {
|
|
||||||
// Using `pool` & `poolAsString` is a workaround to make the mega query work.
|
|
||||||
// See https://github.com/oceanprotocol/ocean-subgraph/issues/301
|
|
||||||
pool: pool.toLowerCase(),
|
|
||||||
poolAsString: pool.toLowerCase(),
|
|
||||||
owner: owner.toLowerCase(),
|
|
||||||
user: user.toLowerCase()
|
|
||||||
}
|
|
||||||
|
|
||||||
const response: OperationResult<PoolData> = await fetchData(
|
|
||||||
poolDataQuery,
|
|
||||||
queryVariables,
|
|
||||||
getQueryContext(chainId)
|
|
||||||
)
|
|
||||||
return response?.data
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getWeight(weight: string) {
|
|
||||||
return isValidNumber(weight) ? new Decimal(weight).mul(10).toString() : '0'
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getFee(fee: string) {
|
|
||||||
// fees are tricky: to get 0.1% you need to convert from 0.001
|
|
||||||
return isValidNumber(fee) ? new Decimal(fee).mul(100).toString() : '0'
|
|
||||||
}
|
|
@ -1,196 +0,0 @@
|
|||||||
import { LoggerInstance } from '@oceanprotocol/lib'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import React, {
|
|
||||||
useContext,
|
|
||||||
useState,
|
|
||||||
useEffect,
|
|
||||||
createContext,
|
|
||||||
ReactElement,
|
|
||||||
useCallback,
|
|
||||||
ReactNode
|
|
||||||
} from 'react'
|
|
||||||
import {
|
|
||||||
PoolData_poolSnapshots as PoolDataPoolSnapshots,
|
|
||||||
PoolData_poolData as PoolDataPoolData
|
|
||||||
} from 'src/@types/subgraph/PoolData'
|
|
||||||
import { useAsset } from '../Asset'
|
|
||||||
import { useWeb3 } from '../Web3'
|
|
||||||
import { calcSingleOutGivenPoolIn } from '@utils/pool'
|
|
||||||
import { PoolProviderValue, PoolInfo, PoolInfoUser } from './_types'
|
|
||||||
import { getFee, getPoolData, getWeight } from './_utils'
|
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
|
||||||
|
|
||||||
const PoolContext = createContext({} as PoolProviderValue)
|
|
||||||
|
|
||||||
const refreshInterval = 10000 // 10 sec.
|
|
||||||
|
|
||||||
const initialPoolInfoUser: Partial<PoolInfoUser> = {
|
|
||||||
liquidity: '0',
|
|
||||||
poolShares: '0'
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialPoolInfoCreator: Partial<PoolInfoUser> = initialPoolInfoUser
|
|
||||||
|
|
||||||
function PoolProvider({ children }: { children: ReactNode }): ReactElement {
|
|
||||||
const { accountId, web3, chainId } = useWeb3()
|
|
||||||
const { asset, owner } = useAsset()
|
|
||||||
const { getOpcFeeForToken } = useMarketMetadata()
|
|
||||||
const [poolData, setPoolData] = useState<PoolDataPoolData>()
|
|
||||||
const [poolInfo, setPoolInfo] = useState<PoolInfo>()
|
|
||||||
const [poolInfoOwner, setPoolInfoOwner] = useState<PoolInfoUser>(
|
|
||||||
initialPoolInfoCreator as PoolInfoUser
|
|
||||||
)
|
|
||||||
const [poolInfoUser, setPoolInfoUser] = useState<PoolInfoUser>(
|
|
||||||
initialPoolInfoUser as PoolInfoUser
|
|
||||||
)
|
|
||||||
const [poolSnapshots, setPoolSnapshots] = useState<PoolDataPoolSnapshots[]>()
|
|
||||||
const [hasUserAddedLiquidity, setUserHasAddedLiquidity] = useState(false)
|
|
||||||
|
|
||||||
const fetchAllData = useCallback(async () => {
|
|
||||||
if (!asset?.chainId || !asset?.accessDetails?.addressOrId || !owner) return
|
|
||||||
|
|
||||||
const response = await getPoolData(
|
|
||||||
asset.chainId,
|
|
||||||
asset.accessDetails.addressOrId,
|
|
||||||
owner,
|
|
||||||
accountId || ''
|
|
||||||
)
|
|
||||||
if (!response) return
|
|
||||||
|
|
||||||
setPoolData(response.poolData)
|
|
||||||
|
|
||||||
// calculate pool info user
|
|
||||||
const poolInfoShares = response.poolDataUser?.shares[0]?.shares || '0'
|
|
||||||
const userLiquidity = calcSingleOutGivenPoolIn(
|
|
||||||
response.poolData.baseTokenLiquidity,
|
|
||||||
response.poolData.totalShares,
|
|
||||||
poolInfoShares
|
|
||||||
)
|
|
||||||
|
|
||||||
// Pool share in %. We double it to compensate for ss bot
|
|
||||||
const poolSharePercentage = new Decimal(poolInfoShares)
|
|
||||||
.dividedBy(new Decimal(response.poolData.totalShares))
|
|
||||||
.mul(200)
|
|
||||||
.toFixed(2)
|
|
||||||
|
|
||||||
setUserHasAddedLiquidity(Number(poolSharePercentage) > 0)
|
|
||||||
|
|
||||||
const newPoolInfoUser: PoolInfoUser = {
|
|
||||||
liquidity: userLiquidity,
|
|
||||||
poolShares: poolInfoShares,
|
|
||||||
poolSharePercentage
|
|
||||||
}
|
|
||||||
setPoolInfoUser((prevState: PoolInfoUser) => ({
|
|
||||||
...prevState,
|
|
||||||
...newPoolInfoUser
|
|
||||||
}))
|
|
||||||
|
|
||||||
setPoolSnapshots(response.poolSnapshots)
|
|
||||||
LoggerInstance.log('[pool] Fetched pool data:', response.poolData)
|
|
||||||
LoggerInstance.log('[pool] Fetched user data:', response.poolDataUser)
|
|
||||||
LoggerInstance.log('[pool] Fetched pool snapshots:', response.poolSnapshots)
|
|
||||||
}, [asset?.chainId, asset?.accessDetails?.addressOrId, owner, accountId])
|
|
||||||
|
|
||||||
// 0 Fetch all the data on mount if we are on a pool.
|
|
||||||
// All further effects depend on the fetched data
|
|
||||||
// and only do further data checking and manipulation.
|
|
||||||
//
|
|
||||||
useEffect(() => {
|
|
||||||
if (asset?.accessDetails?.type !== 'dynamic') return
|
|
||||||
fetchAllData()
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
fetchAllData()
|
|
||||||
}, refreshInterval)
|
|
||||||
return () => clearInterval(interval)
|
|
||||||
}, [fetchAllData, asset?.accessDetails?.type])
|
|
||||||
|
|
||||||
//
|
|
||||||
// 1 General Pool Info
|
|
||||||
//
|
|
||||||
useEffect(() => {
|
|
||||||
if (!poolData) return
|
|
||||||
|
|
||||||
const newPoolInfo = {
|
|
||||||
liquidityProviderSwapFee: getFee(poolData.liquidityProviderSwapFee),
|
|
||||||
publishMarketSwapFee: getFee(poolData.publishMarketSwapFee),
|
|
||||||
opcFee: getFee(
|
|
||||||
getOpcFeeForToken(poolData.baseToken.address, asset?.chainId)
|
|
||||||
),
|
|
||||||
weightBaseToken: getWeight(poolData.baseTokenWeight),
|
|
||||||
weightDt: getWeight(poolData.datatokenWeight),
|
|
||||||
datatokenSymbol: poolData.datatoken.symbol,
|
|
||||||
datatokenAddress: poolData.datatoken.address,
|
|
||||||
datatokenDecimals: poolData.datatoken.decimals,
|
|
||||||
baseTokenSymbol: poolData.baseToken.symbol,
|
|
||||||
baseTokenAddress: poolData.baseToken.address,
|
|
||||||
baseTokenDecimals: poolData.baseToken.decimals,
|
|
||||||
totalPoolTokens: poolData.totalShares
|
|
||||||
}
|
|
||||||
|
|
||||||
setPoolInfo(newPoolInfo)
|
|
||||||
LoggerInstance.log('[pool] Created new pool info:', newPoolInfo)
|
|
||||||
}, [asset?.chainId, chainId, getOpcFeeForToken, poolData, web3])
|
|
||||||
|
|
||||||
//
|
|
||||||
// 2 Pool Creator Info
|
|
||||||
//
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
!poolData ||
|
|
||||||
!poolInfo?.totalPoolTokens ||
|
|
||||||
!poolData.shares[0]?.shares ||
|
|
||||||
poolData.shares[0]?.shares === '0'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
// Pool share tokens. We double it to compensate for ss bot
|
|
||||||
const poolSharePercentage = new Decimal(poolData.shares[0]?.shares)
|
|
||||||
.dividedBy(poolInfo.totalPoolTokens)
|
|
||||||
.mul(200)
|
|
||||||
.toFixed(2)
|
|
||||||
|
|
||||||
const ownerLiquidity = calcSingleOutGivenPoolIn(
|
|
||||||
poolData.baseTokenLiquidity,
|
|
||||||
poolData.totalShares,
|
|
||||||
poolData?.shares[0]?.shares
|
|
||||||
)
|
|
||||||
|
|
||||||
const newPoolOwnerInfo = {
|
|
||||||
liquidity: ownerLiquidity,
|
|
||||||
poolShares: poolData.shares[0]?.shares,
|
|
||||||
poolSharePercentage
|
|
||||||
}
|
|
||||||
setPoolInfoOwner(newPoolOwnerInfo)
|
|
||||||
LoggerInstance.log('[pool] Created new pool creatorinfo:', newPoolOwnerInfo)
|
|
||||||
}, [
|
|
||||||
asset?.chainId,
|
|
||||||
poolData,
|
|
||||||
poolInfo?.baseTokenAddress,
|
|
||||||
poolInfo?.totalPoolTokens
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PoolContext.Provider
|
|
||||||
value={
|
|
||||||
{
|
|
||||||
poolData,
|
|
||||||
poolInfo,
|
|
||||||
poolInfoOwner,
|
|
||||||
poolInfoUser,
|
|
||||||
poolSnapshots,
|
|
||||||
hasUserAddedLiquidity,
|
|
||||||
refreshInterval,
|
|
||||||
fetchAllData
|
|
||||||
} as PoolProviderValue
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</PoolContext.Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper hook to access the provider values
|
|
||||||
const usePool = (): PoolProviderValue => useContext(PoolContext)
|
|
||||||
|
|
||||||
export { PoolProvider, usePool, PoolContext }
|
|
||||||
export default PoolProvider
|
|
@ -7,13 +7,8 @@ import React, {
|
|||||||
useCallback,
|
useCallback,
|
||||||
ReactNode
|
ReactNode
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import {
|
import { getUserSales, getUserTokenOrders } from '@utils/subgraph'
|
||||||
getPoolSharesData,
|
|
||||||
getUserSales,
|
|
||||||
getUserTokenOrders
|
|
||||||
} from '@utils/subgraph'
|
|
||||||
import { useUserPreferences } from './UserPreferences'
|
import { useUserPreferences } from './UserPreferences'
|
||||||
import { PoolShares_poolShares as PoolShare } from '../@types/subgraph/PoolShares'
|
|
||||||
import { Asset, LoggerInstance } from '@oceanprotocol/lib'
|
import { Asset, LoggerInstance } from '@oceanprotocol/lib'
|
||||||
import { getDownloadAssets, getPublishedAssets } from '@utils/aquarius'
|
import { getDownloadAssets, getPublishedAssets } from '@utils/aquarius'
|
||||||
import { accountTruncate } from '@utils/web3'
|
import { accountTruncate } from '@utils/web3'
|
||||||
@ -24,8 +19,6 @@ import { useMarketMetadata } from './MarketMetadata'
|
|||||||
|
|
||||||
interface ProfileProviderValue {
|
interface ProfileProviderValue {
|
||||||
profile: Profile
|
profile: Profile
|
||||||
poolShares: PoolShare[]
|
|
||||||
isPoolSharesLoading: boolean
|
|
||||||
assets: Asset[]
|
assets: Asset[]
|
||||||
assetsTotal: number
|
assetsTotal: number
|
||||||
isEthAddress: boolean
|
isEthAddress: boolean
|
||||||
@ -121,55 +114,6 @@ function ProfileProvider({
|
|||||||
}
|
}
|
||||||
}, [accountId, accountEns, isEthAddress])
|
}, [accountId, accountEns, isEthAddress])
|
||||||
|
|
||||||
//
|
|
||||||
// POOL SHARES
|
|
||||||
//
|
|
||||||
const [poolShares, setPoolShares] = useState<PoolShare[]>()
|
|
||||||
const [isPoolSharesLoading, setIsPoolSharesLoading] = useState<boolean>(false)
|
|
||||||
const [poolSharesInterval, setPoolSharesInterval] = useState<NodeJS.Timeout>()
|
|
||||||
|
|
||||||
const fetchPoolShares = useCallback(
|
|
||||||
async (accountId: string, chainIds: number[], isEthAddress: boolean) => {
|
|
||||||
if (!accountId || !chainIds || !isEthAddress) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
setIsPoolSharesLoading(true)
|
|
||||||
const poolShares = await getPoolSharesData(accountId, chainIds)
|
|
||||||
setPoolShares(poolShares)
|
|
||||||
LoggerInstance.log(
|
|
||||||
`[profile] Fetched ${poolShares.length} pool shares.`,
|
|
||||||
poolShares
|
|
||||||
)
|
|
||||||
} catch (error) {
|
|
||||||
LoggerInstance.error('Error fetching pool shares: ', error.message)
|
|
||||||
} finally {
|
|
||||||
setIsPoolSharesLoading(false)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function init() {
|
|
||||||
await fetchPoolShares(accountId, chainIds, isEthAddress)
|
|
||||||
|
|
||||||
if (poolSharesInterval) return
|
|
||||||
|
|
||||||
const interval = setInterval(async () => {
|
|
||||||
LoggerInstance.log(
|
|
||||||
`[profile] Re-fetching pool shares after ${refreshInterval / 1000}s.`
|
|
||||||
)
|
|
||||||
await fetchPoolShares(accountId, chainIds, isEthAddress)
|
|
||||||
}, refreshInterval)
|
|
||||||
setPoolSharesInterval(interval)
|
|
||||||
}
|
|
||||||
init()
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearInterval(poolSharesInterval)
|
|
||||||
}
|
|
||||||
}, [poolSharesInterval, fetchPoolShares, accountId, chainIds, isEthAddress])
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// PUBLISHED ASSETS
|
// PUBLISHED ASSETS
|
||||||
//
|
//
|
||||||
@ -300,8 +244,6 @@ function ProfileProvider({
|
|||||||
<ProfileContext.Provider
|
<ProfileContext.Provider
|
||||||
value={{
|
value={{
|
||||||
profile,
|
profile,
|
||||||
poolShares,
|
|
||||||
isPoolSharesLoading,
|
|
||||||
assets,
|
assets,
|
||||||
assetsTotal,
|
assetsTotal,
|
||||||
isEthAddress,
|
isEthAddress,
|
||||||
|
8
src/@types/AssetExtended.d.ts
vendored
8
src/@types/AssetExtended.d.ts
vendored
@ -1,5 +1,9 @@
|
|||||||
import { Asset } from '@oceanprotocol/lib'
|
import { Asset } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
interface AssetExtended extends Asset {
|
// declaring into global scope to be able to use this as
|
||||||
accessDetails?: AccessDetails
|
// ambiant types despite the above imports
|
||||||
|
declare global {
|
||||||
|
interface AssetExtended extends Asset {
|
||||||
|
accessDetails?: AccessDetails
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
110
src/@types/Price.d.ts
vendored
110
src/@types/Price.d.ts
vendored
@ -1,64 +1,56 @@
|
|||||||
import { ProviderFees } from '@oceanprotocol/lib'
|
import { ProviderFees } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
/**
|
// declaring into global scope to be able to use this as
|
||||||
* @interface OrderPriceAndFee
|
// ambiant types despite the above imports
|
||||||
* @prop {string} price total price including fees
|
declare global {
|
||||||
* @prop {string} publisherMarketOrderFee fee received by the market where the asset was published. It is set on erc20 creation. It is a absolute value
|
/**
|
||||||
* @prop {string} publisherMarketPoolSwapFee fee received by the market where the asset was published on any swap (pool or fre). Absolute value based on the configured percentage
|
* @interface OrderPriceAndFee
|
||||||
* @prop {string} publisherMarketFixedSwapFee fee received by the market where the asset was published on any swap (pool or fre). Absolute value based on the configured percentage
|
* @prop {string} price total price including fees
|
||||||
* @prop {string} consumeMarketOrderFee fee received by the market where the asset is ordered. It is set on erc20 creation. It is a absolute value
|
* @prop {string} publisherMarketOrderFee fee received by the market where the asset was published. It is set on erc20 creation. It is a absolute value
|
||||||
* @prop {string} consumeMarketPoolSwapFee fee received by the market where the asset is ordered on any swap (pool or fre). Absolute value based on the configured percentage
|
* @prop {string} publisherMarketFixedSwapFee fee received by the market where the asset was published on any swap (fre). Absolute value based on the configured percentage
|
||||||
* @prop {string} consumeMarketFixedSwapFee fee received by the market where the asset is ordered on any swap (pool or fre). Absolute value based on the configured percentage
|
* @prop {string} consumeMarketOrderFee fee received by the market where the asset is ordered. It is set on erc20 creation. It is a absolute value
|
||||||
* @prop {string} liquidityProviderSwapFee fee received by the liquidity providers of the pool. It is a percentage ( ex 50% means liquidityProviderSwapFee=0.5)
|
* @prop {string} consumeMarketFixedSwapFee fee received by the market where the asset is ordered on any swap (fre). Absolute value based on the configured percentage
|
||||||
* @prop {ProviderFees} providerFee received from provider
|
* @prop {ProviderFees} providerFee received from provider
|
||||||
* @prop {string} opcFee ocean protocol community fee, Absolute value based on the configured percentage
|
* @prop {string} opcFee ocean protocol community fee, Absolute value based on the configured percentage
|
||||||
*/
|
*/
|
||||||
interface OrderPriceAndFees {
|
interface OrderPriceAndFees {
|
||||||
price: string
|
price: string
|
||||||
publisherMarketOrderFee: string
|
publisherMarketOrderFee: string
|
||||||
publisherMarketPoolSwapFee: string
|
publisherMarketFixedSwapFee: string
|
||||||
publisherMarketFixedSwapFee: string
|
consumeMarketOrderFee: string
|
||||||
consumeMarketOrderFee: string
|
consumeMarketFixedSwapFee: string
|
||||||
consumeMarketPoolSwapFee: string
|
providerFee: ProviderFees
|
||||||
consumeMarketFixedSwapFee: string
|
opcFee: string
|
||||||
liquidityProviderSwapFee: string
|
}
|
||||||
providerFee: ProviderFees
|
|
||||||
opcFee: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @interface AccessDetails
|
* @interface AccessDetails
|
||||||
* @prop {'dynamic' | 'fixed' | 'free' | ''} type
|
* @prop {'fixed' | 'free' | 'NOT_SUPPORTED'} type
|
||||||
* @prop {string} price can be either spotPrice/rate
|
* @prop {string} price can be either spotPrice/rate
|
||||||
* @prop {string} addressOrId if type is dynamic this is the pool address, for fixed/free this is an id.
|
* @prop {string} addressOrId for fixed/free this is an id.
|
||||||
* @prop {TokenInfo} baseToken
|
* @prop {TokenInfo} baseToken
|
||||||
* @prop {TokenInfo} datatoken
|
* @prop {TokenInfo} datatoken
|
||||||
* @prop {bool} isPurchasable checks if you can buy a datatoken from fixed rate exchange/pool/dispenser. For pool it also checks if there is enough dt liquidity
|
* @prop {bool} isPurchasable checks if you can buy a datatoken from fixed rate exchange/dispenser.
|
||||||
* @prop {bool} isOwned checks if there are valid orders for this, it also takes in consideration timeout
|
* @prop {bool} isOwned checks if there are valid orders for this, it also takes in consideration timeout
|
||||||
* @prop {string} validOrderTx the latest valid order tx, it also takes in consideration timeout
|
* @prop {string} validOrderTx the latest valid order tx, it also takes in consideration timeout
|
||||||
* @prop {string} publisherMarketOrderFee this is here just because it's more efficient, it's allready in the query
|
* @prop {string} publisherMarketOrderFee this is here just because it's more efficient, it's allready in the query
|
||||||
* @prop {FeeInfo} feeInfo values of the relevant fees
|
* @prop {FeeInfo} feeInfo values of the relevant fees
|
||||||
*/
|
*/
|
||||||
interface AccessDetails {
|
interface AccessDetails {
|
||||||
type: 'dynamic' | 'fixed' | 'free' | ''
|
type: 'fixed' | 'free' | 'NOT_SUPPORTED'
|
||||||
price: string
|
price: string
|
||||||
addressOrId: string
|
addressOrId: string
|
||||||
baseToken: TokenInfo
|
baseToken: TokenInfo
|
||||||
datatoken: TokenInfo
|
datatoken: TokenInfo
|
||||||
isPurchasable?: boolean
|
isPurchasable?: boolean
|
||||||
isOwned: bool
|
isOwned: bool
|
||||||
validOrderTx: string
|
validOrderTx: string
|
||||||
publisherMarketOrderFee: string
|
publisherMarketOrderFee: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PriceOptions {
|
interface PricePublishOptions {
|
||||||
price: number
|
price: number
|
||||||
amountDataToken: number
|
type: 'fixed' | 'free'
|
||||||
amountOcean: number
|
freeAgreement: boolean
|
||||||
type: 'dynamic' | 'fixed' | 'free' | ''
|
}
|
||||||
weightOnDataToken: string
|
|
||||||
weightOnOcean: string
|
|
||||||
// easier to keep this as number for Yup input validation
|
|
||||||
swapFee: number
|
|
||||||
freeAgreement: boolean
|
|
||||||
}
|
}
|
||||||
|
5
src/@types/TokenBalance.d.ts
vendored
5
src/@types/TokenBalance.d.ts
vendored
@ -1,8 +1,3 @@
|
|||||||
interface PoolBalance {
|
|
||||||
baseToken: string
|
|
||||||
datatoken: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UserBalance {
|
interface UserBalance {
|
||||||
eth: string
|
eth: string
|
||||||
ocean: string
|
ocean: string
|
||||||
|
9
src/@types/Utils.d.ts
vendored
9
src/@types/Utils.d.ts
vendored
@ -1,9 +0,0 @@
|
|||||||
interface CalcInGivenOutParams {
|
|
||||||
tokenInLiquidity: string
|
|
||||||
tokenOutLiquidity: string
|
|
||||||
tokenOutAmount: string
|
|
||||||
opcFee: string
|
|
||||||
lpSwapFee: string
|
|
||||||
publishMarketSwapFee: string
|
|
||||||
consumeMarketSwapFee: string
|
|
||||||
}
|
|
@ -14,13 +14,12 @@ import {
|
|||||||
ProviderFees,
|
ProviderFees,
|
||||||
ProviderInstance
|
ProviderInstance
|
||||||
} from '@oceanprotocol/lib'
|
} from '@oceanprotocol/lib'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { calcInGivenOut } from './pool'
|
|
||||||
import { getFixedBuyPrice } from './fixedRateExchange'
|
import { getFixedBuyPrice } from './fixedRateExchange'
|
||||||
import { AccessDetails, OrderPriceAndFees } from 'src/@types/Price'
|
|
||||||
import Decimal from 'decimal.js'
|
import Decimal from 'decimal.js'
|
||||||
import { consumeMarketOrderFee } from '../../app.config'
|
import {
|
||||||
import Web3 from 'web3'
|
consumeMarketOrderFee,
|
||||||
|
publisherMarketOrderFee
|
||||||
|
} from '../../app.config'
|
||||||
|
|
||||||
const tokensPriceQuery = gql`
|
const tokensPriceQuery = gql`
|
||||||
query TokensPriceQuery($datatokenIds: [ID!], $account: String) {
|
query TokensPriceQuery($datatokenIds: [ID!], $account: String) {
|
||||||
@ -75,22 +74,6 @@ const tokensPriceQuery = gql`
|
|||||||
}
|
}
|
||||||
active
|
active
|
||||||
}
|
}
|
||||||
pools {
|
|
||||||
id
|
|
||||||
spotPrice
|
|
||||||
isFinalized
|
|
||||||
datatokenLiquidity
|
|
||||||
baseToken {
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
address
|
|
||||||
}
|
|
||||||
datatoken {
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@ -147,22 +130,6 @@ const tokenPriceQuery = gql`
|
|||||||
}
|
}
|
||||||
active
|
active
|
||||||
}
|
}
|
||||||
pools {
|
|
||||||
id
|
|
||||||
spotPrice
|
|
||||||
isFinalized
|
|
||||||
datatokenLiquidity
|
|
||||||
baseToken {
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
address
|
|
||||||
}
|
|
||||||
datatoken {
|
|
||||||
symbol
|
|
||||||
name
|
|
||||||
address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@ -173,6 +140,15 @@ function getAccessDetailsFromTokenPrice(
|
|||||||
): AccessDetails {
|
): AccessDetails {
|
||||||
const accessDetails = {} as AccessDetails
|
const accessDetails = {} as AccessDetails
|
||||||
|
|
||||||
|
// Return early when no supported pricing schema found.
|
||||||
|
if (
|
||||||
|
tokenPrice?.dispensers?.length === 0 &&
|
||||||
|
tokenPrice?.fixedRateExchanges?.length === 0
|
||||||
|
) {
|
||||||
|
accessDetails.type = 'NOT_SUPPORTED'
|
||||||
|
return accessDetails
|
||||||
|
}
|
||||||
|
|
||||||
if (tokenPrice?.orders?.length > 0) {
|
if (tokenPrice?.orders?.length > 0) {
|
||||||
const order = tokenPrice.orders[0]
|
const order = tokenPrice.orders[0]
|
||||||
const reusedOrder = order?.reuses?.length > 0 ? order.reuses[0] : null
|
const reusedOrder = order?.reuses?.length > 0 ? order.reuses[0] : null
|
||||||
@ -198,7 +174,6 @@ function getAccessDetailsFromTokenPrice(
|
|||||||
name: dispenser.token.name,
|
name: dispenser.token.name,
|
||||||
symbol: dispenser.token.symbol
|
symbol: dispenser.token.symbol
|
||||||
}
|
}
|
||||||
return accessDetails
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// checking for fixed price
|
// checking for fixed price
|
||||||
@ -219,30 +194,8 @@ function getAccessDetailsFromTokenPrice(
|
|||||||
name: fixed.datatoken.name,
|
name: fixed.datatoken.name,
|
||||||
symbol: fixed.datatoken.symbol
|
symbol: fixed.datatoken.symbol
|
||||||
}
|
}
|
||||||
return accessDetails
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// checking for pools
|
|
||||||
if (tokenPrice?.pools?.length > 0) {
|
|
||||||
const pool = tokenPrice.pools[0]
|
|
||||||
accessDetails.type = 'dynamic'
|
|
||||||
accessDetails.addressOrId = pool.id
|
|
||||||
accessDetails.price = pool.spotPrice
|
|
||||||
// TODO: pool.datatokenLiquidity > 3 is kinda random here, we shouldn't run into this anymore now , needs more thinking/testing
|
|
||||||
accessDetails.isPurchasable =
|
|
||||||
pool.isFinalized && pool.datatokenLiquidity > 3
|
|
||||||
accessDetails.baseToken = {
|
|
||||||
address: pool.baseToken.address,
|
|
||||||
name: pool.baseToken.name,
|
|
||||||
symbol: pool.baseToken.symbol
|
|
||||||
}
|
|
||||||
accessDetails.datatoken = {
|
|
||||||
address: pool.datatoken.address,
|
|
||||||
name: pool.datatoken.name,
|
|
||||||
symbol: pool.datatoken.symbol
|
|
||||||
}
|
|
||||||
return accessDetails
|
|
||||||
}
|
|
||||||
return accessDetails
|
return accessDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,17 +207,13 @@ function getAccessDetailsFromTokenPrice(
|
|||||||
export async function getOrderPriceAndFees(
|
export async function getOrderPriceAndFees(
|
||||||
asset: AssetExtended,
|
asset: AssetExtended,
|
||||||
accountId?: string,
|
accountId?: string,
|
||||||
paramsForPool?: CalcInGivenOutParams,
|
|
||||||
providerFees?: ProviderFees
|
providerFees?: ProviderFees
|
||||||
): Promise<OrderPriceAndFees> {
|
): Promise<OrderPriceAndFees> {
|
||||||
const orderPriceAndFee = {
|
const orderPriceAndFee = {
|
||||||
price: '0',
|
price: '0',
|
||||||
publisherMarketOrderFee:
|
publisherMarketOrderFee: publisherMarketOrderFee || '0',
|
||||||
asset?.accessDetails?.publisherMarketOrderFee || '0',
|
|
||||||
publisherMarketPoolSwapFee: '0',
|
|
||||||
publisherMarketFixedSwapFee: '0',
|
publisherMarketFixedSwapFee: '0',
|
||||||
consumeMarketOrderFee: consumeMarketOrderFee || '0',
|
consumeMarketOrderFee: consumeMarketOrderFee || '0',
|
||||||
consumeMarketPoolSwapFee: '0',
|
|
||||||
consumeMarketFixedSwapFee: '0',
|
consumeMarketFixedSwapFee: '0',
|
||||||
providerFee: {
|
providerFee: {
|
||||||
providerFeeAmount: '0'
|
providerFeeAmount: '0'
|
||||||
@ -273,7 +222,6 @@ export async function getOrderPriceAndFees(
|
|||||||
} as OrderPriceAndFees
|
} as OrderPriceAndFees
|
||||||
|
|
||||||
// fetch provider fee
|
// fetch provider fee
|
||||||
|
|
||||||
const initializeData =
|
const initializeData =
|
||||||
!providerFees &&
|
!providerFees &&
|
||||||
(await ProviderInstance.initialize(
|
(await ProviderInstance.initialize(
|
||||||
@ -286,27 +234,12 @@ export async function getOrderPriceAndFees(
|
|||||||
orderPriceAndFee.providerFee = providerFees || initializeData.providerFee
|
orderPriceAndFee.providerFee = providerFees || initializeData.providerFee
|
||||||
|
|
||||||
// fetch price and swap fees
|
// fetch price and swap fees
|
||||||
switch (asset?.accessDetails?.type) {
|
if (asset?.accessDetails?.type === 'fixed') {
|
||||||
case 'dynamic': {
|
const fixed = await getFixedBuyPrice(asset?.accessDetails, asset?.chainId)
|
||||||
const poolPrice = calcInGivenOut(paramsForPool)
|
orderPriceAndFee.price = fixed.baseTokenAmount
|
||||||
orderPriceAndFee.price = poolPrice.tokenAmount
|
orderPriceAndFee.opcFee = fixed.oceanFeeAmount
|
||||||
orderPriceAndFee.liquidityProviderSwapFee =
|
orderPriceAndFee.publisherMarketFixedSwapFee = fixed.marketFeeAmount
|
||||||
poolPrice.liquidityProviderSwapFeeAmount
|
orderPriceAndFee.consumeMarketFixedSwapFee = fixed.consumeMarketFeeAmount
|
||||||
orderPriceAndFee.publisherMarketPoolSwapFee =
|
|
||||||
poolPrice.publishMarketSwapFeeAmount
|
|
||||||
orderPriceAndFee.consumeMarketPoolSwapFee =
|
|
||||||
poolPrice.consumeMarketSwapFeeAmount
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'fixed': {
|
|
||||||
const fixed = await getFixedBuyPrice(asset?.accessDetails, asset?.chainId)
|
|
||||||
orderPriceAndFee.price = fixed.baseTokenAmount
|
|
||||||
orderPriceAndFee.opcFee = fixed.oceanFeeAmount
|
|
||||||
orderPriceAndFee.publisherMarketFixedSwapFee = fixed.marketFeeAmount
|
|
||||||
orderPriceAndFee.consumeMarketFixedSwapFee = fixed.consumeMarketFeeAmount
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate full price, we assume that all the values are in ocean, otherwise this will be incorrect
|
// calculate full price, we assume that all the values are in ocean, otherwise this will be incorrect
|
||||||
@ -314,6 +247,7 @@ export async function getOrderPriceAndFees(
|
|||||||
.add(new Decimal(+orderPriceAndFee?.consumeMarketOrderFee || 0))
|
.add(new Decimal(+orderPriceAndFee?.consumeMarketOrderFee || 0))
|
||||||
.add(new Decimal(+orderPriceAndFee?.publisherMarketOrderFee || 0))
|
.add(new Decimal(+orderPriceAndFee?.publisherMarketOrderFee || 0))
|
||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
return orderPriceAndFee
|
return orderPriceAndFee
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { getAccessDetailsForAssets } from './accessDetailsAndPricing'
|
import { getAccessDetailsForAssets } from './accessDetailsAndPricing'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { PublisherTrustedAlgorithm, Asset } from '@oceanprotocol/lib'
|
import { PublisherTrustedAlgorithm, Asset } from '@oceanprotocol/lib'
|
||||||
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
||||||
import { getServiceByName } from './ddo'
|
import { getServiceByName } from './ddo'
|
||||||
|
@ -24,7 +24,6 @@ import { getServiceById, getServiceByName } from './ddo'
|
|||||||
import { SortTermOptions } from 'src/@types/aquarius/SearchQuery'
|
import { SortTermOptions } from 'src/@types/aquarius/SearchQuery'
|
||||||
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
||||||
import { transformAssetToAssetSelection } from './assetConvertor'
|
import { transformAssetToAssetSelection } from './assetConvertor'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { ComputeEditForm } from 'src/components/Asset/Edit/_types'
|
import { ComputeEditForm } from 'src/components/Asset/Edit/_types'
|
||||||
import { getFileDidInfo } from './provider'
|
import { getFileDidInfo } from './provider'
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ export function getOrderFeedback(
|
|||||||
datatokenSymbol: string
|
datatokenSymbol: string
|
||||||
): { [key in number]: string } {
|
): { [key in number]: string } {
|
||||||
return {
|
return {
|
||||||
0: `Approving and buying one ${datatokenSymbol} from pool`,
|
0: `Approving and buying one ${datatokenSymbol}`,
|
||||||
1: `Ordering asset`,
|
1: `Ordering asset`,
|
||||||
2: `Approving ${baseTokenSymbol} and ordering asset`,
|
2: `Approving ${baseTokenSymbol} and ordering asset`,
|
||||||
3: 'Generating signature to access download url'
|
3: 'Generating signature to access download url'
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { FixedRateExchange, PriceAndFees } from '@oceanprotocol/lib'
|
import { FixedRateExchange, PriceAndFees } from '@oceanprotocol/lib'
|
||||||
import { AccessDetails } from 'src/@types/Price'
|
import { consumeMarketFixedSwapFee } from '../../app.config'
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import { getOceanConfig } from './ocean'
|
import { getOceanConfig } from './ocean'
|
||||||
import { consumeMarketPoolSwapFee } from '../../app.config'
|
|
||||||
import { getDummyWeb3 } from './web3'
|
import { getDummyWeb3 } from './web3'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +29,7 @@ export async function getFixedBuyPrice(
|
|||||||
const estimatedPrice = await fixed.calcBaseInGivenOutDT(
|
const estimatedPrice = await fixed.calcBaseInGivenOutDT(
|
||||||
accessDetails.addressOrId,
|
accessDetails.addressOrId,
|
||||||
'1',
|
'1',
|
||||||
consumeMarketPoolSwapFee
|
consumeMarketFixedSwapFee
|
||||||
)
|
)
|
||||||
return estimatedPrice
|
return estimatedPrice
|
||||||
}
|
}
|
||||||
|
@ -10,21 +10,17 @@ import {
|
|||||||
ProviderFees,
|
ProviderFees,
|
||||||
ProviderInstance
|
ProviderInstance
|
||||||
} from '@oceanprotocol/lib'
|
} from '@oceanprotocol/lib'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import { getOceanConfig } from './ocean'
|
import { getOceanConfig } from './ocean'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
import { TransactionReceipt } from 'web3-eth'
|
||||||
import { OrderPriceAndFees } from 'src/@types/Price'
|
|
||||||
import {
|
import {
|
||||||
marketFeeAddress,
|
marketFeeAddress,
|
||||||
consumeMarketOrderFee,
|
consumeMarketOrderFee,
|
||||||
consumeMarketFixedSwapFee
|
consumeMarketFixedSwapFee
|
||||||
} from '../../app.config'
|
} from '../../app.config'
|
||||||
import { buyDtFromPool } from './pool'
|
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For pool you need to buy the datatoken beforehand, this always assumes you want to order the first service
|
|
||||||
* @param web3
|
* @param web3
|
||||||
* @param asset
|
* @param asset
|
||||||
* @param orderPriceAndFees
|
* @param orderPriceAndFees
|
||||||
@ -102,17 +98,6 @@ export async function order(
|
|||||||
|
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
case 'dynamic': {
|
|
||||||
const tx = await datatoken.startOrder(
|
|
||||||
asset.accessDetails.datatoken.address,
|
|
||||||
accountId,
|
|
||||||
computeConsumerAddress || accountId,
|
|
||||||
0,
|
|
||||||
providerFees || initializeData.providerFee
|
|
||||||
)
|
|
||||||
return tx
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'free': {
|
case 'free': {
|
||||||
const tx = await datatoken.buyFromDispenserAndOrder(
|
const tx = await datatoken.buyFromDispenserAndOrder(
|
||||||
asset.services[0].datatokenAddress,
|
asset.services[0].datatokenAddress,
|
||||||
@ -191,14 +176,6 @@ async function startOrder(
|
|||||||
initializeData: ProviderComputeInitialize,
|
initializeData: ProviderComputeInitialize,
|
||||||
computeConsumerAddress?: string
|
computeConsumerAddress?: string
|
||||||
): Promise<TransactionReceipt> {
|
): Promise<TransactionReceipt> {
|
||||||
if (!hasDatatoken && asset?.accessDetails.type === 'dynamic') {
|
|
||||||
const poolTx = await buyDtFromPool(asset?.accessDetails, accountId, web3)
|
|
||||||
LoggerInstance.log('[compute] Bought datatoken from pool: ', poolTx)
|
|
||||||
if (!poolTx) {
|
|
||||||
toast.error('Failed to buy datatoken from pool!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const tx = await order(
|
const tx = await order(
|
||||||
web3,
|
web3,
|
||||||
asset,
|
asset,
|
||||||
|
@ -1,185 +0,0 @@
|
|||||||
import { approve, Pool, PoolPriceAndFees } from '@oceanprotocol/lib'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
import { getDummyWeb3 } from './web3'
|
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { AccessDetails } from 'src/@types/Price'
|
|
||||||
import { consumeMarketPoolSwapFee, marketFeeAddress } from '../../app.config'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is used to calculate the price to buy one datatoken from a pool, that is different from spot price. You need to pass either a web3 object or a chainId. If you pass a chainId a dummy web3 object will be created
|
|
||||||
* @param {AccessDetails} accessDetails
|
|
||||||
* @param {Web3?} [web3]
|
|
||||||
* @param {number?} [chainId]
|
|
||||||
* @return {Promise<PoolPriceAndFees>}
|
|
||||||
*/
|
|
||||||
export async function calculateBuyPrice(
|
|
||||||
accessDetails: AccessDetails,
|
|
||||||
chainId?: number,
|
|
||||||
web3?: Web3
|
|
||||||
): Promise<PoolPriceAndFees> {
|
|
||||||
if (!web3 && !chainId)
|
|
||||||
throw new Error("web3 and chainId can't be undefined at the same time!")
|
|
||||||
|
|
||||||
if (!web3) {
|
|
||||||
web3 = await getDummyWeb3(chainId)
|
|
||||||
}
|
|
||||||
|
|
||||||
const pool = new Pool(web3)
|
|
||||||
|
|
||||||
const estimatedPrice = await pool.getAmountInExactOut(
|
|
||||||
accessDetails.addressOrId,
|
|
||||||
accessDetails.baseToken.address,
|
|
||||||
accessDetails.datatoken.address,
|
|
||||||
'1',
|
|
||||||
consumeMarketPoolSwapFee,
|
|
||||||
accessDetails.baseToken.decimals,
|
|
||||||
accessDetails.datatoken.decimals
|
|
||||||
)
|
|
||||||
|
|
||||||
return estimatedPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function buyDtFromPool(
|
|
||||||
accessDetails: AccessDetails,
|
|
||||||
accountId: string,
|
|
||||||
web3: Web3
|
|
||||||
): Promise<TransactionReceipt> {
|
|
||||||
const pool = new Pool(web3)
|
|
||||||
// we need to calculate the actual price to buy one datatoken
|
|
||||||
const dtPrice = await calculateBuyPrice(accessDetails, null, web3)
|
|
||||||
const approveTx = await approve(
|
|
||||||
web3,
|
|
||||||
accountId,
|
|
||||||
accessDetails.baseToken.address,
|
|
||||||
accessDetails.addressOrId,
|
|
||||||
dtPrice.tokenAmount,
|
|
||||||
false,
|
|
||||||
accessDetails.baseToken.decimals
|
|
||||||
)
|
|
||||||
if (!approveTx) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const result = await pool.swapExactAmountOut(
|
|
||||||
accountId,
|
|
||||||
accessDetails.addressOrId,
|
|
||||||
{
|
|
||||||
marketFeeAddress,
|
|
||||||
tokenIn: accessDetails.baseToken.address,
|
|
||||||
tokenOut: accessDetails.datatoken.address,
|
|
||||||
tokenInDecimals: accessDetails.baseToken.decimals,
|
|
||||||
tokenOutDecimals: accessDetails.datatoken.decimals
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this is just to be safe
|
|
||||||
maxAmountIn: new Decimal(dtPrice.tokenAmount).mul(10).toString(),
|
|
||||||
swapMarketFee: consumeMarketPoolSwapFee,
|
|
||||||
tokenAmountOut: '1'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is used to calculate the actual price of buying a datatoken, it's a copy of the math in the contracts.
|
|
||||||
* @param params
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function calcInGivenOut(params: CalcInGivenOutParams): PoolPriceAndFees {
|
|
||||||
const result = {
|
|
||||||
tokenAmount: '0',
|
|
||||||
liquidityProviderSwapFeeAmount: '0',
|
|
||||||
oceanFeeAmount: '0',
|
|
||||||
publishMarketSwapFeeAmount: '0',
|
|
||||||
consumeMarketSwapFeeAmount: '0'
|
|
||||||
} as PoolPriceAndFees
|
|
||||||
const one = new Decimal(1)
|
|
||||||
const tokenOutLiqudity = new Decimal(params.tokenOutLiquidity)
|
|
||||||
const tokenInLiquidity = new Decimal(params.tokenInLiquidity)
|
|
||||||
const tokenOutAmount = new Decimal(params.tokenOutAmount)
|
|
||||||
const opcFee = new Decimal(params.opcFee)
|
|
||||||
const lpFee = new Decimal(params.lpSwapFee)
|
|
||||||
const publishMarketSwapFee = new Decimal(params.publishMarketSwapFee)
|
|
||||||
const consumeMarketSwapFee = new Decimal(params.consumeMarketSwapFee)
|
|
||||||
|
|
||||||
const diff = tokenOutLiqudity.minus(tokenOutAmount)
|
|
||||||
const y = tokenOutLiqudity.div(diff)
|
|
||||||
let foo = y.pow(one)
|
|
||||||
foo = foo.minus(one)
|
|
||||||
const totalFee = lpFee
|
|
||||||
.plus(opcFee)
|
|
||||||
.plus(publishMarketSwapFee)
|
|
||||||
.plus(consumeMarketSwapFee)
|
|
||||||
|
|
||||||
const tokenAmountIn = tokenInLiquidity.mul(foo).div(one.sub(totalFee))
|
|
||||||
result.tokenAmount = tokenAmountIn.toString()
|
|
||||||
result.oceanFeeAmount = tokenAmountIn
|
|
||||||
.sub(tokenAmountIn.mul(one.sub(opcFee)))
|
|
||||||
.toString()
|
|
||||||
result.publishMarketSwapFeeAmount = tokenAmountIn
|
|
||||||
.sub(tokenAmountIn.mul(one.sub(publishMarketSwapFee)))
|
|
||||||
.toString()
|
|
||||||
result.consumeMarketSwapFeeAmount = tokenAmountIn
|
|
||||||
.sub(tokenAmountIn.mul(one.sub(consumeMarketSwapFee)))
|
|
||||||
.toString()
|
|
||||||
result.liquidityProviderSwapFeeAmount = tokenAmountIn
|
|
||||||
.sub(tokenAmountIn.mul(one.sub(lpFee)))
|
|
||||||
.toString()
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to calculate swap values, it's a copy of the math in the contracts.
|
|
||||||
* @param tokenLiquidity
|
|
||||||
* @param poolSupply
|
|
||||||
* @param poolShareAmount
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function calcSingleOutGivenPoolIn(
|
|
||||||
tokenLiquidity: string,
|
|
||||||
poolSupply: string,
|
|
||||||
poolShareAmount: string
|
|
||||||
): string {
|
|
||||||
const tokenLiquidityD = new Decimal(tokenLiquidity)
|
|
||||||
const poolSupplyD = new Decimal(poolSupply)
|
|
||||||
const poolShareAmountD = new Decimal(poolShareAmount).mul(2)
|
|
||||||
const newPoolSupply = poolSupplyD.sub(poolShareAmountD)
|
|
||||||
const poolRatio = newPoolSupply.div(poolSupplyD)
|
|
||||||
|
|
||||||
const tokenOutRatio = new Decimal(1).sub(poolRatio)
|
|
||||||
const newTokenBalanceOut = tokenLiquidityD.mul(tokenOutRatio)
|
|
||||||
return newTokenBalanceOut.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the amount of tokens (based on tokenAddress) that can be withdrawn from the pool
|
|
||||||
* @param {string} poolAddress
|
|
||||||
* @param {string} tokenAddress
|
|
||||||
* @param {string} shares
|
|
||||||
* @param {number} chainId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export async function getLiquidityByShares(
|
|
||||||
pool: string,
|
|
||||||
tokenAddress: string,
|
|
||||||
tokenDecimals: number,
|
|
||||||
shares: string,
|
|
||||||
chainId: number
|
|
||||||
): Promise<string> {
|
|
||||||
// we only use the dummyWeb3 connection here
|
|
||||||
const web3 = await getDummyWeb3(chainId)
|
|
||||||
|
|
||||||
const poolInstance = new Pool(web3)
|
|
||||||
// get shares VL in ocean
|
|
||||||
const amountBaseToken = await poolInstance.calcSingleOutGivenPoolIn(
|
|
||||||
pool,
|
|
||||||
tokenAddress,
|
|
||||||
shares,
|
|
||||||
18,
|
|
||||||
tokenDecimals
|
|
||||||
)
|
|
||||||
|
|
||||||
return amountBaseToken
|
|
||||||
}
|
|
@ -8,7 +8,6 @@ import {
|
|||||||
ProviderComputeInitializeResults,
|
ProviderComputeInitializeResults,
|
||||||
ProviderInstance
|
ProviderInstance
|
||||||
} from '@oceanprotocol/lib'
|
} from '@oceanprotocol/lib'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import { getValidUntilTime } from './compute'
|
import { getValidUntilTime } from './compute'
|
||||||
|
|
||||||
|
@ -1,23 +1,11 @@
|
|||||||
import { gql, OperationResult, TypedDocumentNode, OperationContext } from 'urql'
|
import { gql, OperationResult, TypedDocumentNode, OperationContext } from 'urql'
|
||||||
import { Asset, LoggerInstance } from '@oceanprotocol/lib'
|
import { LoggerInstance } from '@oceanprotocol/lib'
|
||||||
import { getUrqlClientInstance } from '@context/UrqlProvider'
|
import { getUrqlClientInstance } from '@context/UrqlProvider'
|
||||||
import { getOceanConfig } from './ocean'
|
import { getOceanConfig } from './ocean'
|
||||||
import { AssetPoolPrice } from '../@types/subgraph/AssetPoolPrice'
|
|
||||||
import { AssetPreviousOrder } from '../@types/subgraph/AssetPreviousOrder'
|
import { AssetPreviousOrder } from '../@types/subgraph/AssetPreviousOrder'
|
||||||
import {
|
|
||||||
HighestLiquidityAssets_pools as HighestLiquidityAssetsPool,
|
|
||||||
HighestLiquidityAssets as HighestLiquidityGraphAssets
|
|
||||||
} from '../@types/subgraph/HighestLiquidityAssets'
|
|
||||||
import {
|
|
||||||
PoolShares as PoolSharesList,
|
|
||||||
PoolShares_poolShares as PoolShare
|
|
||||||
} from '../@types/subgraph/PoolShares'
|
|
||||||
import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData'
|
import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData'
|
||||||
import { UserSalesQuery as UsersSalesList } from '../@types/subgraph/UserSalesQuery'
|
|
||||||
import { OpcFeesQuery as OpcFeesData } from '../@types/subgraph/OpcFeesQuery'
|
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'
|
import { getPublishedAssets, getTopPublishers } from '@utils/aquarius'
|
||||||
export interface UserLiquidity {
|
export interface UserLiquidity {
|
||||||
price: string
|
price: string
|
||||||
@ -28,24 +16,6 @@ export interface PriceList {
|
|||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const AssetPoolPriceQuery = gql`
|
|
||||||
query AssetPoolPrice($datatokenAddress: String) {
|
|
||||||
pools(where: { datatoken: $datatokenAddress }) {
|
|
||||||
id
|
|
||||||
spotPrice
|
|
||||||
datatoken {
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
baseToken {
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
datatokenLiquidity
|
|
||||||
baseTokenLiquidity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const PreviousOrderQuery = gql`
|
const PreviousOrderQuery = gql`
|
||||||
query AssetPreviousOrder($id: String!, $account: String!) {
|
query AssetPreviousOrder($id: String!, $account: String!) {
|
||||||
orders(
|
orders(
|
||||||
@ -59,84 +29,6 @@ const PreviousOrderQuery = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const HighestLiquidityAssets = gql`
|
|
||||||
query HighestLiquidityAssets {
|
|
||||||
pools(
|
|
||||||
where: { datatokenLiquidity_gte: 1 }
|
|
||||||
orderBy: baseTokenLiquidity
|
|
||||||
orderDirection: desc
|
|
||||||
first: 15
|
|
||||||
) {
|
|
||||||
id
|
|
||||||
datatoken {
|
|
||||||
address
|
|
||||||
}
|
|
||||||
baseToken {
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
baseTokenLiquidity
|
|
||||||
datatokenLiquidity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const UserSharesQuery = gql`
|
|
||||||
query UserSharesQuery($user: String, $pools: [String!]) {
|
|
||||||
poolShares(where: { user: $user, pool_in: $pools }) {
|
|
||||||
id
|
|
||||||
shares
|
|
||||||
user {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
datatoken {
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
baseToken {
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
datatokenLiquidity
|
|
||||||
baseTokenLiquidity
|
|
||||||
totalShares
|
|
||||||
spotPrice
|
|
||||||
createdTimestamp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const userPoolSharesQuery = gql`
|
|
||||||
query PoolShares($user: String) {
|
|
||||||
poolShares(where: { user: $user, shares_gt: 0.001 }, first: 1000) {
|
|
||||||
id
|
|
||||||
shares
|
|
||||||
user {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pool {
|
|
||||||
id
|
|
||||||
datatoken {
|
|
||||||
id
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
baseToken {
|
|
||||||
id
|
|
||||||
address
|
|
||||||
symbol
|
|
||||||
}
|
|
||||||
baseTokenLiquidity
|
|
||||||
datatokenLiquidity
|
|
||||||
totalShares
|
|
||||||
spotPrice
|
|
||||||
createdTimestamp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const UserTokenOrders = gql`
|
const UserTokenOrders = gql`
|
||||||
query OrdersData($user: String!) {
|
query OrdersData($user: String!) {
|
||||||
@ -163,24 +55,6 @@ const UserTokenOrders = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const UserSalesQuery = gql`
|
|
||||||
query UserSalesQuery($user: ID!) {
|
|
||||||
users(where: { id: $user }) {
|
|
||||||
id
|
|
||||||
totalSales
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const TopSalesQuery = gql`
|
|
||||||
query TopSalesQuery {
|
|
||||||
users(first: 20, orderBy: totalSales, orderDirection: desc) {
|
|
||||||
id
|
|
||||||
totalSales
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const OpcFeesQuery = gql`
|
const OpcFeesQuery = gql`
|
||||||
query OpcFeesQuery($id: ID!) {
|
query OpcFeesQuery($id: ID!) {
|
||||||
opc(id: $id) {
|
opc(id: $id) {
|
||||||
@ -289,99 +163,6 @@ export async function getPreviousOrders(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSpotPrice(asset: Asset): Promise<number> {
|
|
||||||
const poolVariables = {
|
|
||||||
datatokenAddress: asset?.services[0].datatokenAddress.toLowerCase()
|
|
||||||
}
|
|
||||||
const queryContext = getQueryContext(Number(asset.chainId))
|
|
||||||
|
|
||||||
const poolPriceResponse: OperationResult<AssetPoolPrice> = await fetchData(
|
|
||||||
AssetPoolPriceQuery,
|
|
||||||
poolVariables,
|
|
||||||
queryContext
|
|
||||||
)
|
|
||||||
|
|
||||||
return poolPriceResponse.data.pools[0].spotPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getHighestLiquidityDatatokens(
|
|
||||||
chainIds: number[]
|
|
||||||
): Promise<string[]> {
|
|
||||||
const dtList: string[] = []
|
|
||||||
let highestLiquidityAssets: HighestLiquidityAssetsPool[] = []
|
|
||||||
|
|
||||||
for (const chain of chainIds) {
|
|
||||||
const queryContext = getQueryContext(Number(chain))
|
|
||||||
const fetchedPools: OperationResult<HighestLiquidityGraphAssets, any> =
|
|
||||||
await fetchData(HighestLiquidityAssets, null, queryContext)
|
|
||||||
highestLiquidityAssets = highestLiquidityAssets.concat(
|
|
||||||
fetchedPools?.data?.pools
|
|
||||||
)
|
|
||||||
}
|
|
||||||
highestLiquidityAssets.sort(
|
|
||||||
(a, b) => b.baseTokenLiquidity - a.baseTokenLiquidity
|
|
||||||
)
|
|
||||||
|
|
||||||
for (let i = 0; i < highestLiquidityAssets.length; i++) {
|
|
||||||
if (!highestLiquidityAssets[i]?.datatoken?.address) continue
|
|
||||||
dtList.push(highestLiquidityAssets[i].datatoken.address)
|
|
||||||
}
|
|
||||||
return dtList
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAccountLiquidityInOwnAssets(
|
|
||||||
accountId: string,
|
|
||||||
chainIds: number[],
|
|
||||||
pools: string[]
|
|
||||||
): Promise<string> {
|
|
||||||
const queryVariables = {
|
|
||||||
user: accountId.toLowerCase(),
|
|
||||||
pools
|
|
||||||
}
|
|
||||||
const results: PoolSharesList[] = await fetchDataForMultipleChains(
|
|
||||||
UserSharesQuery,
|
|
||||||
queryVariables,
|
|
||||||
chainIds
|
|
||||||
)
|
|
||||||
let totalLiquidity = new Decimal(0)
|
|
||||||
|
|
||||||
for (const result of results) {
|
|
||||||
for (const poolShare of result.poolShares) {
|
|
||||||
const poolUserLiquidity = calcSingleOutGivenPoolIn(
|
|
||||||
poolShare.pool.baseTokenLiquidity,
|
|
||||||
poolShare.pool.totalShares,
|
|
||||||
poolShare.shares
|
|
||||||
)
|
|
||||||
|
|
||||||
totalLiquidity = totalLiquidity.add(new Decimal(poolUserLiquidity))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return totalLiquidity.toDecimalPlaces(MAX_DECIMALS).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getPoolSharesData(
|
|
||||||
accountId: string,
|
|
||||||
chainIds: number[]
|
|
||||||
): Promise<PoolShare[]> {
|
|
||||||
const variables = { user: accountId?.toLowerCase() }
|
|
||||||
const data: PoolShare[] = []
|
|
||||||
try {
|
|
||||||
const result = await fetchDataForMultipleChains(
|
|
||||||
userPoolSharesQuery,
|
|
||||||
variables,
|
|
||||||
chainIds
|
|
||||||
)
|
|
||||||
for (let i = 0; i < result.length; i++) {
|
|
||||||
result[i].poolShares.forEach((poolShare: PoolShare) => {
|
|
||||||
data.push(poolShare)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
} catch (error) {
|
|
||||||
LoggerInstance.error('Error getPoolSharesData: ', error.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getUserTokenOrders(
|
export async function getUserTokenOrders(
|
||||||
accountId: string,
|
accountId: string,
|
||||||
chainIds: number[]
|
chainIds: number[]
|
||||||
|
@ -6,9 +6,6 @@ import classNames from 'classnames/bind'
|
|||||||
import Loader from '@shared/atoms/Loader'
|
import Loader from '@shared/atoms/Loader'
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
import { useUserPreferences } from '@context/UserPreferences'
|
||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
// not sure why this import is required
|
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { Asset } from '@oceanprotocol/lib'
|
|
||||||
import { getAccessDetailsForAssets } from '@utils/accessDetailsAndPricing'
|
import { getAccessDetailsForAssets } from '@utils/accessDetailsAndPricing'
|
||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
|
|
||||||
@ -23,7 +20,7 @@ function LoaderArea() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare type AssetListProps = {
|
declare type AssetListProps = {
|
||||||
assets: Asset[]
|
assets: AssetExtended[]
|
||||||
showPagination: boolean
|
showPagination: boolean
|
||||||
page?: number
|
page?: number
|
||||||
totalPages?: number
|
totalPages?: number
|
||||||
@ -51,6 +48,7 @@ export default function AssetList({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!assets) return
|
if (!assets) return
|
||||||
|
|
||||||
setAssetsWithPrices(assets as AssetExtended[])
|
setAssetsWithPrices(assets as AssetExtended[])
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
async function fetchPrices() {
|
async function fetchPrices() {
|
||||||
@ -58,7 +56,7 @@ export default function AssetList({
|
|||||||
assets,
|
assets,
|
||||||
accountId || ''
|
accountId || ''
|
||||||
)
|
)
|
||||||
if (!isMounted()) return
|
if (!isMounted() || !assetsWithPrices) return
|
||||||
setAssetsWithPrices([...assetsWithPrices])
|
setAssetsWithPrices([...assetsWithPrices])
|
||||||
}
|
}
|
||||||
fetchPrices()
|
fetchPrices()
|
||||||
|
@ -8,7 +8,6 @@ import AssetType from '@shared/AssetType'
|
|||||||
import NetworkName from '@shared/NetworkName'
|
import NetworkName from '@shared/NetworkName'
|
||||||
import styles from './AssetTeaser.module.css'
|
import styles from './AssetTeaser.module.css'
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
|
|
||||||
declare type AssetTeaserProps = {
|
declare type AssetTeaserProps = {
|
||||||
asset: AssetExtended
|
asset: AssetExtended
|
||||||
|
@ -10,7 +10,6 @@ interface ButtonBuyProps {
|
|||||||
hasDatatoken: boolean
|
hasDatatoken: boolean
|
||||||
dtSymbol: string
|
dtSymbol: string
|
||||||
dtBalance: string
|
dtBalance: string
|
||||||
datasetLowPoolLiquidity: boolean
|
|
||||||
assetType: string
|
assetType: string
|
||||||
assetTimeout: string
|
assetTimeout: string
|
||||||
isConsumable: boolean
|
isConsumable: boolean
|
||||||
@ -19,7 +18,6 @@ interface ButtonBuyProps {
|
|||||||
hasDatatokenSelectedComputeAsset?: boolean
|
hasDatatokenSelectedComputeAsset?: boolean
|
||||||
dtSymbolSelectedComputeAsset?: string
|
dtSymbolSelectedComputeAsset?: string
|
||||||
dtBalanceSelectedComputeAsset?: string
|
dtBalanceSelectedComputeAsset?: string
|
||||||
selectedComputeAssetLowPoolLiquidity?: boolean
|
|
||||||
selectedComputeAssetType?: string
|
selectedComputeAssetType?: string
|
||||||
isBalanceSufficient: boolean
|
isBalanceSufficient: boolean
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
@ -39,7 +37,6 @@ function getConsumeHelpText(
|
|||||||
dtSymbol: string,
|
dtSymbol: string,
|
||||||
hasDatatoken: boolean,
|
hasDatatoken: boolean,
|
||||||
hasPreviousOrder: boolean,
|
hasPreviousOrder: boolean,
|
||||||
lowPoolLiquidity: boolean,
|
|
||||||
assetType: string,
|
assetType: string,
|
||||||
isConsumable: boolean,
|
isConsumable: boolean,
|
||||||
isBalanceSufficient: boolean,
|
isBalanceSufficient: boolean,
|
||||||
@ -52,11 +49,9 @@ function getConsumeHelpText(
|
|||||||
? `You bought this ${assetType} already allowing you to use it without paying again.`
|
? `You bought this ${assetType} already allowing you to use it without paying again.`
|
||||||
: hasDatatoken
|
: hasDatatoken
|
||||||
? `You own ${dtBalance} ${dtSymbol} allowing you to use this data set by spending 1 ${dtSymbol}, but without paying OCEAN again.`
|
? `You own ${dtBalance} ${dtSymbol} allowing you to use this data set by spending 1 ${dtSymbol}, but without paying OCEAN again.`
|
||||||
: lowPoolLiquidity
|
|
||||||
? `There are not enought ${dtSymbol} available in the pool for the transaction to take place`
|
|
||||||
: isBalanceSufficient === false
|
: isBalanceSufficient === false
|
||||||
? 'You do not have enough OCEAN in your wallet to purchase this asset.'
|
? 'You do not have enough OCEAN in your wallet to purchase this asset.'
|
||||||
: `For using this ${assetType}, you will buy 1 ${dtSymbol} and immediately spend it back to the publisher and pool.`
|
: `For using this ${assetType}, you will buy 1 ${dtSymbol} and immediately spend it back to the publisher.`
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,16 +60,14 @@ function getComputeAssetHelpText(
|
|||||||
hasDatatoken: boolean,
|
hasDatatoken: boolean,
|
||||||
dtSymbol: string,
|
dtSymbol: string,
|
||||||
dtBalance: string,
|
dtBalance: string,
|
||||||
lowPoolLiquidity: boolean,
|
|
||||||
assetType: string,
|
|
||||||
isConsumable: boolean,
|
isConsumable: boolean,
|
||||||
consumableFeedback: string,
|
consumableFeedback: string,
|
||||||
isBalanceSufficient: boolean,
|
isBalanceSufficient: boolean,
|
||||||
hasPreviousOrderSelectedComputeAsset?: boolean,
|
hasPreviousOrderSelectedComputeAsset?: boolean,
|
||||||
hasDatatokenSelectedComputeAsset?: boolean,
|
hasDatatokenSelectedComputeAsset?: boolean,
|
||||||
|
assetType?: string,
|
||||||
dtSymbolSelectedComputeAsset?: string,
|
dtSymbolSelectedComputeAsset?: string,
|
||||||
dtBalanceSelectedComputeAsset?: string,
|
dtBalanceSelectedComputeAsset?: string,
|
||||||
selectedComputeAssettLowPoolLiquidity?: boolean,
|
|
||||||
selectedComputeAssetType?: string,
|
selectedComputeAssetType?: string,
|
||||||
isAlgorithmConsumable?: boolean,
|
isAlgorithmConsumable?: boolean,
|
||||||
hasProviderFee?: boolean
|
hasProviderFee?: boolean
|
||||||
@ -84,12 +77,12 @@ function getComputeAssetHelpText(
|
|||||||
dtSymbol,
|
dtSymbol,
|
||||||
hasDatatoken,
|
hasDatatoken,
|
||||||
hasPreviousOrder,
|
hasPreviousOrder,
|
||||||
lowPoolLiquidity,
|
|
||||||
assetType,
|
assetType,
|
||||||
isConsumable,
|
isConsumable,
|
||||||
isBalanceSufficient,
|
isBalanceSufficient,
|
||||||
consumableFeedback
|
consumableFeedback
|
||||||
)
|
)
|
||||||
|
|
||||||
const computeAlgoHelpText =
|
const computeAlgoHelpText =
|
||||||
(!dtSymbolSelectedComputeAsset && !dtBalanceSelectedComputeAsset) ||
|
(!dtSymbolSelectedComputeAsset && !dtBalanceSelectedComputeAsset) ||
|
||||||
isConsumable === false ||
|
isConsumable === false ||
|
||||||
@ -99,19 +92,13 @@ function getComputeAssetHelpText(
|
|||||||
? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.`
|
? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.`
|
||||||
: hasDatatokenSelectedComputeAsset
|
: hasDatatokenSelectedComputeAsset
|
||||||
? `You own ${dtBalanceSelectedComputeAsset} ${dtSymbolSelectedComputeAsset} allowing you to use the selected ${selectedComputeAssetType} by spending 1 ${dtSymbolSelectedComputeAsset}, but without paying OCEAN again.`
|
? `You own ${dtBalanceSelectedComputeAsset} ${dtSymbolSelectedComputeAsset} allowing you to use the selected ${selectedComputeAssetType} by spending 1 ${dtSymbolSelectedComputeAsset}, but without paying OCEAN again.`
|
||||||
: selectedComputeAssettLowPoolLiquidity
|
|
||||||
? `There are not enought ${dtSymbolSelectedComputeAsset} available in the pool for the transaction to take place`
|
|
||||||
: isBalanceSufficient === false
|
: isBalanceSufficient === false
|
||||||
? ''
|
? ''
|
||||||
: `Additionally, you will buy 1 ${dtSymbolSelectedComputeAsset} for the ${selectedComputeAssetType} and spend it back to its publisher and pool.`
|
: `Additionally, you will buy 1 ${dtSymbolSelectedComputeAsset} for the ${selectedComputeAssetType} and spend it back to its publisher.`
|
||||||
const providerFeeHelpText = hasProviderFee
|
const providerFeeHelpText = hasProviderFee
|
||||||
? 'In order to start the job you also need to pay the fees for renting the c2d resources.'
|
? 'In order to start the job you also need to pay the fees for renting the c2d resources.'
|
||||||
: 'C2D resources required to start the job are available, no payment required for those fees.'
|
: 'C2D resources required to start the job are available, no payment required for those fees.'
|
||||||
const computeHelpText = selectedComputeAssettLowPoolLiquidity
|
const computeHelpText = `${computeAssetHelpText} ${computeAlgoHelpText} ${providerFeeHelpText}`
|
||||||
? computeAlgoHelpText
|
|
||||||
: lowPoolLiquidity
|
|
||||||
? computeAssetHelpText
|
|
||||||
: `${computeAssetHelpText} ${computeAlgoHelpText} ${providerFeeHelpText}`
|
|
||||||
return computeHelpText
|
return computeHelpText
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +109,6 @@ export default function ButtonBuy({
|
|||||||
hasDatatoken,
|
hasDatatoken,
|
||||||
dtSymbol,
|
dtSymbol,
|
||||||
dtBalance,
|
dtBalance,
|
||||||
datasetLowPoolLiquidity,
|
|
||||||
assetType,
|
assetType,
|
||||||
assetTimeout,
|
assetTimeout,
|
||||||
isConsumable,
|
isConsumable,
|
||||||
@ -132,7 +118,6 @@ export default function ButtonBuy({
|
|||||||
hasDatatokenSelectedComputeAsset,
|
hasDatatokenSelectedComputeAsset,
|
||||||
dtSymbolSelectedComputeAsset,
|
dtSymbolSelectedComputeAsset,
|
||||||
dtBalanceSelectedComputeAsset,
|
dtBalanceSelectedComputeAsset,
|
||||||
selectedComputeAssetLowPoolLiquidity,
|
|
||||||
selectedComputeAssetType,
|
selectedComputeAssetType,
|
||||||
onClick,
|
onClick,
|
||||||
stepText,
|
stepText,
|
||||||
@ -180,7 +165,6 @@ export default function ButtonBuy({
|
|||||||
dtSymbol,
|
dtSymbol,
|
||||||
hasDatatoken,
|
hasDatatoken,
|
||||||
hasPreviousOrder,
|
hasPreviousOrder,
|
||||||
datasetLowPoolLiquidity,
|
|
||||||
assetType,
|
assetType,
|
||||||
isConsumable,
|
isConsumable,
|
||||||
isBalanceSufficient,
|
isBalanceSufficient,
|
||||||
@ -191,16 +175,14 @@ export default function ButtonBuy({
|
|||||||
hasDatatoken,
|
hasDatatoken,
|
||||||
dtSymbol,
|
dtSymbol,
|
||||||
dtBalance,
|
dtBalance,
|
||||||
datasetLowPoolLiquidity,
|
|
||||||
assetType,
|
|
||||||
isConsumable,
|
isConsumable,
|
||||||
consumableFeedback,
|
consumableFeedback,
|
||||||
isBalanceSufficient,
|
isBalanceSufficient,
|
||||||
hasPreviousOrderSelectedComputeAsset,
|
hasPreviousOrderSelectedComputeAsset,
|
||||||
hasDatatokenSelectedComputeAsset,
|
hasDatatokenSelectedComputeAsset,
|
||||||
|
assetType,
|
||||||
dtSymbolSelectedComputeAsset,
|
dtSymbolSelectedComputeAsset,
|
||||||
dtBalanceSelectedComputeAsset,
|
dtBalanceSelectedComputeAsset,
|
||||||
selectedComputeAssetLowPoolLiquidity,
|
|
||||||
selectedComputeAssetType,
|
selectedComputeAssetType,
|
||||||
isAlgorithmConsumable,
|
isAlgorithmConsumable,
|
||||||
hasProviderFee
|
hasProviderFee
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
.titleText {
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
import React, { useState, useEffect, ReactElement } from 'react'
|
|
||||||
import { PoolTransaction } from '.'
|
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
|
||||||
import ExplorerLink from '@shared/ExplorerLink'
|
|
||||||
import { formatPrice } from '@shared/Price/PriceUnit'
|
|
||||||
import styles from './Title.module.css'
|
|
||||||
|
|
||||||
function getTitle(row: PoolTransaction, locale: string) {
|
|
||||||
let title = ''
|
|
||||||
|
|
||||||
switch (row.type) {
|
|
||||||
case 'SWAP': {
|
|
||||||
const { datatoken, baseToken, datatokenValue, baseTokenValue } = row
|
|
||||||
|
|
||||||
const outToken =
|
|
||||||
(datatokenValue < 0 && datatoken) || (baseTokenValue < 0 && baseToken)
|
|
||||||
const outTokenValue =
|
|
||||||
(datatokenValue < 0 && datatokenValue) ||
|
|
||||||
(baseTokenValue < 0 && baseTokenValue)
|
|
||||||
const outTokenSymbol = outToken?.symbol
|
|
||||||
|
|
||||||
const inToken =
|
|
||||||
(datatokenValue > 0 && datatoken) || (baseTokenValue > 0 && baseToken)
|
|
||||||
const inTokenValue =
|
|
||||||
(datatokenValue > 0 && datatokenValue) ||
|
|
||||||
(baseTokenValue > 0 && baseTokenValue)
|
|
||||||
const inTokenSymbol = inToken?.symbol
|
|
||||||
|
|
||||||
title += `Swap ${formatPrice(
|
|
||||||
Math.abs(inTokenValue).toString(),
|
|
||||||
locale
|
|
||||||
)}${inTokenSymbol} for ${formatPrice(
|
|
||||||
Math.abs(outTokenValue).toString(),
|
|
||||||
locale
|
|
||||||
)}${outTokenSymbol}`
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'SETUP': {
|
|
||||||
const firstToken = row.baseToken
|
|
||||||
const firstTokenSymbol = firstToken?.symbol
|
|
||||||
title += `Create pool with ${formatPrice(
|
|
||||||
Math.abs(row.baseTokenValue).toString(),
|
|
||||||
locale
|
|
||||||
)}${firstTokenSymbol}`
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'JOIN':
|
|
||||||
case 'EXIT': {
|
|
||||||
const tokenMoved =
|
|
||||||
Math.abs(row.baseTokenValue) > 0 ? row.baseToken : row.datatoken
|
|
||||||
const tokenValueMoved =
|
|
||||||
Math.abs(row.baseTokenValue) > 0
|
|
||||||
? row.baseTokenValue
|
|
||||||
: row.datatokenValue
|
|
||||||
const tokenSymbol = tokenMoved.symbol
|
|
||||||
|
|
||||||
title += `${row.type === 'JOIN' ? 'Add' : 'Remove'} ${formatPrice(
|
|
||||||
Math.abs(tokenValueMoved).toString(),
|
|
||||||
locale
|
|
||||||
)}${tokenSymbol}`
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return title
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Title({ row }: { row: PoolTransaction }): ReactElement {
|
|
||||||
const [title, setTitle] = useState<string>()
|
|
||||||
const { locale } = useUserPreferences()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!locale || !row) return
|
|
||||||
|
|
||||||
const title = getTitle(row, locale)
|
|
||||||
setTitle(title)
|
|
||||||
}, [row, locale])
|
|
||||||
|
|
||||||
return title ? (
|
|
||||||
<ExplorerLink networkId={row.networkId} path={`/tx/${row.tx}`}>
|
|
||||||
<span className={styles.titleText}>{title}</span>
|
|
||||||
</ExplorerLink>
|
|
||||||
) : null
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
.time {
|
|
||||||
color: var(--color-secondary);
|
|
||||||
}
|
|
@ -1,264 +0,0 @@
|
|||||||
import React, { ReactElement, useCallback, useEffect, useState } from 'react'
|
|
||||||
import Time from '@shared/atoms/Time'
|
|
||||||
import Table, { TableOceanColumn } from '@shared/atoms/Table'
|
|
||||||
import AssetTitle from '@shared/AssetList/AssetListTitle'
|
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
|
||||||
import { gql } from 'urql'
|
|
||||||
import { TransactionHistory_poolTransactions as TransactionHistoryPoolTransactions } from '../../../@types/subgraph/TransactionHistory'
|
|
||||||
import { fetchDataForMultipleChains } from '@utils/subgraph'
|
|
||||||
import NetworkName from '@shared/NetworkName'
|
|
||||||
import { getAssetsFromDtList } from '@utils/aquarius'
|
|
||||||
import { getAsset } from '../../Profile/History/PoolShares/_utils'
|
|
||||||
import { CancelToken } from 'axios'
|
|
||||||
import Title from './Title'
|
|
||||||
import styles from './index.module.css'
|
|
||||||
import { Asset, LoggerInstance } from '@oceanprotocol/lib'
|
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
|
||||||
|
|
||||||
const REFETCH_INTERVAL = 20000
|
|
||||||
|
|
||||||
const txHistoryQueryByPool = gql`
|
|
||||||
query TransactionHistoryByPool($user: String, $pool: String) {
|
|
||||||
poolTransactions(
|
|
||||||
orderBy: timestamp
|
|
||||||
orderDirection: desc
|
|
||||||
where: { pool: $pool, user: $user }
|
|
||||||
first: 1000
|
|
||||||
) {
|
|
||||||
baseToken {
|
|
||||||
symbol
|
|
||||||
address
|
|
||||||
}
|
|
||||||
baseTokenValue
|
|
||||||
datatoken {
|
|
||||||
symbol
|
|
||||||
address
|
|
||||||
}
|
|
||||||
datatokenValue
|
|
||||||
type
|
|
||||||
tx
|
|
||||||
timestamp
|
|
||||||
pool {
|
|
||||||
datatoken {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
const txHistoryQuery = gql`
|
|
||||||
query TransactionHistory($user: String) {
|
|
||||||
poolTransactions(
|
|
||||||
orderBy: timestamp
|
|
||||||
orderDirection: desc
|
|
||||||
where: { user: $user }
|
|
||||||
first: 1000
|
|
||||||
) {
|
|
||||||
baseToken {
|
|
||||||
symbol
|
|
||||||
address
|
|
||||||
}
|
|
||||||
baseTokenValue
|
|
||||||
datatoken {
|
|
||||||
symbol
|
|
||||||
address
|
|
||||||
}
|
|
||||||
datatokenValue
|
|
||||||
type
|
|
||||||
tx
|
|
||||||
timestamp
|
|
||||||
pool {
|
|
||||||
datatoken {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export interface PoolTransaction extends TransactionHistoryPoolTransactions {
|
|
||||||
networkId: number
|
|
||||||
asset: Asset
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns: TableOceanColumn<PoolTransaction>[] = [
|
|
||||||
{
|
|
||||||
name: 'Title',
|
|
||||||
selector: (row) => <Title row={row} />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Data Set',
|
|
||||||
selector: (row) => <AssetTitle asset={row.asset} />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Network',
|
|
||||||
selector: (row) => <NetworkName networkId={row.networkId} />,
|
|
||||||
maxWidth: '12rem'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Time',
|
|
||||||
selector: (row) => (
|
|
||||||
<Time
|
|
||||||
className={styles.time}
|
|
||||||
date={row.timestamp.toString()}
|
|
||||||
relative
|
|
||||||
isUnix
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
maxWidth: '10rem'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// hack! if we use a function to omit one field this will display a strange refresh to the enduser for each row
|
|
||||||
const columnsMinimal = [columns[0], columns[3]]
|
|
||||||
|
|
||||||
export default function PoolTransactions({
|
|
||||||
poolAddress,
|
|
||||||
poolChainId,
|
|
||||||
minimal,
|
|
||||||
accountId
|
|
||||||
}: {
|
|
||||||
poolAddress?: string
|
|
||||||
poolChainId?: number
|
|
||||||
minimal?: boolean
|
|
||||||
accountId: string
|
|
||||||
}): ReactElement {
|
|
||||||
const { chainIds } = useUserPreferences()
|
|
||||||
const { appConfig } = useMarketMetadata()
|
|
||||||
const cancelToken = useCancelToken()
|
|
||||||
|
|
||||||
const [transactions, setTransactions] = useState<PoolTransaction[]>()
|
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
|
||||||
const [dataFetchInterval, setDataFetchInterval] = useState<NodeJS.Timeout>()
|
|
||||||
const [data, setData] = useState<PoolTransaction[]>()
|
|
||||||
|
|
||||||
const getPoolTransactionData = useCallback(async () => {
|
|
||||||
const variables = {
|
|
||||||
user: accountId?.toLowerCase(),
|
|
||||||
pool: poolAddress?.toLowerCase()
|
|
||||||
}
|
|
||||||
const transactions: PoolTransaction[] = []
|
|
||||||
const result = await fetchDataForMultipleChains(
|
|
||||||
poolAddress ? txHistoryQueryByPool : txHistoryQuery,
|
|
||||||
variables,
|
|
||||||
poolAddress ? [poolChainId] : chainIds
|
|
||||||
)
|
|
||||||
|
|
||||||
for (let i = 0; i < result.length; i++) {
|
|
||||||
result[i].poolTransactions.forEach((poolTransaction: PoolTransaction) => {
|
|
||||||
transactions.push(poolTransaction)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JSON.stringify(data) !== JSON.stringify(transactions)) {
|
|
||||||
setData(transactions)
|
|
||||||
}
|
|
||||||
}, [accountId, chainIds, data, poolAddress, poolChainId])
|
|
||||||
|
|
||||||
const getPoolTransactions = useCallback(
|
|
||||||
async (cancelToken: CancelToken) => {
|
|
||||||
if (!data) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const poolTransactions: PoolTransaction[] = []
|
|
||||||
let dtList: string[] = []
|
|
||||||
|
|
||||||
dtList = [...new Set(data.map((item) => item.pool.datatoken.id))]
|
|
||||||
if (dtList.length === 0) {
|
|
||||||
setTransactions([])
|
|
||||||
setIsLoading(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const ddoList = !minimal
|
|
||||||
? await getAssetsFromDtList(dtList, chainIds, cancelToken)
|
|
||||||
: []
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
poolTransactions.push({
|
|
||||||
...data[i],
|
|
||||||
networkId: !minimal
|
|
||||||
? getAsset(ddoList, data[i].pool.datatoken.id)?.chainId
|
|
||||||
: poolChainId,
|
|
||||||
asset: !minimal ? getAsset(ddoList, data[i].pool.datatoken.id) : null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const sortedTransactions = poolTransactions.sort(
|
|
||||||
(a, b) => b.timestamp - a.timestamp
|
|
||||||
)
|
|
||||||
|
|
||||||
setTransactions(sortedTransactions)
|
|
||||||
setIsLoading(false)
|
|
||||||
},
|
|
||||||
[data, minimal, chainIds, poolChainId]
|
|
||||||
)
|
|
||||||
|
|
||||||
//
|
|
||||||
// Get data, periodically
|
|
||||||
//
|
|
||||||
useEffect(() => {
|
|
||||||
if (!appConfig?.metadataCacheUri) return
|
|
||||||
|
|
||||||
async function getTransactions() {
|
|
||||||
try {
|
|
||||||
await getPoolTransactionData()
|
|
||||||
if (dataFetchInterval) return
|
|
||||||
const interval = setInterval(async () => {
|
|
||||||
await getPoolTransactionData()
|
|
||||||
}, REFETCH_INTERVAL)
|
|
||||||
setDataFetchInterval(interval)
|
|
||||||
} catch (error) {
|
|
||||||
LoggerInstance.error(
|
|
||||||
'Error fetching pool transactions: ',
|
|
||||||
error.message
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getTransactions()
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearInterval(dataFetchInterval)
|
|
||||||
}
|
|
||||||
}, [getPoolTransactionData, dataFetchInterval, appConfig.metadataCacheUri])
|
|
||||||
|
|
||||||
//
|
|
||||||
// Transform to final transactions
|
|
||||||
//
|
|
||||||
useEffect(() => {
|
|
||||||
if (!cancelToken()) return
|
|
||||||
async function transformData() {
|
|
||||||
try {
|
|
||||||
setIsLoading(true)
|
|
||||||
await getPoolTransactions(cancelToken())
|
|
||||||
} catch (error) {
|
|
||||||
LoggerInstance.error(
|
|
||||||
'Error fetching pool transactions: ',
|
|
||||||
error.message
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transformData()
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cancelToken()
|
|
||||||
}
|
|
||||||
}, [cancelToken, getPoolTransactions])
|
|
||||||
|
|
||||||
return accountId ? (
|
|
||||||
<Table
|
|
||||||
columns={minimal ? columnsMinimal : columns}
|
|
||||||
data={transactions}
|
|
||||||
isLoading={isLoading}
|
|
||||||
noTableHead={minimal}
|
|
||||||
dense={minimal}
|
|
||||||
pagination={
|
|
||||||
minimal ? transactions?.length >= 4 : transactions?.length >= 9
|
|
||||||
}
|
|
||||||
paginationPerPage={minimal ? 5 : 10}
|
|
||||||
emptyMessage={chainIds.length === 0 ? 'No network selected' : null}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div>Please connect your Web3 wallet.</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -6,9 +6,6 @@
|
|||||||
font-weight: var(--font-weight-base);
|
font-weight: var(--font-weight-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
.removeTvlPadding {
|
|
||||||
padding-left: 0 !important;
|
|
||||||
}
|
|
||||||
/* fiat currency symbol */
|
/* fiat currency symbol */
|
||||||
.conversion strong span {
|
.conversion strong span {
|
||||||
font-weight: var(--font-weight-base);
|
font-weight: var(--font-weight-base);
|
||||||
|
@ -33,16 +33,13 @@ export default function PriceUnit({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.price} ${styles[size]} ${className}`}>
|
<div className={`${styles.price} ${styles[size]} ${className}`}>
|
||||||
{type && type === 'free' ? (
|
{type === 'free' ? (
|
||||||
<div> Free </div>
|
<div>Free</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
{Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '}
|
{Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '}
|
||||||
<span className={styles.symbol}>{symbol}</span>
|
<span className={styles.symbol}>{symbol}</span>
|
||||||
{type && type === 'dynamic' && (
|
|
||||||
<Badge label="pool" className={styles.badge} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{conversion && <Conversion price={price} />}
|
{conversion && <Conversion price={price} />}
|
||||||
</>
|
</>
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
.empty {
|
|
||||||
color: var(--color-secondary);
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
}
|
|
@ -1,9 +1,5 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import styles from './index.module.css'
|
|
||||||
import Loader from '../atoms/Loader'
|
|
||||||
import Tooltip from '../atoms/Tooltip'
|
|
||||||
import PriceUnit from './PriceUnit'
|
import PriceUnit from './PriceUnit'
|
||||||
import { AccessDetails, OrderPriceAndFees } from 'src/@types/Price'
|
|
||||||
|
|
||||||
export default function Price({
|
export default function Price({
|
||||||
accessDetails,
|
accessDetails,
|
||||||
@ -18,7 +14,10 @@ export default function Price({
|
|||||||
conversion?: boolean
|
conversion?: boolean
|
||||||
size?: 'small' | 'mini' | 'large'
|
size?: 'small' | 'mini' | 'large'
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return accessDetails?.price || accessDetails?.type === 'free' ? (
|
const isSupported =
|
||||||
|
accessDetails?.type === 'fixed' || accessDetails?.type === 'free'
|
||||||
|
|
||||||
|
return isSupported ? (
|
||||||
<PriceUnit
|
<PriceUnit
|
||||||
price={`${orderPriceAndFees?.price || accessDetails?.price}`}
|
price={`${orderPriceAndFees?.price || accessDetails?.price}`}
|
||||||
symbol={accessDetails.baseToken?.symbol}
|
symbol={accessDetails.baseToken?.symbol}
|
||||||
@ -27,18 +26,5 @@ export default function Price({
|
|||||||
conversion={conversion}
|
conversion={conversion}
|
||||||
type={accessDetails.type}
|
type={accessDetails.type}
|
||||||
/>
|
/>
|
||||||
) : !accessDetails || accessDetails?.type === '' ? (
|
) : null
|
||||||
<div className={styles.empty}>
|
|
||||||
No price set{' '}
|
|
||||||
<Tooltip content="No pricing mechanism has been set on this asset yet." />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
// TODO: Hacky hack, put back some check for low liquidity
|
|
||||||
// ) : price.isConsumable !== 'true' ? (
|
|
||||||
// <div className={styles.empty}>
|
|
||||||
// Low liquidity{' '}
|
|
||||||
// <Tooltip content="This pool does not have enough liquidity for using this data set." />
|
|
||||||
// </div>
|
|
||||||
<Loader message="Retrieving price..." />
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
.token {
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbol {
|
|
||||||
font-weight: var(--font-weight-base);
|
|
||||||
color: var(--color-secondary);
|
|
||||||
font-size: var(--font-size-base);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
display: inline-block;
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 0.3rem;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-right: calc(var(--spacer) / 8);
|
|
||||||
margin-top: -0.2rem;
|
|
||||||
background: var(--background-body);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon svg {
|
|
||||||
width: var(--font-size-base);
|
|
||||||
height: var(--font-size-base);
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversion {
|
|
||||||
composes: token;
|
|
||||||
margin-bottom: 0;
|
|
||||||
font-weight: var(--font-weight-base) !important;
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
padding-left: var(--font-size-base);
|
|
||||||
padding-top: calc(var(--spacer) / 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversion strong {
|
|
||||||
font-size: var(--font-size-base);
|
|
||||||
color: var(--font-color-heading);
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Data Token Icon Style */
|
|
||||||
.icon:not([class*='OCEAN']) path {
|
|
||||||
fill: var(--brand-violet);
|
|
||||||
}
|
|
||||||
|
|
||||||
.noIcon {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.mini {
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
import React, { ReactElement } from 'react'
|
|
||||||
import styles from './index.module.css'
|
|
||||||
import PriceUnit from '@shared/Price/PriceUnit'
|
|
||||||
import Logo from '@shared/atoms/Logo'
|
|
||||||
import Conversion from '@shared/Price/Conversion'
|
|
||||||
|
|
||||||
export default function Token({
|
|
||||||
symbol,
|
|
||||||
balance,
|
|
||||||
conversion,
|
|
||||||
noIcon,
|
|
||||||
size
|
|
||||||
}: {
|
|
||||||
symbol: string
|
|
||||||
balance: string
|
|
||||||
conversion?: boolean
|
|
||||||
noIcon?: boolean
|
|
||||||
size?: 'small' | 'mini'
|
|
||||||
}): ReactElement {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={`${styles.token} ${size ? styles[size] : ''}`}>
|
|
||||||
<figure
|
|
||||||
className={`${styles.icon} ${symbol} ${noIcon ? styles.noIcon : ''}`}
|
|
||||||
>
|
|
||||||
<Logo noWordmark />
|
|
||||||
</figure>
|
|
||||||
<PriceUnit price={balance} symbol={symbol} size={size} />
|
|
||||||
</div>
|
|
||||||
{conversion && (
|
|
||||||
<Conversion price={balance} className={`${styles.conversion}`} />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
import React, { ReactElement } from 'react'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import Loader from '@shared/atoms/Loader'
|
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
|
||||||
import Tooltip from '@shared/atoms/Tooltip'
|
|
||||||
import content from '../../../../content/price.json'
|
|
||||||
|
|
||||||
export function ButtonApprove({
|
|
||||||
amount,
|
|
||||||
tokenSymbol,
|
|
||||||
approveTokens,
|
|
||||||
isLoading
|
|
||||||
}: {
|
|
||||||
amount: string
|
|
||||||
tokenSymbol: string
|
|
||||||
approveTokens: (amount: string) => void
|
|
||||||
isLoading: boolean
|
|
||||||
}): ReactElement {
|
|
||||||
const { infiniteApproval } = useUserPreferences()
|
|
||||||
|
|
||||||
return isLoading ? (
|
|
||||||
<Loader message={`Approving ${tokenSymbol}...`} />
|
|
||||||
) : infiniteApproval ? (
|
|
||||||
<Button
|
|
||||||
style="primary"
|
|
||||||
size="small"
|
|
||||||
disabled={parseInt(amount) < 1}
|
|
||||||
onClick={() => approveTokens(`${2 ** 53 - 1}`)}
|
|
||||||
>
|
|
||||||
Approve {tokenSymbol}{' '}
|
|
||||||
<Tooltip
|
|
||||||
content={content.pool.tooltips.approveInfinite.replace(
|
|
||||||
'COIN',
|
|
||||||
tokenSymbol
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button style="primary" size="small" onClick={() => approveTokens(amount)}>
|
|
||||||
Approve {amount} {tokenSymbol}
|
|
||||||
<Tooltip
|
|
||||||
content={content.pool.tooltips.approveSpecific.replace(
|
|
||||||
'COIN',
|
|
||||||
tokenSymbol
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
import React, { ReactElement, useCallback, useEffect, useState } from 'react'
|
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { ButtonApprove } from './ButtonApprove'
|
|
||||||
import { allowance, approve, LoggerInstance } from '@oceanprotocol/lib'
|
|
||||||
|
|
||||||
export default function TokenApproval({
|
|
||||||
actionButton,
|
|
||||||
disabled,
|
|
||||||
amount,
|
|
||||||
tokenAddress,
|
|
||||||
tokenSymbol,
|
|
||||||
setSubmitting,
|
|
||||||
setIsTokenApproved
|
|
||||||
}: {
|
|
||||||
actionButton: JSX.Element
|
|
||||||
disabled: boolean
|
|
||||||
amount: string
|
|
||||||
tokenAddress: string
|
|
||||||
tokenSymbol: string
|
|
||||||
setSubmitting?: (isSubmitting: boolean) => void
|
|
||||||
setIsTokenApproved: (isApproved: boolean) => void
|
|
||||||
}): ReactElement {
|
|
||||||
const { asset, isAssetNetwork } = useAsset()
|
|
||||||
const [tokenApproved, setTokenApproved] = useState(false)
|
|
||||||
const [loading, setLoading] = useState(false)
|
|
||||||
const { web3, accountId } = useWeb3()
|
|
||||||
|
|
||||||
const spender = asset?.accessDetails?.addressOrId
|
|
||||||
|
|
||||||
const checkTokenApproval = useCallback(async () => {
|
|
||||||
if (!web3 || !tokenAddress || !spender || !isAssetNetwork || !amount) return
|
|
||||||
|
|
||||||
const allowanceValue = await allowance(
|
|
||||||
web3,
|
|
||||||
tokenAddress,
|
|
||||||
accountId,
|
|
||||||
spender
|
|
||||||
)
|
|
||||||
LoggerInstance.log(`[token approval] allowanceValue: ${allowanceValue}`)
|
|
||||||
|
|
||||||
if (!allowanceValue) return
|
|
||||||
|
|
||||||
new Decimal(amount).greaterThan(new Decimal('0')) &&
|
|
||||||
setTokenApproved(
|
|
||||||
new Decimal(allowanceValue).greaterThanOrEqualTo(new Decimal(amount))
|
|
||||||
)
|
|
||||||
setIsTokenApproved(
|
|
||||||
new Decimal(allowanceValue).greaterThanOrEqualTo(new Decimal(amount))
|
|
||||||
)
|
|
||||||
}, [web3, tokenAddress, spender, accountId, amount, isAssetNetwork])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
checkTokenApproval()
|
|
||||||
}, [checkTokenApproval])
|
|
||||||
|
|
||||||
async function approveTokens(amount: string) {
|
|
||||||
setLoading(true)
|
|
||||||
setSubmitting(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const tx = await approve(web3, accountId, tokenAddress, spender, amount)
|
|
||||||
LoggerInstance.log(`[token approval] Approve tokens tx:`, tx)
|
|
||||||
} catch (error) {
|
|
||||||
LoggerInstance.error(
|
|
||||||
`[token approval] Approve tokens tx failed:`,
|
|
||||||
error.message
|
|
||||||
)
|
|
||||||
} finally {
|
|
||||||
await checkTokenApproval()
|
|
||||||
setLoading(false)
|
|
||||||
setSubmitting(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{tokenApproved ||
|
|
||||||
disabled ||
|
|
||||||
amount === '0' ||
|
|
||||||
amount === '' ||
|
|
||||||
!amount ||
|
|
||||||
typeof amount === 'undefined' ? (
|
|
||||||
actionButton
|
|
||||||
) : (
|
|
||||||
<ButtonApprove
|
|
||||||
amount={amount}
|
|
||||||
tokenSymbol={tokenSymbol}
|
|
||||||
approveTokens={approveTokens}
|
|
||||||
isLoading={loading}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -19,26 +19,11 @@ export default function App({
|
|||||||
const { siteContent, appConfig } = useMarketMetadata()
|
const { siteContent, appConfig } = useMarketMetadata()
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||||
function openInNewTab() {
|
|
||||||
window
|
|
||||||
.open(
|
|
||||||
'https://blog.oceanprotocol.com/how-to-publish-a-data-nft-f58ad2a622a9',
|
|
||||||
'_blank'
|
|
||||||
)
|
|
||||||
.focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.app}>
|
<div className={styles.app}>
|
||||||
{siteContent?.announcement !== '' && (
|
{siteContent?.announcement !== '' && (
|
||||||
<AnnouncementBanner
|
<AnnouncementBanner text={siteContent?.announcement} />
|
||||||
text={siteContent?.announcement}
|
|
||||||
action={{
|
|
||||||
name: 'Explore OceanONDA V4.',
|
|
||||||
style: 'link',
|
|
||||||
handleAction: openInNewTab
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
|||||||
import AssetComputeList from '@shared/AssetList/AssetComputeList'
|
import AssetComputeList from '@shared/AssetList/AssetComputeList'
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
|
|
||||||
export default function AlgorithmDatasetsListForCompute({
|
export default function AlgorithmDatasetsListForCompute({
|
||||||
asset,
|
asset,
|
||||||
@ -19,7 +18,7 @@ export default function AlgorithmDatasetsListForCompute({
|
|||||||
useState<AssetSelectionAsset[]>()
|
useState<AssetSelectionAsset[]>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!asset) return
|
if (!asset || !asset?.accessDetails?.type) return
|
||||||
|
|
||||||
async function getDatasetsAllowedForCompute() {
|
async function getDatasetsAllowedForCompute() {
|
||||||
const isCompute = Boolean(getServiceByName(asset, 'compute'))
|
const isCompute = Boolean(getServiceByName(asset, 'compute'))
|
||||||
|
@ -10,9 +10,7 @@ import { useAsset } from '@context/Asset'
|
|||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
import content from '../../../../../content/pages/startComputeDataset.json'
|
import content from '../../../../../content/pages/startComputeDataset.json'
|
||||||
import { Asset } from '@oceanprotocol/lib'
|
import { Asset } from '@oceanprotocol/lib'
|
||||||
import { OrderPriceAndFees } from 'src/@types/Price'
|
|
||||||
import { getAccessDetails } from '@utils/accessDetailsAndPricing'
|
import { getAccessDetails } from '@utils/accessDetailsAndPricing'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import Decimal from 'decimal.js'
|
import Decimal from 'decimal.js'
|
||||||
import { MAX_DECIMALS } from '@utils/constants'
|
import { MAX_DECIMALS } from '@utils/constants'
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
import { useMarketMetadata } from '@context/MarketMetadata'
|
||||||
@ -28,7 +26,6 @@ export default function FormStartCompute({
|
|||||||
hasPreviousOrder,
|
hasPreviousOrder,
|
||||||
hasDatatoken,
|
hasDatatoken,
|
||||||
dtBalance,
|
dtBalance,
|
||||||
datasetLowPoolLiquidity,
|
|
||||||
assetType,
|
assetType,
|
||||||
assetTimeout,
|
assetTimeout,
|
||||||
hasPreviousOrderSelectedComputeAsset,
|
hasPreviousOrderSelectedComputeAsset,
|
||||||
@ -36,7 +33,6 @@ export default function FormStartCompute({
|
|||||||
oceanSymbol,
|
oceanSymbol,
|
||||||
dtSymbolSelectedComputeAsset,
|
dtSymbolSelectedComputeAsset,
|
||||||
dtBalanceSelectedComputeAsset,
|
dtBalanceSelectedComputeAsset,
|
||||||
selectedComputeAssetLowPoolLiquidity,
|
|
||||||
selectedComputeAssetType,
|
selectedComputeAssetType,
|
||||||
selectedComputeAssetTimeout,
|
selectedComputeAssetTimeout,
|
||||||
stepText,
|
stepText,
|
||||||
@ -56,7 +52,6 @@ export default function FormStartCompute({
|
|||||||
hasPreviousOrder: boolean
|
hasPreviousOrder: boolean
|
||||||
hasDatatoken: boolean
|
hasDatatoken: boolean
|
||||||
dtBalance: string
|
dtBalance: string
|
||||||
datasetLowPoolLiquidity: boolean
|
|
||||||
assetType: string
|
assetType: string
|
||||||
assetTimeout: string
|
assetTimeout: string
|
||||||
hasPreviousOrderSelectedComputeAsset?: boolean
|
hasPreviousOrderSelectedComputeAsset?: boolean
|
||||||
@ -64,7 +59,6 @@ export default function FormStartCompute({
|
|||||||
oceanSymbol?: string
|
oceanSymbol?: string
|
||||||
dtSymbolSelectedComputeAsset?: string
|
dtSymbolSelectedComputeAsset?: string
|
||||||
dtBalanceSelectedComputeAsset?: string
|
dtBalanceSelectedComputeAsset?: string
|
||||||
selectedComputeAssetLowPoolLiquidity?: boolean
|
|
||||||
selectedComputeAssetType?: string
|
selectedComputeAssetType?: string
|
||||||
selectedComputeAssetTimeout?: string
|
selectedComputeAssetTimeout?: string
|
||||||
stepText: string
|
stepText: string
|
||||||
@ -180,15 +174,17 @@ export default function FormStartCompute({
|
|||||||
state="info"
|
state="info"
|
||||||
text={siteContent.warning.ctd}
|
text={siteContent.warning.ctd}
|
||||||
/>
|
/>
|
||||||
{content.form.data.map((field: FormFieldContent) => (
|
{content.form.data.map((field: FormFieldContent) => {
|
||||||
<Field
|
return (
|
||||||
key={field.name}
|
<Field
|
||||||
{...field}
|
key={field.name}
|
||||||
options={algorithms}
|
{...field}
|
||||||
component={Input}
|
options={algorithms}
|
||||||
disabled={isLoading}
|
component={Input}
|
||||||
/>
|
disabled={isLoading || isComputeButtonDisabled}
|
||||||
))}
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
<PriceOutput
|
<PriceOutput
|
||||||
hasPreviousOrder={hasPreviousOrder}
|
hasPreviousOrder={hasPreviousOrder}
|
||||||
@ -221,7 +217,6 @@ export default function FormStartCompute({
|
|||||||
hasDatatoken={hasDatatoken}
|
hasDatatoken={hasDatatoken}
|
||||||
dtSymbol={asset?.datatokens[0]?.symbol}
|
dtSymbol={asset?.datatokens[0]?.symbol}
|
||||||
dtBalance={dtBalance}
|
dtBalance={dtBalance}
|
||||||
datasetLowPoolLiquidity={datasetLowPoolLiquidity}
|
|
||||||
assetTimeout={assetTimeout}
|
assetTimeout={assetTimeout}
|
||||||
assetType={assetType}
|
assetType={assetType}
|
||||||
hasPreviousOrderSelectedComputeAsset={
|
hasPreviousOrderSelectedComputeAsset={
|
||||||
@ -230,9 +225,6 @@ export default function FormStartCompute({
|
|||||||
hasDatatokenSelectedComputeAsset={hasDatatokenSelectedComputeAsset}
|
hasDatatokenSelectedComputeAsset={hasDatatokenSelectedComputeAsset}
|
||||||
dtSymbolSelectedComputeAsset={dtSymbolSelectedComputeAsset}
|
dtSymbolSelectedComputeAsset={dtSymbolSelectedComputeAsset}
|
||||||
dtBalanceSelectedComputeAsset={dtBalanceSelectedComputeAsset}
|
dtBalanceSelectedComputeAsset={dtBalanceSelectedComputeAsset}
|
||||||
selectedComputeAssetLowPoolLiquidity={
|
|
||||||
selectedComputeAssetLowPoolLiquidity
|
|
||||||
}
|
|
||||||
selectedComputeAssetType={selectedComputeAssetType}
|
selectedComputeAssetType={selectedComputeAssetType}
|
||||||
stepText={stepText}
|
stepText={stepText}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
@ -1,5 +1,37 @@
|
|||||||
|
.container {
|
||||||
|
margin-left: calc(-1 * var(--spacer) / 1.5);
|
||||||
|
margin-right: calc(-1 * var(--spacer) / 1.5);
|
||||||
|
padding: calc(var(--spacer) / 1.5) calc(var(--spacer) / 1.5)
|
||||||
|
calc(var(--spacer) / 2) calc(var(--spacer) / 1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 40rem) {
|
||||||
|
.container {
|
||||||
|
padding-left: var(--spacer);
|
||||||
|
padding-right: var(--spacer);
|
||||||
|
margin-left: calc(-1 * var(--spacer));
|
||||||
|
margin-right: calc(-1 * var(--spacer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
composes: container;
|
||||||
|
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section.highlight {
|
||||||
|
background: var(--background-highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
composes: section from './Pool/Section/index.module.css';
|
composes: section;
|
||||||
margin-top: calc(var(--spacer) / 1.5);
|
margin-top: calc(var(--spacer) / 1.5);
|
||||||
padding: calc(var(--spacer) / 1.5);
|
padding: calc(var(--spacer) / 1.5);
|
||||||
background: var(--background-highlight);
|
background: var(--background-highlight);
|
||||||
@ -11,7 +43,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
composes: title from './Pool/Section/Title.module.css';
|
font-size: var(--font-size-base);
|
||||||
|
margin-bottom: calc(var(--spacer) / 3);
|
||||||
|
color: var(--color-secondary);
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
@ -1,9 +1,9 @@
|
|||||||
import React, { ReactElement, ReactNode, useState } from 'react'
|
import React, { ReactElement, ReactNode, useState } from 'react'
|
||||||
import Button from '@shared/atoms/Button'
|
import Button from '@shared/atoms/Button'
|
||||||
import styles from './AssetActionHistoryTable.module.css'
|
import styles from './History.module.css'
|
||||||
import Caret from '@images/caret.svg'
|
import Caret from '@images/caret.svg'
|
||||||
|
|
||||||
export default function AssetActionHistoryTable({
|
export default function ComputeHistory({
|
||||||
title,
|
title,
|
||||||
children
|
children
|
||||||
}: {
|
}: {
|
@ -3,7 +3,6 @@ import { useAsset } from '@context/Asset'
|
|||||||
import PriceUnit from '@shared/Price/PriceUnit'
|
import PriceUnit from '@shared/Price/PriceUnit'
|
||||||
import Tooltip from '@shared/atoms/Tooltip'
|
import Tooltip from '@shared/atoms/Tooltip'
|
||||||
import styles from './PriceOutput.module.css'
|
import styles from './PriceOutput.module.css'
|
||||||
import { AccessDetails } from 'src/@types/Price'
|
|
||||||
import { MAX_DECIMALS } from '@utils/constants'
|
import { MAX_DECIMALS } from '@utils/constants'
|
||||||
import Decimal from 'decimal.js'
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
@ -17,8 +16,8 @@ interface PriceOutputProps {
|
|||||||
hasDatatokenSelectedComputeAsset: boolean
|
hasDatatokenSelectedComputeAsset: boolean
|
||||||
algorithmConsumeDetails: AccessDetails
|
algorithmConsumeDetails: AccessDetails
|
||||||
selectedComputeAssetTimeout: string
|
selectedComputeAssetTimeout: string
|
||||||
datasetOrderPrice?: number
|
datasetOrderPrice?: string
|
||||||
algoOrderPrice?: number
|
algoOrderPrice?: string
|
||||||
providerFeeAmount?: string
|
providerFeeAmount?: string
|
||||||
validUntil?: string
|
validUntil?: string
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,11 @@
|
|||||||
calc(var(--spacer) * 1.5);
|
calc(var(--spacer) * 1.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.feedback {
|
.feedback {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: calc(var(--spacer) / 2);
|
margin-top: calc(var(--spacer) / 2);
|
||||||
|
@ -33,19 +33,14 @@ import {
|
|||||||
} from '@utils/compute'
|
} from '@utils/compute'
|
||||||
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
||||||
import AlgorithmDatasetsListForCompute from './AlgorithmDatasetsListForCompute'
|
import AlgorithmDatasetsListForCompute from './AlgorithmDatasetsListForCompute'
|
||||||
import AssetActionHistoryTable from '../AssetActionHistoryTable'
|
import ComputeHistory from './History'
|
||||||
import ComputeJobs from '../../../Profile/History/ComputeJobs'
|
import ComputeJobs from '../../../Profile/History/ComputeJobs'
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { Decimal } from 'decimal.js'
|
import { Decimal } from 'decimal.js'
|
||||||
import { useAbortController } from '@hooks/useAbortController'
|
import { useAbortController } from '@hooks/useAbortController'
|
||||||
import { getOrderPriceAndFees } from '@utils/accessDetailsAndPricing'
|
import { getOrderPriceAndFees } from '@utils/accessDetailsAndPricing'
|
||||||
import { OrderPriceAndFees } from 'src/@types/Price'
|
|
||||||
import { handleComputeOrder } from '@utils/order'
|
import { handleComputeOrder } from '@utils/order'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { getComputeFeedback } from '@utils/feedback'
|
import { getComputeFeedback } from '@utils/feedback'
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
|
||||||
import { getPoolData } from '@context/Pool/_utils'
|
|
||||||
import { getDummyWeb3 } from '@utils/web3'
|
import { getDummyWeb3 } from '@utils/web3'
|
||||||
import { initializeProviderForCompute } from '@utils/provider'
|
import { initializeProviderForCompute } from '@utils/provider'
|
||||||
|
|
||||||
@ -63,8 +58,6 @@ export default function Compute({
|
|||||||
consumableFeedback?: string
|
consumableFeedback?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { accountId, web3 } = useWeb3()
|
const { accountId, web3 } = useWeb3()
|
||||||
const { getOpcFeeForToken } = useMarketMetadata()
|
|
||||||
const { poolData } = usePool()
|
|
||||||
const newAbortController = useAbortController()
|
const newAbortController = useAbortController()
|
||||||
const newCancelToken = useCancelToken()
|
const newCancelToken = useCancelToken()
|
||||||
|
|
||||||
@ -108,6 +101,8 @@ export default function Compute({
|
|||||||
!hasAlgoAssetDatatoken &&
|
!hasAlgoAssetDatatoken &&
|
||||||
!isConsumableaAlgorithmPrice)
|
!isConsumableaAlgorithmPrice)
|
||||||
|
|
||||||
|
const isUnsupportedPricing = asset?.accessDetails?.type === 'NOT_SUPPORTED'
|
||||||
|
|
||||||
async function checkAssetDTBalance(asset: DDO): Promise<boolean> {
|
async function checkAssetDTBalance(asset: DDO): Promise<boolean> {
|
||||||
if (!asset?.services[0].datatokenAddress) return
|
if (!asset?.services[0].datatokenAddress) return
|
||||||
const web3 = await getDummyWeb3(asset?.chainId)
|
const web3 = await getDummyWeb3(asset?.chainId)
|
||||||
@ -168,26 +163,9 @@ export default function Compute({
|
|||||||
asset.metadata.type
|
asset.metadata.type
|
||||||
)[0]
|
)[0]
|
||||||
)
|
)
|
||||||
const poolParams =
|
|
||||||
asset?.accessDetails?.type === 'dynamic'
|
|
||||||
? {
|
|
||||||
tokenInLiquidity: poolData?.baseTokenLiquidity,
|
|
||||||
tokenOutLiquidity: poolData?.datatokenLiquidity,
|
|
||||||
tokenOutAmount: '1',
|
|
||||||
opcFee: getOpcFeeForToken(
|
|
||||||
asset?.accessDetails?.baseToken.address,
|
|
||||||
asset?.chainId
|
|
||||||
),
|
|
||||||
lpSwapFee: poolData?.liquidityProviderSwapFee,
|
|
||||||
publishMarketSwapFee:
|
|
||||||
asset?.accessDetails?.publisherMarketOrderFee,
|
|
||||||
consumeMarketSwapFee: '0'
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
const datasetPriceAndFees = await getOrderPriceAndFees(
|
const datasetPriceAndFees = await getOrderPriceAndFees(
|
||||||
asset,
|
asset,
|
||||||
ZERO_ADDRESS,
|
ZERO_ADDRESS,
|
||||||
poolParams,
|
|
||||||
initializedProvider?.datasets?.[0]?.providerFee
|
initializedProvider?.datasets?.[0]?.providerFee
|
||||||
)
|
)
|
||||||
if (!datasetPriceAndFees)
|
if (!datasetPriceAndFees)
|
||||||
@ -208,32 +186,9 @@ export default function Compute({
|
|||||||
selectedAlgorithmAsset?.metadata?.type
|
selectedAlgorithmAsset?.metadata?.type
|
||||||
)[0]
|
)[0]
|
||||||
)
|
)
|
||||||
let algoPoolParams = null
|
|
||||||
if (selectedAlgorithmAsset?.accessDetails?.type === 'dynamic') {
|
|
||||||
const response = await getPoolData(
|
|
||||||
selectedAlgorithmAsset.chainId,
|
|
||||||
selectedAlgorithmAsset.accessDetails?.addressOrId,
|
|
||||||
selectedAlgorithmAsset?.nft.owner,
|
|
||||||
accountId || ''
|
|
||||||
)
|
|
||||||
algoPoolParams = {
|
|
||||||
tokenInLiquidity: response?.poolData?.baseTokenLiquidity,
|
|
||||||
tokenOutLiquidity: response?.poolData?.datatokenLiquidity,
|
|
||||||
tokenOutAmount: '1',
|
|
||||||
opcFee: getOpcFeeForToken(
|
|
||||||
selectedAlgorithmAsset?.accessDetails?.baseToken.address,
|
|
||||||
selectedAlgorithmAsset?.chainId
|
|
||||||
),
|
|
||||||
lpSwapFee: response?.poolData?.liquidityProviderSwapFee,
|
|
||||||
publishMarketSwapFee:
|
|
||||||
selectedAlgorithmAsset?.accessDetails?.publisherMarketOrderFee,
|
|
||||||
consumeMarketSwapFee: '0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const algorithmOrderPriceAndFees = await getOrderPriceAndFees(
|
const algorithmOrderPriceAndFees = await getOrderPriceAndFees(
|
||||||
selectedAlgorithmAsset,
|
selectedAlgorithmAsset,
|
||||||
ZERO_ADDRESS,
|
ZERO_ADDRESS,
|
||||||
algoPoolParams,
|
|
||||||
initializedProvider.algorithm.providerFee
|
initializedProvider.algorithm.providerFee
|
||||||
)
|
)
|
||||||
if (!algorithmOrderPriceAndFees)
|
if (!algorithmOrderPriceAndFees)
|
||||||
@ -248,11 +203,11 @@ export default function Compute({
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!asset?.accessDetails || !accountId) return
|
if (!asset?.accessDetails || !accountId || isUnsupportedPricing) return
|
||||||
|
|
||||||
setIsConsumablePrice(asset?.accessDetails?.isPurchasable)
|
setIsConsumablePrice(asset?.accessDetails?.isPurchasable)
|
||||||
setValidOrderTx(asset?.accessDetails?.validOrderTx)
|
setValidOrderTx(asset?.accessDetails?.validOrderTx)
|
||||||
}, [asset?.accessDetails, accountId])
|
}, [asset?.accessDetails, accountId, isUnsupportedPricing])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedAlgorithmAsset?.accessDetails || !accountId) return
|
if (!selectedAlgorithmAsset?.accessDetails || !accountId) return
|
||||||
@ -276,7 +231,8 @@ export default function Compute({
|
|||||||
}, [selectedAlgorithmAsset, accountId])
|
}, [selectedAlgorithmAsset, accountId])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!asset) return
|
if (!asset?.accessDetails || isUnsupportedPricing) return
|
||||||
|
|
||||||
getAlgorithmsForAsset(asset, newCancelToken()).then((algorithmsAssets) => {
|
getAlgorithmsForAsset(asset, newCancelToken()).then((algorithmsAssets) => {
|
||||||
setDdoAlgorithmList(algorithmsAssets)
|
setDdoAlgorithmList(algorithmsAssets)
|
||||||
getAlgorithmAssetSelectionList(asset, algorithmsAssets).then(
|
getAlgorithmAssetSelectionList(asset, algorithmsAssets).then(
|
||||||
@ -285,7 +241,7 @@ export default function Compute({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}, [asset])
|
}, [asset, isUnsupportedPricing])
|
||||||
|
|
||||||
// Output errors in toast UI
|
// Output errors in toast UI
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -323,13 +279,7 @@ export default function Compute({
|
|||||||
selectedAlgorithmAsset.accessDetails.baseToken?.symbol,
|
selectedAlgorithmAsset.accessDetails.baseToken?.symbol,
|
||||||
selectedAlgorithmAsset.accessDetails.datatoken?.symbol,
|
selectedAlgorithmAsset.accessDetails.datatoken?.symbol,
|
||||||
selectedAlgorithmAsset.metadata.type
|
selectedAlgorithmAsset.metadata.type
|
||||||
)[
|
)[selectedAlgorithmAsset.accessDetails?.type === 'fixed' ? 2 : 3]
|
||||||
selectedAlgorithmAsset.accessDetails?.type === 'fixed'
|
|
||||||
? 2
|
|
||||||
: selectedAlgorithmAsset.accessDetails?.type === 'dynamic'
|
|
||||||
? 1
|
|
||||||
: 3
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const algorithmOrderTx = await handleComputeOrder(
|
const algorithmOrderTx = await handleComputeOrder(
|
||||||
@ -348,13 +298,7 @@ export default function Compute({
|
|||||||
asset.accessDetails.baseToken?.symbol,
|
asset.accessDetails.baseToken?.symbol,
|
||||||
asset.accessDetails.datatoken?.symbol,
|
asset.accessDetails.datatoken?.symbol,
|
||||||
asset.metadata.type
|
asset.metadata.type
|
||||||
)[
|
)[asset.accessDetails?.type === 'fixed' ? 2 : 3]
|
||||||
asset.accessDetails?.type === 'fixed'
|
|
||||||
? 2
|
|
||||||
: asset.accessDetails?.type === 'dynamic'
|
|
||||||
? 1
|
|
||||||
: 3
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
const datasetOrderTx = await handleComputeOrder(
|
const datasetOrderTx = await handleComputeOrder(
|
||||||
web3,
|
web3,
|
||||||
@ -406,17 +350,37 @@ export default function Compute({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.info}>
|
<div
|
||||||
|
className={`${styles.info} ${
|
||||||
|
isUnsupportedPricing ? styles.warning : null
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<FileIcon file={file} isLoading={fileIsLoading} small />
|
<FileIcon file={file} isLoading={fileIsLoading} small />
|
||||||
<Price accessDetails={asset?.accessDetails} conversion />
|
{isUnsupportedPricing ? (
|
||||||
</div>
|
|
||||||
|
|
||||||
{asset.metadata.type === 'algorithm' ? (
|
|
||||||
<>
|
|
||||||
<Alert
|
<Alert
|
||||||
text="This algorithm has been set to private by the publisher and can't be downloaded. You can run it against any allowed data sets though!"
|
text={`No pricing schema available for this asset.`}
|
||||||
state="info"
|
state="info"
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<Price
|
||||||
|
accessDetails={asset?.accessDetails}
|
||||||
|
orderPriceAndFees={datasetOrderPriceAndFees}
|
||||||
|
conversion
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isUnsupportedPricing ? null : asset.metadata.type === 'algorithm' ? (
|
||||||
|
<>
|
||||||
|
{asset.services[0].type === 'compute' && (
|
||||||
|
<Alert
|
||||||
|
text={
|
||||||
|
"This algorithm has been set to private by the publisher and can't be downloaded. You can run it against any allowed data sets though!"
|
||||||
|
}
|
||||||
|
state="info"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<AlgorithmDatasetsListForCompute
|
<AlgorithmDatasetsListForCompute
|
||||||
algorithmDid={asset.id}
|
algorithmDid={asset.id}
|
||||||
asset={asset}
|
asset={asset}
|
||||||
@ -442,7 +406,6 @@ export default function Compute({
|
|||||||
hasPreviousOrder={validOrderTx !== undefined}
|
hasPreviousOrder={validOrderTx !== undefined}
|
||||||
hasDatatoken={hasDatatoken}
|
hasDatatoken={hasDatatoken}
|
||||||
dtBalance={dtBalance}
|
dtBalance={dtBalance}
|
||||||
datasetLowPoolLiquidity={!isConsumablePrice}
|
|
||||||
assetType={asset?.metadata.type}
|
assetType={asset?.metadata.type}
|
||||||
assetTimeout={secondsToString(asset?.services[0].timeout)}
|
assetTimeout={secondsToString(asset?.services[0].timeout)}
|
||||||
hasPreviousOrderSelectedComputeAsset={
|
hasPreviousOrderSelectedComputeAsset={
|
||||||
@ -480,13 +443,13 @@ export default function Compute({
|
|||||||
)}
|
)}
|
||||||
</footer>
|
</footer>
|
||||||
{accountId && asset?.accessDetails?.datatoken && (
|
{accountId && asset?.accessDetails?.datatoken && (
|
||||||
<AssetActionHistoryTable title="Your Compute Jobs">
|
<ComputeHistory title="Your Compute Jobs">
|
||||||
<ComputeJobs
|
<ComputeJobs
|
||||||
minimal
|
minimal
|
||||||
assetChainIds={[asset?.chainId]}
|
assetChainIds={[asset?.chainId]}
|
||||||
refetchJobs={refetchJobs}
|
refetchJobs={refetchJobs}
|
||||||
/>
|
/>
|
||||||
</AssetActionHistoryTable>
|
</ComputeHistory>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
.consume {
|
.consume {
|
||||||
display: flex;
|
width: auto;
|
||||||
flex-wrap: wrap;
|
margin-bottom: calc(var(--spacer) / 2);
|
||||||
|
margin-top: -1rem;
|
||||||
|
margin-left: -2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
padding: 0 calc(var(--spacer) / 2) 0 calc(var(--spacer) * 1.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.filewrapper {
|
.filewrapper {
|
||||||
|
@ -9,16 +9,13 @@ import AlgorithmDatasetsListForCompute from './Compute/AlgorithmDatasetsListForC
|
|||||||
import styles from './Download.module.css'
|
import styles from './Download.module.css'
|
||||||
import { FileInfo, LoggerInstance, ZERO_ADDRESS } from '@oceanprotocol/lib'
|
import { FileInfo, LoggerInstance, ZERO_ADDRESS } from '@oceanprotocol/lib'
|
||||||
import { order } from '@utils/order'
|
import { order } from '@utils/order'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { buyDtFromPool } from '@utils/pool'
|
|
||||||
import { downloadFile } from '@utils/provider'
|
import { downloadFile } from '@utils/provider'
|
||||||
import { getOrderFeedback } from '@utils/feedback'
|
import { getOrderFeedback } from '@utils/feedback'
|
||||||
import { getOrderPriceAndFees } from '@utils/accessDetailsAndPricing'
|
import { getOrderPriceAndFees } from '@utils/accessDetailsAndPricing'
|
||||||
import { OrderPriceAndFees } from 'src/@types/Price'
|
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
import { useMarketMetadata } from '@context/MarketMetadata'
|
||||||
|
import Alert from '@shared/atoms/Alert'
|
||||||
|
|
||||||
export default function Download({
|
export default function Download({
|
||||||
asset,
|
asset,
|
||||||
@ -38,7 +35,6 @@ export default function Download({
|
|||||||
const { accountId, web3 } = useWeb3()
|
const { accountId, web3 } = useWeb3()
|
||||||
const { getOpcFeeForToken } = useMarketMetadata()
|
const { getOpcFeeForToken } = useMarketMetadata()
|
||||||
const { isInPurgatory, isAssetNetwork } = useAsset()
|
const { isInPurgatory, isAssetNetwork } = useAsset()
|
||||||
const { poolData } = usePool()
|
|
||||||
const isMounted = useIsMounted()
|
const isMounted = useIsMounted()
|
||||||
|
|
||||||
const [isDisabled, setIsDisabled] = useState(true)
|
const [isDisabled, setIsDisabled] = useState(true)
|
||||||
@ -50,63 +46,50 @@ export default function Download({
|
|||||||
const [orderPriceAndFees, setOrderPriceAndFees] =
|
const [orderPriceAndFees, setOrderPriceAndFees] =
|
||||||
useState<OrderPriceAndFees>()
|
useState<OrderPriceAndFees>()
|
||||||
|
|
||||||
useEffect(() => {
|
const isUnsupportedPricing = asset?.accessDetails?.type === 'NOT_SUPPORTED'
|
||||||
if (!asset?.accessDetails) return
|
|
||||||
|
|
||||||
asset?.accessDetails?.isOwned && setIsOwned(asset?.accessDetails?.isOwned)
|
useEffect(() => {
|
||||||
asset?.accessDetails?.validOrderTx &&
|
if (!asset?.accessDetails || isUnsupportedPricing) return
|
||||||
|
|
||||||
|
asset.accessDetails.isOwned && setIsOwned(asset?.accessDetails?.isOwned)
|
||||||
|
asset.accessDetails.validOrderTx &&
|
||||||
setValidOrderTx(asset?.accessDetails?.validOrderTx)
|
setValidOrderTx(asset?.accessDetails?.validOrderTx)
|
||||||
|
|
||||||
// get full price and fees
|
// get full price and fees
|
||||||
async function init() {
|
async function init() {
|
||||||
if (
|
if (
|
||||||
asset?.accessDetails?.addressOrId === ZERO_ADDRESS ||
|
asset.accessDetails.addressOrId === ZERO_ADDRESS ||
|
||||||
asset?.accessDetails?.type === 'free' ||
|
asset.accessDetails.type === 'free' ||
|
||||||
(!poolData && asset?.accessDetails?.type === 'dynamic') ||
|
|
||||||
isLoading
|
isLoading
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
!orderPriceAndFees && setIsLoading(true)
|
const _orderPriceAndFees = await getOrderPriceAndFees(asset, ZERO_ADDRESS)
|
||||||
setStatusText('Refreshing price')
|
|
||||||
// this is needed just for pool
|
|
||||||
const paramsForPool: CalcInGivenOutParams = {
|
|
||||||
tokenInLiquidity: poolData?.baseTokenLiquidity,
|
|
||||||
tokenOutLiquidity: poolData?.datatokenLiquidity,
|
|
||||||
tokenOutAmount: '1',
|
|
||||||
opcFee: getOpcFeeForToken(
|
|
||||||
asset?.accessDetails?.baseToken.address,
|
|
||||||
asset?.chainId
|
|
||||||
),
|
|
||||||
lpSwapFee: poolData?.liquidityProviderSwapFee,
|
|
||||||
publishMarketSwapFee: asset?.accessDetails?.publisherMarketOrderFee,
|
|
||||||
consumeMarketSwapFee: '0'
|
|
||||||
}
|
|
||||||
const _orderPriceAndFees = await getOrderPriceAndFees(
|
|
||||||
asset,
|
|
||||||
ZERO_ADDRESS,
|
|
||||||
paramsForPool
|
|
||||||
)
|
|
||||||
|
|
||||||
setOrderPriceAndFees(_orderPriceAndFees)
|
setOrderPriceAndFees(_orderPriceAndFees)
|
||||||
!orderPriceAndFees && setIsLoading(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init()
|
init()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* we listen to the assets' changes to get the most updated price
|
* we listen to the assets' changes to get the most updated price
|
||||||
* based on the asset and the poolData's information.
|
* based on the asset and the poolData's information.
|
||||||
* Not adding isLoading and getOpcFeeForToken because we set these here. It is a compromise
|
* Not adding isLoading and getOpcFeeForToken because we set these here. It is a compromise
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [asset, accountId, poolData, getOpcFeeForToken])
|
}, [asset, accountId, getOpcFeeForToken, isUnsupportedPricing])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHasDatatoken(Number(dtBalance) >= 1)
|
setHasDatatoken(Number(dtBalance) >= 1)
|
||||||
}, [dtBalance])
|
}, [dtBalance])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isMounted || !accountId || !asset?.accessDetails) return
|
if (
|
||||||
|
!isMounted ||
|
||||||
|
!accountId ||
|
||||||
|
!asset?.accessDetails ||
|
||||||
|
isUnsupportedPricing
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* disabled in these cases:
|
* disabled in these cases:
|
||||||
@ -128,7 +111,8 @@ export default function Download({
|
|||||||
isAssetNetwork,
|
isAssetNetwork,
|
||||||
hasDatatoken,
|
hasDatatoken,
|
||||||
accountId,
|
accountId,
|
||||||
isOwned
|
isOwned,
|
||||||
|
isUnsupportedPricing
|
||||||
])
|
])
|
||||||
|
|
||||||
async function handleOrderOrDownload() {
|
async function handleOrderOrDownload() {
|
||||||
@ -138,30 +122,18 @@ export default function Download({
|
|||||||
if (isOwned) {
|
if (isOwned) {
|
||||||
setStatusText(
|
setStatusText(
|
||||||
getOrderFeedback(
|
getOrderFeedback(
|
||||||
asset.accessDetails?.baseToken?.symbol,
|
asset.accessDetails.baseToken?.symbol,
|
||||||
asset.accessDetails?.datatoken?.symbol
|
asset.accessDetails.datatoken?.symbol
|
||||||
)[3]
|
)[3]
|
||||||
)
|
)
|
||||||
|
|
||||||
await downloadFile(web3, asset, accountId, validOrderTx)
|
await downloadFile(web3, asset, accountId, validOrderTx)
|
||||||
} else {
|
} else {
|
||||||
if (!hasDatatoken && asset.accessDetails.type === 'dynamic') {
|
|
||||||
setStatusText(
|
|
||||||
getOrderFeedback(
|
|
||||||
asset.accessDetails.baseToken?.symbol,
|
|
||||||
asset.accessDetails.datatoken?.symbol
|
|
||||||
)[0]
|
|
||||||
)
|
|
||||||
const tx = await buyDtFromPool(asset.accessDetails, accountId, web3)
|
|
||||||
if (!tx) {
|
|
||||||
throw new Error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setStatusText(
|
setStatusText(
|
||||||
getOrderFeedback(
|
getOrderFeedback(
|
||||||
asset.accessDetails.baseToken?.symbol,
|
asset.accessDetails.baseToken?.symbol,
|
||||||
asset.accessDetails.datatoken?.symbol
|
asset.accessDetails.datatoken?.symbol
|
||||||
)[asset.accessDetails?.type === 'fixed' ? 2 : 1]
|
)[asset.accessDetails.type === 'fixed' ? 2 : 1]
|
||||||
)
|
)
|
||||||
const orderTx = await order(web3, asset, orderPriceAndFees, accountId)
|
const orderTx = await order(web3, asset, orderPriceAndFees, accountId)
|
||||||
if (!orderTx) {
|
if (!orderTx) {
|
||||||
@ -188,7 +160,6 @@ export default function Download({
|
|||||||
hasDatatoken={hasDatatoken}
|
hasDatatoken={hasDatatoken}
|
||||||
dtSymbol={asset?.datatokens[0]?.symbol}
|
dtSymbol={asset?.datatokens[0]?.symbol}
|
||||||
dtBalance={dtBalance}
|
dtBalance={dtBalance}
|
||||||
datasetLowPoolLiquidity={!asset.accessDetails?.isPurchasable}
|
|
||||||
onClick={handleOrderOrDownload}
|
onClick={handleOrderOrDownload}
|
||||||
assetTimeout={secondsToString(asset.services[0].timeout)}
|
assetTimeout={secondsToString(asset.services[0].timeout)}
|
||||||
assetType={asset?.metadata?.type}
|
assetType={asset?.metadata?.type}
|
||||||
@ -201,21 +172,37 @@ export default function Download({
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const AssetAction = ({ asset }: { asset: AssetExtended }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{isUnsupportedPricing ? (
|
||||||
|
<Alert
|
||||||
|
className={styles.fieldWarning}
|
||||||
|
state="info"
|
||||||
|
text={`No pricing schema available for this asset.`}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Price
|
||||||
|
accessDetails={asset.accessDetails}
|
||||||
|
orderPriceAndFees={orderPriceAndFees}
|
||||||
|
conversion
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
{!isInPurgatory && <PurchaseButton />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.consume}>
|
<aside className={styles.consume}>
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
<div className={styles.filewrapper}>
|
<div className={styles.filewrapper}>
|
||||||
<FileIcon file={file} isLoading={fileIsLoading} />
|
<FileIcon file={file} isLoading={fileIsLoading} small />
|
||||||
</div>
|
|
||||||
<div className={styles.pricewrapper}>
|
|
||||||
<Price
|
|
||||||
accessDetails={asset.accessDetails}
|
|
||||||
orderPriceAndFees={orderPriceAndFees}
|
|
||||||
conversion
|
|
||||||
size="large"
|
|
||||||
/>
|
|
||||||
{!isInPurgatory && <PurchaseButton />}
|
|
||||||
</div>
|
</div>
|
||||||
|
<AssetAction asset={asset} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{asset?.metadata?.type === 'algorithm' && (
|
{asset?.metadata?.type === 'algorithm' && (
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: var(--spacer);
|
|
||||||
padding-bottom: calc(var(--spacer) / 2);
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
margin-left: -2rem;
|
|
||||||
margin-right: -2rem;
|
|
||||||
padding-left: var(--spacer);
|
|
||||||
padding-right: var(--spacer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 40rem) {
|
|
||||||
.header {
|
|
||||||
margin-top: -1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.headerTitle {
|
|
||||||
font-size: var(--font-size-large);
|
|
||||||
margin: 0;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: -3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back {
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import React, { ReactElement } from 'react'
|
|
||||||
import styles from './Header.module.css'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
|
|
||||||
export default function Header({
|
|
||||||
title,
|
|
||||||
backAction
|
|
||||||
}: {
|
|
||||||
title: string
|
|
||||||
backAction: () => void
|
|
||||||
}): ReactElement {
|
|
||||||
return (
|
|
||||||
<header className={styles.header}>
|
|
||||||
<Button
|
|
||||||
className={styles.back}
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
onClick={backAction}
|
|
||||||
>
|
|
||||||
← Back
|
|
||||||
</Button>
|
|
||||||
<h3 className={styles.headerTitle}>{title}</h3>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
.actions {
|
|
||||||
margin-left: -2rem;
|
|
||||||
margin-right: -2rem;
|
|
||||||
padding-left: var(--spacer);
|
|
||||||
padding-right: var(--spacer);
|
|
||||||
padding-top: calc(var(--spacer) / 1.5);
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.success {
|
|
||||||
margin-top: calc(var(--spacer) / 2);
|
|
||||||
margin-bottom: calc(var(--spacer) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions button {
|
|
||||||
margin-left: calc(var(--spacer) / 4);
|
|
||||||
margin-right: calc(var(--spacer) / 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions button svg {
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
import React, { ReactElement, useState } from 'react'
|
|
||||||
import Loader from '@shared/atoms/Loader'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import styles from './index.module.css'
|
|
||||||
import ExplorerLink from '@shared/ExplorerLink'
|
|
||||||
import SuccessConfetti from '@shared/SuccessConfetti'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import TokenApproval from '@shared/TokenApproval'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
|
|
||||||
export default function Actions({
|
|
||||||
isLoading,
|
|
||||||
loaderMessage,
|
|
||||||
successMessage,
|
|
||||||
slippage,
|
|
||||||
txId,
|
|
||||||
actionName,
|
|
||||||
amount,
|
|
||||||
action,
|
|
||||||
isDisabled,
|
|
||||||
tokenAddress,
|
|
||||||
tokenSymbol,
|
|
||||||
setSubmitting
|
|
||||||
}: {
|
|
||||||
isLoading: boolean
|
|
||||||
loaderMessage: string
|
|
||||||
successMessage: string
|
|
||||||
slippage?: string
|
|
||||||
txId: string
|
|
||||||
actionName: string
|
|
||||||
amount?: string
|
|
||||||
action: () => void
|
|
||||||
isDisabled?: boolean
|
|
||||||
tokenAddress: string
|
|
||||||
tokenSymbol: string
|
|
||||||
setSubmitting?: (isSubmitting: boolean) => void
|
|
||||||
}): ReactElement {
|
|
||||||
const { networkId } = useWeb3()
|
|
||||||
const [isTokenApproved, setIsTokenApproved] = useState(false)
|
|
||||||
|
|
||||||
const actionButton = (
|
|
||||||
<Button
|
|
||||||
style="primary"
|
|
||||||
size="small"
|
|
||||||
onClick={() => action()}
|
|
||||||
disabled={isDisabled}
|
|
||||||
>
|
|
||||||
{actionName}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
|
|
||||||
const applySlippage = (amount: string) => {
|
|
||||||
if (!amount) return '0'
|
|
||||||
const newAmount = new Decimal(amount)
|
|
||||||
.mul(
|
|
||||||
new Decimal(1)
|
|
||||||
.plus(new Decimal(slippage).div(new Decimal(100)))
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
.toString()
|
|
||||||
return newAmount
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={styles.actions}>
|
|
||||||
{isLoading ? (
|
|
||||||
<Loader
|
|
||||||
message={
|
|
||||||
isTokenApproved || actionName === 'Remove'
|
|
||||||
? loaderMessage
|
|
||||||
: `Approving ${tokenSymbol}...`
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : actionName === 'Supply' || actionName === 'Swap' ? (
|
|
||||||
<TokenApproval
|
|
||||||
actionButton={actionButton}
|
|
||||||
amount={slippage ? applySlippage(amount) : amount}
|
|
||||||
setIsTokenApproved={setIsTokenApproved}
|
|
||||||
tokenAddress={tokenAddress}
|
|
||||||
tokenSymbol={tokenSymbol}
|
|
||||||
disabled={isDisabled}
|
|
||||||
setSubmitting={setSubmitting}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
actionButton
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{txId && (
|
|
||||||
<SuccessConfetti
|
|
||||||
className={styles.success}
|
|
||||||
success={successMessage}
|
|
||||||
action={
|
|
||||||
<ExplorerLink networkId={networkId} path={`/tx/${txId}`}>
|
|
||||||
View transaction
|
|
||||||
</ExplorerLink>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
.type {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 5px var(--spacer);
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button,
|
|
||||||
.button:hover,
|
|
||||||
.button:focus,
|
|
||||||
.button:active {
|
|
||||||
display: inline-block;
|
|
||||||
color: var(--color-secondary);
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
padding: calc(var(--spacer) / 16) calc(var(--spacer) / 4) !important;
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button.active {
|
|
||||||
color: var(--font-color-text);
|
|
||||||
border-color: var(--border-color);
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import React, {
|
|
||||||
ChangeEvent,
|
|
||||||
Dispatch,
|
|
||||||
ReactElement,
|
|
||||||
SetStateAction
|
|
||||||
} from 'react'
|
|
||||||
import styles from './Nav.module.css'
|
|
||||||
import { graphTypes, GraphType } from './_constants'
|
|
||||||
|
|
||||||
export default function Nav({
|
|
||||||
graphType,
|
|
||||||
setGraphType
|
|
||||||
}: {
|
|
||||||
graphType: GraphType
|
|
||||||
setGraphType: Dispatch<SetStateAction<GraphType>>
|
|
||||||
}): ReactElement {
|
|
||||||
function handleGraphTypeSwitch(e: ChangeEvent<HTMLButtonElement>) {
|
|
||||||
e.preventDefault()
|
|
||||||
setGraphType(e.currentTarget.textContent.toLowerCase() as GraphType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<nav className={styles.type}>
|
|
||||||
{graphTypes.map((type: GraphType) => (
|
|
||||||
<Button
|
|
||||||
key={type}
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
onClick={handleGraphTypeSwitch}
|
|
||||||
className={`${styles.button} ${
|
|
||||||
graphType === type.toLowerCase() ? styles.active : null
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{type}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
</nav>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
import {
|
|
||||||
Chart as ChartJS,
|
|
||||||
LinearScale,
|
|
||||||
CategoryScale,
|
|
||||||
PointElement,
|
|
||||||
Tooltip,
|
|
||||||
BarElement,
|
|
||||||
LineElement,
|
|
||||||
LineController,
|
|
||||||
BarController,
|
|
||||||
ChartDataset,
|
|
||||||
TooltipOptions,
|
|
||||||
defaults
|
|
||||||
} from 'chart.js'
|
|
||||||
|
|
||||||
export declare type GraphType = 'tvl' | 'price' | 'volume'
|
|
||||||
|
|
||||||
export const graphTypes = ['TVL', 'Price', 'Volume']
|
|
||||||
|
|
||||||
// Chart.js global defaults
|
|
||||||
ChartJS.register(
|
|
||||||
LineElement,
|
|
||||||
BarElement,
|
|
||||||
PointElement,
|
|
||||||
LinearScale,
|
|
||||||
CategoryScale,
|
|
||||||
Tooltip,
|
|
||||||
LineController,
|
|
||||||
BarController
|
|
||||||
)
|
|
||||||
|
|
||||||
defaults.font.family = `'Sharp Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif`
|
|
||||||
defaults.animation = { easing: 'easeInOutQuart', duration: 1000 }
|
|
||||||
|
|
||||||
export const lineStyle: Partial<ChartDataset> = {
|
|
||||||
fill: false,
|
|
||||||
borderWidth: 2,
|
|
||||||
pointBorderWidth: 1,
|
|
||||||
pointRadius: 2,
|
|
||||||
pointHoverRadius: 4,
|
|
||||||
pointHoverBorderWidth: 0,
|
|
||||||
pointHitRadius: 2,
|
|
||||||
pointHoverBackgroundColor: '#ff4092'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const tooltipOptions: Partial<TooltipOptions> = {
|
|
||||||
intersect: false,
|
|
||||||
displayColors: false,
|
|
||||||
padding: 10,
|
|
||||||
cornerRadius: 3,
|
|
||||||
borderWidth: 1,
|
|
||||||
caretSize: 7,
|
|
||||||
bodyFont: {
|
|
||||||
size: 13,
|
|
||||||
weight: 'bold',
|
|
||||||
lineHeight: 1,
|
|
||||||
style: 'normal',
|
|
||||||
family: defaults.font.family
|
|
||||||
},
|
|
||||||
titleFont: {
|
|
||||||
size: 10,
|
|
||||||
weight: 'normal',
|
|
||||||
lineHeight: 1,
|
|
||||||
style: 'normal',
|
|
||||||
family: defaults.font.family
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
import { formatPrice } from '@shared/Price/PriceUnit'
|
|
||||||
import { ChartOptions, TooltipItem } from 'chart.js'
|
|
||||||
import { tooltipOptions } from './_constants'
|
|
||||||
|
|
||||||
export function getOptions(
|
|
||||||
locale: string,
|
|
||||||
isDarkMode: boolean,
|
|
||||||
symbol: string
|
|
||||||
): ChartOptions {
|
|
||||||
return {
|
|
||||||
layout: {
|
|
||||||
padding: {
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
top: 0,
|
|
||||||
bottom: 20
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
tooltip: {
|
|
||||||
...tooltipOptions,
|
|
||||||
backgroundColor: isDarkMode ? `#141414` : `#fff`,
|
|
||||||
titleColor: isDarkMode ? `#e2e2e2` : `#303030`,
|
|
||||||
bodyColor: isDarkMode ? `#fff` : `#141414`,
|
|
||||||
borderColor: isDarkMode ? `#41474e` : `#e2e2e2`,
|
|
||||||
callbacks: {
|
|
||||||
label: (tooltipItem: TooltipItem<any>) =>
|
|
||||||
`${tooltipItem.formattedValue} ${symbol}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hover: { intersect: false },
|
|
||||||
scales: {
|
|
||||||
y: { display: false, beginAtZero: true },
|
|
||||||
x: { display: false, offset: true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
.graphWrap {
|
|
||||||
composes: container from '../Section/index.module.css';
|
|
||||||
|
|
||||||
padding: 0;
|
|
||||||
grid-column: full;
|
|
||||||
min-height: 120px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-bottom: calc(var(--spacer) / 2);
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.graphWrap canvas {
|
|
||||||
position: relative;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
|
||||||
import { ChartData, ChartOptions } from 'chart.js'
|
|
||||||
import { Bar, Line } from 'react-chartjs-2'
|
|
||||||
import Loader from '@shared/atoms/Loader'
|
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
|
||||||
import useDarkMode from 'use-dark-mode'
|
|
||||||
import { darkModeConfig } from '../../../../../../app.config'
|
|
||||||
import { LoggerInstance } from '@oceanprotocol/lib'
|
|
||||||
import styles from './index.module.css'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { lineStyle, GraphType } from './_constants'
|
|
||||||
import Nav from './Nav'
|
|
||||||
import { getOptions } from './_utils'
|
|
||||||
import { usePrices } from '@context/Prices'
|
|
||||||
import { MAX_DECIMALS } from '@utils/constants'
|
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
|
|
||||||
export default function Graph(): ReactElement {
|
|
||||||
const { locale, currency } = useUserPreferences()
|
|
||||||
const { prices } = usePrices()
|
|
||||||
const { poolSnapshots } = usePool()
|
|
||||||
const darkMode = useDarkMode(false, darkModeConfig)
|
|
||||||
|
|
||||||
const [options, setOptions] = useState<ChartOptions<any>>()
|
|
||||||
const [graphType, setGraphType] = useState<GraphType>('tvl')
|
|
||||||
const [graphData, setGraphData] = useState<ChartData<any>>()
|
|
||||||
|
|
||||||
//
|
|
||||||
// 0 Get Graph options
|
|
||||||
//
|
|
||||||
useEffect(() => {
|
|
||||||
if (!poolSnapshots) return
|
|
||||||
|
|
||||||
LoggerInstance.log('[pool graph] Fired getOptions().')
|
|
||||||
const symbol =
|
|
||||||
graphType === 'tvl' ? currency : poolSnapshots[0]?.baseToken?.symbol
|
|
||||||
const options = getOptions(locale, darkMode.value, symbol)
|
|
||||||
setOptions(options)
|
|
||||||
}, [locale, darkMode.value, graphType, currency, poolSnapshots])
|
|
||||||
|
|
||||||
//
|
|
||||||
// 1 Data manipulation
|
|
||||||
//
|
|
||||||
useEffect(() => {
|
|
||||||
if (!poolSnapshots) return
|
|
||||||
|
|
||||||
const timestamps = poolSnapshots.map((item) => {
|
|
||||||
const date = new Date(item.date * 1000)
|
|
||||||
return `${date.toLocaleDateString(locale)}`
|
|
||||||
})
|
|
||||||
|
|
||||||
const tvlHistory = poolSnapshots.map((item) => {
|
|
||||||
const conversionSpotPrice = prices[currency.toLowerCase()]
|
|
||||||
|
|
||||||
const tvl = new Decimal(item.baseTokenLiquidity)
|
|
||||||
.mul(conversionSpotPrice) // convert to user currency
|
|
||||||
.toString()
|
|
||||||
return tvl
|
|
||||||
})
|
|
||||||
|
|
||||||
const priceHistory = poolSnapshots.map((item) => item.spotPrice)
|
|
||||||
const volumeHistory = poolSnapshots.map((item) => {
|
|
||||||
const volume = new Decimal(item.swapVolume)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
return volume
|
|
||||||
})
|
|
||||||
|
|
||||||
let data
|
|
||||||
switch (graphType) {
|
|
||||||
case 'price':
|
|
||||||
data = priceHistory
|
|
||||||
break
|
|
||||||
case 'volume':
|
|
||||||
data = volumeHistory
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
data = tvlHistory
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
const newGraphData = {
|
|
||||||
labels: timestamps,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
...lineStyle,
|
|
||||||
data,
|
|
||||||
borderColor: `#8b98a9`,
|
|
||||||
backgroundColor: darkMode.value ? '#201f1f' : '#f7f7f7'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
setGraphData(newGraphData)
|
|
||||||
LoggerInstance.log('[pool graph] New graph data created:', newGraphData)
|
|
||||||
}, [poolSnapshots, graphType, currency, prices, locale, darkMode.value])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.graphWrap}>
|
|
||||||
{!graphData ? (
|
|
||||||
<Loader />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{graphType === 'volume' ? (
|
|
||||||
<Bar width={416} height={120} data={graphData} options={options} />
|
|
||||||
) : (
|
|
||||||
<Line width={416} height={120} data={graphData} options={options} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Nav graphType={graphType} setGraphType={setGraphType} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
import { PoolInfo, PoolInfoUser } from '@context/Pool/_types'
|
|
||||||
import { calcMaxExactOut, Pool } from '@oceanprotocol/lib'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { PoolData_poolData as PoolData } from 'src/@types/subgraph/PoolData'
|
|
||||||
|
|
||||||
export async function getMax(
|
|
||||||
poolInstance: Pool,
|
|
||||||
poolInfo: PoolInfo,
|
|
||||||
poolInfoUser: PoolInfoUser,
|
|
||||||
poolData: PoolData
|
|
||||||
) {
|
|
||||||
const maxBaseTokensRemovable = calcMaxExactOut(poolData.baseTokenLiquidity)
|
|
||||||
|
|
||||||
const maxPoolSharesRemovable = await poolInstance.calcPoolInGivenSingleOut(
|
|
||||||
poolData.id,
|
|
||||||
poolInfo.baseTokenAddress,
|
|
||||||
maxBaseTokensRemovable.toString()
|
|
||||||
)
|
|
||||||
|
|
||||||
const userPoolShares = poolInfoUser.poolShares
|
|
||||||
|
|
||||||
const maxPoolSharesRemovableDecimal = new Decimal(maxPoolSharesRemovable)
|
|
||||||
const userPoolSharesDecimal = new Decimal(userPoolShares)
|
|
||||||
|
|
||||||
const maxPoolSharesRemovableByUser =
|
|
||||||
maxPoolSharesRemovableDecimal.greaterThan(userPoolSharesDecimal)
|
|
||||||
? userPoolSharesDecimal
|
|
||||||
: maxPoolSharesRemovableDecimal
|
|
||||||
|
|
||||||
// small hack because if the values are equal the decimal.js result is 99.(9)
|
|
||||||
const maxPercent = maxPoolSharesRemovableByUser.equals(userPoolSharesDecimal)
|
|
||||||
? new Decimal(100)
|
|
||||||
: new Decimal(100)
|
|
||||||
.mul(maxPoolSharesRemovableByUser)
|
|
||||||
.div(userPoolSharesDecimal)
|
|
||||||
|
|
||||||
return maxPercent.toDecimalPlaces(0, Decimal.ROUND_DOWN).toString()
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
.removeInput {
|
|
||||||
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);
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range {
|
|
||||||
margin-top: calc(var(--spacer) / 2);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range h3 {
|
|
||||||
margin-bottom: calc(var(--spacer) / 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.range input {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
margin-left: -2rem;
|
|
||||||
margin-right: -2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.maximum {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 2.5rem;
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
min-width: 5rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.maximum:hover {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle {
|
|
||||||
margin-top: calc(var(--spacer) / 2);
|
|
||||||
margin-bottom: 0;
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
margin-bottom: -2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.output {
|
|
||||||
composes: container from '../Section/index.module.css';
|
|
||||||
display: grid;
|
|
||||||
gap: var(--spacer);
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.output p {
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
margin-bottom: calc(var(--spacer) / 8);
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
}
|
|
||||||
|
|
||||||
.output [class*='token'] > figure {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.slippage {
|
|
||||||
composes: slippage from '../../Trade/Slippage.module.css';
|
|
||||||
}
|
|
@ -1,235 +0,0 @@
|
|||||||
import React, {
|
|
||||||
ReactElement,
|
|
||||||
useState,
|
|
||||||
ChangeEvent,
|
|
||||||
useEffect,
|
|
||||||
useRef
|
|
||||||
} from 'react'
|
|
||||||
import styles from './index.module.css'
|
|
||||||
import Header from '../Actions/Header'
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import Actions from '../Actions'
|
|
||||||
import { LoggerInstance, Pool } from '@oceanprotocol/lib'
|
|
||||||
import Token from '../../../../@shared/Token'
|
|
||||||
import FormHelp from '@shared/FormInput/Help'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import debounce from 'lodash.debounce'
|
|
||||||
import UserLiquidity from '../../UserLiquidity'
|
|
||||||
import InputElement from '@shared/FormInput/InputElement'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import content from '../../../../../../content/price.json'
|
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
import { getMax } from './_utils'
|
|
||||||
|
|
||||||
const slippagePresets = ['5', '10', '15', '25', '50']
|
|
||||||
|
|
||||||
export default function Remove({
|
|
||||||
setShowRemove
|
|
||||||
}: {
|
|
||||||
setShowRemove: (show: boolean) => void
|
|
||||||
}): ReactElement {
|
|
||||||
const { accountId, web3 } = useWeb3()
|
|
||||||
const { isAssetNetwork } = useAsset()
|
|
||||||
const { poolData, poolInfo, poolInfoUser, fetchAllData } = usePool()
|
|
||||||
|
|
||||||
const [amountPercent, setAmountPercent] = useState('0')
|
|
||||||
const [amountMaxPercent, setAmountMaxPercent] = useState('100')
|
|
||||||
const [amountPoolShares, setAmountPoolShares] = useState('0')
|
|
||||||
const [amountOcean, setAmountOcean] = useState('0')
|
|
||||||
const [isLoading, setIsLoading] = useState<boolean>()
|
|
||||||
const [txId, setTxId] = useState<string>()
|
|
||||||
const [slippage, setSlippage] = useState(slippagePresets[0])
|
|
||||||
const [minOceanAmount, setMinOceanAmount] = useState<string>('0')
|
|
||||||
const [poolInstance, setPoolInstance] = useState<Pool>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!web3) return
|
|
||||||
setPoolInstance(new Pool(web3))
|
|
||||||
}, [web3])
|
|
||||||
|
|
||||||
async function handleRemoveLiquidity() {
|
|
||||||
setIsLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await poolInstance.exitswapPoolAmountIn(
|
|
||||||
accountId,
|
|
||||||
poolData?.id,
|
|
||||||
amountPoolShares,
|
|
||||||
minOceanAmount
|
|
||||||
)
|
|
||||||
setTxId(result?.transactionHash)
|
|
||||||
// fetch new data
|
|
||||||
fetchAllData()
|
|
||||||
} catch (error) {
|
|
||||||
LoggerInstance.error(error.message)
|
|
||||||
toast.error(error.message)
|
|
||||||
} finally {
|
|
||||||
// reset slider after transaction
|
|
||||||
setAmountPercent('0')
|
|
||||||
setAmountOcean('0')
|
|
||||||
setMinOceanAmount('0')
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Calculate and set maximum shares user is able to remove
|
|
||||||
//
|
|
||||||
useEffect(() => {
|
|
||||||
if (!accountId || !poolInfoUser || !poolInfo || !poolInstance) return
|
|
||||||
|
|
||||||
getMax(poolInstance, poolInfo, poolInfoUser, poolData).then((max) =>
|
|
||||||
setAmountMaxPercent(max)
|
|
||||||
)
|
|
||||||
}, [accountId, poolInfoUser, poolInfo, poolInstance, poolData])
|
|
||||||
|
|
||||||
const getValues = useRef(
|
|
||||||
debounce(async (poolInstance, id, poolInfo, newAmountPoolShares) => {
|
|
||||||
if (newAmountPoolShares === '0') {
|
|
||||||
setAmountOcean('0')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const newAmountOcean = await poolInstance.calcSingleOutGivenPoolIn(
|
|
||||||
id,
|
|
||||||
poolInfo.baseTokenAddress,
|
|
||||||
newAmountPoolShares,
|
|
||||||
18,
|
|
||||||
poolInfo.baseTokenDecimals
|
|
||||||
)
|
|
||||||
setAmountOcean(newAmountOcean)
|
|
||||||
}, 150)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Check and set outputs when amountPoolShares changes
|
|
||||||
useEffect(() => {
|
|
||||||
if (!accountId || !poolInfo || !poolData?.id || !poolInstance) return
|
|
||||||
getValues.current(poolInstance, poolData?.id, poolInfo, amountPoolShares)
|
|
||||||
}, [amountPoolShares, accountId, poolInfo, poolData?.id, poolInstance])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!amountOcean || amountPercent === '0') {
|
|
||||||
setMinOceanAmount('0')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const minOceanAmount = new Decimal(amountOcean)
|
|
||||||
.mul(new Decimal(100).minus(new Decimal(slippage)))
|
|
||||||
.dividedBy(100)
|
|
||||||
.toString()
|
|
||||||
|
|
||||||
setMinOceanAmount(minOceanAmount.slice(0, 18))
|
|
||||||
}, [slippage, amountOcean, amountPercent])
|
|
||||||
|
|
||||||
// Set amountPoolShares based on set slider value
|
|
||||||
function handleAmountPercentChange(e: ChangeEvent<HTMLInputElement>) {
|
|
||||||
setAmountPercent(e.target.value)
|
|
||||||
if (!poolInfoUser?.poolShares) return
|
|
||||||
|
|
||||||
const amountPoolShares = new Decimal(e.target.value)
|
|
||||||
.dividedBy(100)
|
|
||||||
.mul(new Decimal(poolInfoUser.poolShares))
|
|
||||||
.toString()
|
|
||||||
setAmountPoolShares(amountPoolShares)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMaxButton(e: ChangeEvent<HTMLInputElement>) {
|
|
||||||
e.preventDefault()
|
|
||||||
setAmountPercent(amountMaxPercent)
|
|
||||||
const amountPoolShares = new Decimal(amountMaxPercent)
|
|
||||||
.dividedBy(100)
|
|
||||||
.mul(new Decimal(poolInfoUser?.poolShares))
|
|
||||||
.toString()
|
|
||||||
|
|
||||||
setAmountPoolShares(amountPoolShares)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSlippageChange(e: ChangeEvent<HTMLSelectElement>) {
|
|
||||||
setSlippage(e.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.remove}>
|
|
||||||
<Header
|
|
||||||
title={content.pool.remove.title}
|
|
||||||
backAction={() => {
|
|
||||||
setShowRemove(false)
|
|
||||||
fetchAllData()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<form className={styles.removeInput}>
|
|
||||||
<UserLiquidity amount={poolInfoUser?.poolShares} symbol="pool shares" />
|
|
||||||
<div className={styles.range}>
|
|
||||||
<h3>{amountPercent}%</h3>
|
|
||||||
<div className={styles.slider}>
|
|
||||||
<input
|
|
||||||
type="range"
|
|
||||||
min="0"
|
|
||||||
max={amountMaxPercent}
|
|
||||||
disabled={!isAssetNetwork || isLoading}
|
|
||||||
value={amountPercent}
|
|
||||||
onChange={handleAmountPercentChange}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
className={styles.maximum}
|
|
||||||
disabled={!isAssetNetwork || isLoading}
|
|
||||||
onClick={handleMaxButton}
|
|
||||||
>
|
|
||||||
{`${amountMaxPercent}% max`}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FormHelp>{content.pool.remove.simple}</FormHelp>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div className={styles.output}>
|
|
||||||
<div>
|
|
||||||
<p>{content.pool.remove.output.titleOutExpected}</p>
|
|
||||||
<Token
|
|
||||||
symbol={poolInfo?.baseTokenSymbol}
|
|
||||||
balance={amountOcean}
|
|
||||||
noIcon
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>{content.pool.remove.output.titleOutMinimum}</p>
|
|
||||||
<Token symbol={poolInfo?.baseTokenSymbol} balance={minOceanAmount} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={styles.slippage}>
|
|
||||||
<strong>Slippage Tolerance</strong>
|
|
||||||
<InputElement
|
|
||||||
name="slippage"
|
|
||||||
type="select"
|
|
||||||
size="mini"
|
|
||||||
postfix="%"
|
|
||||||
sortOptions={false}
|
|
||||||
options={slippagePresets}
|
|
||||||
disabled={!isAssetNetwork || isLoading}
|
|
||||||
value={slippage}
|
|
||||||
onChange={handleSlippageChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Actions
|
|
||||||
isLoading={isLoading}
|
|
||||||
loaderMessage="Removing Liquidity..."
|
|
||||||
actionName={content.pool.remove.action}
|
|
||||||
action={handleRemoveLiquidity}
|
|
||||||
successMessage="Successfully removed liquidity."
|
|
||||||
isDisabled={
|
|
||||||
!isAssetNetwork ||
|
|
||||||
amountPercent === '0' ||
|
|
||||||
amountOcean === '0' ||
|
|
||||||
poolInfo?.totalPoolTokens === '0'
|
|
||||||
}
|
|
||||||
txId={txId}
|
|
||||||
tokenAddress={poolInfo?.baseTokenAddress}
|
|
||||||
tokenSymbol={poolInfo?.baseTokenSymbol}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
.title {
|
|
||||||
font-size: var(--font-size-base);
|
|
||||||
margin-bottom: calc(var(--spacer) / 3);
|
|
||||||
color: var(--color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.titlePostfix {
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
font-family: var(--font-family-base);
|
|
||||||
font-weight: var(--font-weight-base);
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 0.3rem;
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
import Tooltip from '@shared/atoms/Tooltip'
|
|
||||||
import React from 'react'
|
|
||||||
import styles from './Title.module.css'
|
|
||||||
|
|
||||||
export default function Title({
|
|
||||||
title,
|
|
||||||
tooltip,
|
|
||||||
titlePostfix,
|
|
||||||
titlePostfixTitle
|
|
||||||
}: {
|
|
||||||
title: string
|
|
||||||
tooltip?: string
|
|
||||||
titlePostfix?: string
|
|
||||||
titlePostfixTitle?: string
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<h3 className={styles.title}>
|
|
||||||
{title} {tooltip && <Tooltip content={tooltip} />}{' '}
|
|
||||||
{titlePostfix && (
|
|
||||||
<span className={styles.titlePostfix} title={titlePostfixTitle}>
|
|
||||||
{titlePostfix}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</h3>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
.container {
|
|
||||||
margin-left: calc(-1 * var(--spacer) / 1.5);
|
|
||||||
margin-right: calc(-1 * var(--spacer) / 1.5);
|
|
||||||
padding: calc(var(--spacer) / 1.5) calc(var(--spacer) / 1.5)
|
|
||||||
calc(var(--spacer) / 2) calc(var(--spacer) / 1.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 40rem) {
|
|
||||||
.container {
|
|
||||||
padding-left: var(--spacer);
|
|
||||||
padding-right: var(--spacer);
|
|
||||||
margin-left: calc(-1 * var(--spacer));
|
|
||||||
margin-right: calc(-1 * var(--spacer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
composes: container;
|
|
||||||
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section.highlight {
|
|
||||||
background: var(--background-highlight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.section:first-child {
|
|
||||||
padding-top: 0;
|
|
||||||
border-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
display: grid;
|
|
||||||
gap: calc(var(--spacer) / 2);
|
|
||||||
grid-template-columns:
|
|
||||||
[full-start] minmax(13rem, 1fr) [break] minmax(7rem, 1fr)
|
|
||||||
[full-end];
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
import React, { ReactElement, ReactNode } from 'react'
|
|
||||||
import styles from './index.module.css'
|
|
||||||
import Title from './Title'
|
|
||||||
|
|
||||||
export default function PoolSection({
|
|
||||||
title,
|
|
||||||
tooltip,
|
|
||||||
titlePostfix,
|
|
||||||
titlePostfixTitle,
|
|
||||||
children,
|
|
||||||
highlight,
|
|
||||||
className
|
|
||||||
}: {
|
|
||||||
title?: string
|
|
||||||
children: ReactNode
|
|
||||||
tooltip?: string
|
|
||||||
titlePostfix?: string
|
|
||||||
titlePostfixTitle?: string
|
|
||||||
highlight?: boolean
|
|
||||||
className?: string
|
|
||||||
}): ReactElement {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`${styles.section} ${highlight ? styles.highlight : ''} ${
|
|
||||||
className || ''
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{title && (
|
|
||||||
<Title
|
|
||||||
title={title}
|
|
||||||
tooltip={tooltip}
|
|
||||||
titlePostfix={titlePostfix}
|
|
||||||
titlePostfixTitle={titlePostfixTitle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div className={styles.grid}>{children}</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
.update {
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
color: var(--color-secondary);
|
|
||||||
text-align: center;
|
|
||||||
padding-top: calc(var(--spacer) / 2);
|
|
||||||
padding-bottom: calc(var(--spacer) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.update:before {
|
|
||||||
content: '';
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
border: 1px solid var(--brand-alert-green);
|
|
||||||
margin-right: 0.2rem;
|
|
||||||
margin-top: -0.1rem;
|
|
||||||
vertical-align: middle;
|
|
||||||
animation: pulse 2s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse {
|
|
||||||
0% {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background: var(--brand-alert-green);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
import { usePool } from '@context/Pool'
|
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import React from 'react'
|
|
||||||
import styles from './Update.module.css'
|
|
||||||
|
|
||||||
export default function Update() {
|
|
||||||
const { debug } = useUserPreferences()
|
|
||||||
const { fetchAllData, refreshInterval } = usePool()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<p className={styles.update}>
|
|
||||||
Fetching every {refreshInterval / 1000} sec.{' '}
|
|
||||||
{debug && (
|
|
||||||
<Button
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
onClick={() => fetchAllData()}
|
|
||||||
className={styles.button}
|
|
||||||
>
|
|
||||||
Refresh Data
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
.dataToken {
|
|
||||||
font-size: var(--font-size-large);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataToken > div {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTokenLinks {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
margin-top: calc(var(--spacer) / 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTokenLinks a {
|
|
||||||
margin-left: calc(var(--spacer) / 3);
|
|
||||||
margin-right: calc(var(--spacer) / 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fees {
|
|
||||||
border-top: none;
|
|
||||||
padding-top: 0;
|
|
||||||
margin-top: -0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fees > div {
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(5rem, 1fr));
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fees figure {
|
|
||||||
display: none;
|
|
||||||
}
|
|
@ -1,139 +0,0 @@
|
|||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
import Tooltip from '@shared/atoms/Tooltip'
|
|
||||||
import ExplorerLink from '@shared/ExplorerLink'
|
|
||||||
import PriceUnit from '@shared/Price/PriceUnit'
|
|
||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
import Graph from '../Graph'
|
|
||||||
import PoolSection from '../Section'
|
|
||||||
import Token from '../../../../@shared/Token'
|
|
||||||
import content from '../../../../../../content/price.json'
|
|
||||||
import styles from './index.module.css'
|
|
||||||
import Update from './Update'
|
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
|
||||||
import { OpcFeesQuery_opc as OpcFeesData } from '../../../../../@types/subgraph/OpcFeesQuery'
|
|
||||||
import { getOpcFees } from '@utils/subgraph'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
|
|
||||||
export default function PoolSections() {
|
|
||||||
const { asset } = useAsset()
|
|
||||||
const { poolData, poolInfo, poolInfoUser, poolInfoOwner } = usePool()
|
|
||||||
const { getOpcFeeForToken } = useMarketMetadata()
|
|
||||||
const { chainId } = useWeb3()
|
|
||||||
const [oceanCommunitySwapFee, setOceanCommunitySwapFee] = useState<string>('')
|
|
||||||
useEffect(() => {
|
|
||||||
getOpcFees(chainId || 1).then((response: OpcFeesData) => {
|
|
||||||
setOceanCommunitySwapFee(
|
|
||||||
response?.swapOceanFee
|
|
||||||
? new Decimal(response.swapOceanFee).mul(100).toString()
|
|
||||||
: '0'
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}, [chainId])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<PoolSection className={styles.dataToken}>
|
|
||||||
<PriceUnit price="1" symbol={poolInfo?.datatokenSymbol} size="large" />{' '}
|
|
||||||
={' '}
|
|
||||||
<PriceUnit
|
|
||||||
price={`${poolData?.spotPrice}`}
|
|
||||||
symbol={poolInfo?.baseTokenSymbol}
|
|
||||||
size="large"
|
|
||||||
/>
|
|
||||||
<Tooltip content={content.pool.tooltips.price} />
|
|
||||||
<div className={styles.dataTokenLinks}>
|
|
||||||
<ExplorerLink
|
|
||||||
networkId={asset?.chainId}
|
|
||||||
path={`address/${asset?.accessDetails?.addressOrId}`}
|
|
||||||
>
|
|
||||||
Pool
|
|
||||||
</ExplorerLink>
|
|
||||||
<ExplorerLink
|
|
||||||
networkId={asset?.chainId}
|
|
||||||
path={
|
|
||||||
asset?.chainId === 2021000 || asset?.chainId === 1287
|
|
||||||
? `tokens/${asset?.services[0].datatokenAddress}`
|
|
||||||
: `token/${asset?.services[0].datatokenAddress}`
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Datatoken
|
|
||||||
</ExplorerLink>
|
|
||||||
</div>
|
|
||||||
</PoolSection>
|
|
||||||
|
|
||||||
<PoolSection
|
|
||||||
title="Your liquidity"
|
|
||||||
titlePostfix={
|
|
||||||
poolInfoUser?.poolSharePercentage &&
|
|
||||||
`${poolInfoUser?.poolSharePercentage}% of pool`
|
|
||||||
}
|
|
||||||
tooltip={content.pool.tooltips.liquidity.replace(
|
|
||||||
'SWAPFEE',
|
|
||||||
poolInfo?.liquidityProviderSwapFee
|
|
||||||
)}
|
|
||||||
highlight
|
|
||||||
>
|
|
||||||
<Token
|
|
||||||
symbol={poolInfo?.baseTokenSymbol}
|
|
||||||
balance={poolInfoUser?.liquidity}
|
|
||||||
conversion
|
|
||||||
/>
|
|
||||||
</PoolSection>
|
|
||||||
|
|
||||||
<PoolSection
|
|
||||||
title="Owner liquidity"
|
|
||||||
titlePostfix={`${poolInfoOwner?.poolSharePercentage}% of pool`}
|
|
||||||
>
|
|
||||||
<Token
|
|
||||||
symbol={poolInfo?.baseTokenSymbol}
|
|
||||||
balance={poolInfoOwner?.liquidity}
|
|
||||||
conversion
|
|
||||||
/>
|
|
||||||
</PoolSection>
|
|
||||||
|
|
||||||
<PoolSection title="Total Value Locked">
|
|
||||||
<Token
|
|
||||||
symbol={poolInfo?.baseTokenSymbol}
|
|
||||||
balance={poolData?.baseTokenLiquidity.toString()}
|
|
||||||
conversion
|
|
||||||
/>
|
|
||||||
</PoolSection>
|
|
||||||
|
|
||||||
<PoolSection
|
|
||||||
title="Pool Statistics"
|
|
||||||
titlePostfix={
|
|
||||||
poolInfo?.weightDt &&
|
|
||||||
`${poolInfo?.weightBaseToken}/${poolInfo?.weightDt}`
|
|
||||||
}
|
|
||||||
titlePostfixTitle={`Weight of ${poolInfo?.weightBaseToken}% ${poolInfo?.baseTokenSymbol} & ${poolInfo?.weightDt}% ${poolInfo?.datatokenSymbol}`}
|
|
||||||
>
|
|
||||||
<Graph />
|
|
||||||
</PoolSection>
|
|
||||||
|
|
||||||
<PoolSection className={styles.fees}>
|
|
||||||
<Token
|
|
||||||
symbol="% swap fee"
|
|
||||||
balance={poolInfo?.liquidityProviderSwapFee}
|
|
||||||
noIcon
|
|
||||||
size="mini"
|
|
||||||
/>
|
|
||||||
<Token
|
|
||||||
symbol="% market fee"
|
|
||||||
balance={poolInfo?.publishMarketSwapFee}
|
|
||||||
noIcon
|
|
||||||
size="mini"
|
|
||||||
/>
|
|
||||||
<Token
|
|
||||||
symbol="% OPC fee"
|
|
||||||
balance={oceanCommunitySwapFee}
|
|
||||||
noIcon
|
|
||||||
size="mini"
|
|
||||||
/>
|
|
||||||
</PoolSection>
|
|
||||||
|
|
||||||
<Update />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
import React, { ReactElement, useState } from 'react'
|
|
||||||
import stylesActions from './Actions/index.module.css'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import Remove from './Remove'
|
|
||||||
import AssetActionHistoryTable from '../AssetActionHistoryTable'
|
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import PoolTransactions from '@shared/PoolTransactions'
|
|
||||||
|
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
import PoolSections from './Sections'
|
|
||||||
|
|
||||||
export default function Pool(): ReactElement {
|
|
||||||
const { asset, isAssetNetwork } = useAsset()
|
|
||||||
const { hasUserAddedLiquidity } = usePool()
|
|
||||||
const { accountId } = useWeb3()
|
|
||||||
|
|
||||||
const [showRemove, setShowRemove] = useState(false)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{showRemove ? (
|
|
||||||
<Remove setShowRemove={setShowRemove} />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<PoolSections />
|
|
||||||
|
|
||||||
{hasUserAddedLiquidity && (
|
|
||||||
<div className={stylesActions.actions}>
|
|
||||||
<Button
|
|
||||||
style="primary"
|
|
||||||
size="small"
|
|
||||||
onClick={() => setShowRemove(true)}
|
|
||||||
disabled={!isAssetNetwork}
|
|
||||||
>
|
|
||||||
Remove Liquidity
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{accountId && (
|
|
||||||
<AssetActionHistoryTable title="Your Pool Transactions">
|
|
||||||
<PoolTransactions
|
|
||||||
accountId={accountId}
|
|
||||||
poolAddress={asset?.accessDetails?.addressOrId}
|
|
||||||
poolChainId={asset?.chainId}
|
|
||||||
minimal
|
|
||||||
/>
|
|
||||||
</AssetActionHistoryTable>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
.alertWrap {
|
|
||||||
min-height: 320px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
@ -1,240 +0,0 @@
|
|||||||
import React, { ReactElement, useState } from 'react'
|
|
||||||
import {
|
|
||||||
AmountsInMaxFee,
|
|
||||||
AmountsOutMaxFee,
|
|
||||||
LoggerInstance,
|
|
||||||
Pool,
|
|
||||||
TokenInOutMarket
|
|
||||||
} from '@oceanprotocol/lib'
|
|
||||||
import * as Yup from 'yup'
|
|
||||||
import { Formik } from 'formik'
|
|
||||||
import Actions from '../Pool/Actions'
|
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import Swap from './Swap'
|
|
||||||
import Alert from '@shared/atoms/Alert'
|
|
||||||
import styles from './FormTrade.module.css'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import { FormTradeData } from './_types'
|
|
||||||
import { initialValues } from './_constants'
|
|
||||||
import content from '../../../../../content/price.json'
|
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
|
||||||
|
|
||||||
export default function FormTrade({
|
|
||||||
asset,
|
|
||||||
balance
|
|
||||||
}: {
|
|
||||||
asset: AssetExtended
|
|
||||||
balance: PoolBalance
|
|
||||||
}): ReactElement {
|
|
||||||
const { web3, accountId } = useWeb3()
|
|
||||||
const { isAssetNetwork } = useAsset()
|
|
||||||
const { debug } = useUserPreferences()
|
|
||||||
const { appConfig } = useMarketMetadata()
|
|
||||||
const { poolInfo, fetchAllData } = usePool()
|
|
||||||
|
|
||||||
const [txId, setTxId] = useState<string>()
|
|
||||||
const [coinFrom, setCoinFrom] = useState<string>('OCEAN')
|
|
||||||
const [maximumBaseToken, setMaximumBaseToken] = useState('0')
|
|
||||||
const [maximumDt, setMaximumDt] = useState('0')
|
|
||||||
|
|
||||||
const validationSchema: Yup.SchemaOf<FormTradeData> = Yup.object()
|
|
||||||
.shape({
|
|
||||||
baseToken: Yup.number()
|
|
||||||
.max(
|
|
||||||
Number(maximumBaseToken),
|
|
||||||
(param) => `Must be less or equal to ${param.max}`
|
|
||||||
)
|
|
||||||
.min(0.001, (param) => `Must be more or equal to ${param.min}`)
|
|
||||||
.required('Required')
|
|
||||||
.nullable(),
|
|
||||||
datatoken: Yup.number()
|
|
||||||
.max(
|
|
||||||
Number(maximumDt),
|
|
||||||
(param) => `Must be less or equal to ${param.max}`
|
|
||||||
)
|
|
||||||
.min(0.00001, (param) => `Must be more or equal to ${param.min}`)
|
|
||||||
.required('Required')
|
|
||||||
.nullable(),
|
|
||||||
type: Yup.string(),
|
|
||||||
slippage: Yup.string()
|
|
||||||
})
|
|
||||||
.defined()
|
|
||||||
|
|
||||||
async function handleTrade(values: FormTradeData) {
|
|
||||||
if (!web3 || !asset || !poolInfo || !values || !appConfig) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
const poolInstance = new Pool(web3)
|
|
||||||
let tx
|
|
||||||
if (values.output === 'exactIn') {
|
|
||||||
const tokenInOutMarket: TokenInOutMarket = {
|
|
||||||
tokenIn:
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.datatokenAddress
|
|
||||||
: poolInfo.baseTokenAddress,
|
|
||||||
tokenOut:
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.baseTokenAddress
|
|
||||||
: poolInfo.datatokenAddress,
|
|
||||||
marketFeeAddress: appConfig.marketFeeAddress,
|
|
||||||
tokenInDecimals:
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.datatokenDecimals
|
|
||||||
: poolInfo.baseTokenDecimals,
|
|
||||||
tokenOutDecimals:
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.baseTokenDecimals
|
|
||||||
: poolInfo.datatokenDecimals
|
|
||||||
}
|
|
||||||
|
|
||||||
const amountsInOutMaxFee: AmountsInMaxFee = {
|
|
||||||
tokenAmountIn:
|
|
||||||
values.type === 'sell' ? values.datatoken : values.baseToken,
|
|
||||||
minAmountOut: new Decimal(
|
|
||||||
values.type === 'sell' ? values.baseToken : values.datatoken
|
|
||||||
)
|
|
||||||
.mul(
|
|
||||||
new Decimal(1)
|
|
||||||
.minus(new Decimal(values.slippage).div(new Decimal(100)))
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
.toString(),
|
|
||||||
swapMarketFee: appConfig.consumeMarketPoolSwapFee
|
|
||||||
}
|
|
||||||
tx = await poolInstance.swapExactAmountIn(
|
|
||||||
accountId,
|
|
||||||
asset.accessDetails.addressOrId,
|
|
||||||
tokenInOutMarket,
|
|
||||||
amountsInOutMaxFee
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!tx) {
|
|
||||||
throw new Error('Failed to swap tokens!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (values.output === 'exactOut') {
|
|
||||||
const tokenOutMarket: TokenInOutMarket = {
|
|
||||||
tokenIn:
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.datatokenAddress
|
|
||||||
: poolInfo.baseTokenAddress,
|
|
||||||
tokenOut:
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.baseTokenAddress
|
|
||||||
: poolInfo.datatokenAddress,
|
|
||||||
marketFeeAddress: appConfig.marketFeeAddress,
|
|
||||||
tokenInDecimals:
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.datatokenDecimals
|
|
||||||
: poolInfo.baseTokenDecimals,
|
|
||||||
tokenOutDecimals:
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.baseTokenDecimals
|
|
||||||
: poolInfo.datatokenDecimals
|
|
||||||
}
|
|
||||||
|
|
||||||
const amountsOutMaxFee: AmountsOutMaxFee = {
|
|
||||||
maxAmountIn: new Decimal(
|
|
||||||
values.type === 'sell' ? values.datatoken : values.baseToken
|
|
||||||
)
|
|
||||||
.mul(
|
|
||||||
new Decimal(1)
|
|
||||||
.plus(new Decimal(values.slippage).div(new Decimal(100)))
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
.toString(),
|
|
||||||
tokenAmountOut:
|
|
||||||
values.type === 'sell' ? values.baseToken : values.datatoken,
|
|
||||||
swapMarketFee: appConfig.consumeMarketPoolSwapFee
|
|
||||||
}
|
|
||||||
tx = await poolInstance.swapExactAmountOut(
|
|
||||||
accountId,
|
|
||||||
asset.accessDetails.addressOrId,
|
|
||||||
tokenOutMarket,
|
|
||||||
amountsOutMaxFee
|
|
||||||
)
|
|
||||||
if (!tx) {
|
|
||||||
throw new Error('Failed to swap tokens!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await fetchAllData()
|
|
||||||
setTxId(tx?.transactionHash)
|
|
||||||
} catch (error) {
|
|
||||||
LoggerInstance.error(error.message)
|
|
||||||
toast.error(error.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Formik
|
|
||||||
initialValues={initialValues}
|
|
||||||
validationSchema={validationSchema}
|
|
||||||
onSubmit={async (values, { setFieldValue, setSubmitting, resetForm }) => {
|
|
||||||
await handleTrade(values)
|
|
||||||
await setFieldValue('baseToken', '')
|
|
||||||
await setFieldValue('datatoken', '')
|
|
||||||
resetForm()
|
|
||||||
setSubmitting(false)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ isSubmitting, setSubmitting, submitForm, values, isValid }) => (
|
|
||||||
<>
|
|
||||||
<Swap
|
|
||||||
asset={asset}
|
|
||||||
balance={balance}
|
|
||||||
setCoin={setCoinFrom}
|
|
||||||
setMaximumBaseToken={setMaximumBaseToken}
|
|
||||||
setMaximumDt={setMaximumDt}
|
|
||||||
isLoading={isSubmitting}
|
|
||||||
/>
|
|
||||||
<Actions
|
|
||||||
isDisabled={
|
|
||||||
!isValid ||
|
|
||||||
!isAssetNetwork ||
|
|
||||||
values.datatoken === undefined ||
|
|
||||||
values.baseToken === undefined
|
|
||||||
}
|
|
||||||
isLoading={isSubmitting}
|
|
||||||
loaderMessage="Swapping tokens..."
|
|
||||||
successMessage="Successfully swapped tokens."
|
|
||||||
actionName={content.trade.action}
|
|
||||||
slippage={values.slippage}
|
|
||||||
amount={
|
|
||||||
values.type === 'sell'
|
|
||||||
? values.datatoken
|
|
||||||
? `${values.datatoken}`
|
|
||||||
: undefined
|
|
||||||
: values.baseToken
|
|
||||||
? `${values.baseToken}`
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
action={submitForm}
|
|
||||||
txId={txId}
|
|
||||||
tokenAddress={
|
|
||||||
values.type === 'buy'
|
|
||||||
? poolInfo.baseTokenAddress
|
|
||||||
: poolInfo.datatokenAddress
|
|
||||||
}
|
|
||||||
tokenSymbol={
|
|
||||||
values.type === 'buy'
|
|
||||||
? poolInfo.baseTokenSymbol
|
|
||||||
: poolInfo.datatokenSymbol
|
|
||||||
}
|
|
||||||
setSubmitting={setSubmitting}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{debug && (
|
|
||||||
<pre>
|
|
||||||
<code>{JSON.stringify(values, null, 2)}</code>
|
|
||||||
</pre>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
.output {
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
padding: var(--spacer);
|
|
||||||
padding-bottom: calc(var(--spacer) / 1.5);
|
|
||||||
display: grid;
|
|
||||||
gap: var(--spacer);
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
margin-left: -2rem;
|
|
||||||
margin-right: -2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.output p {
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
margin-bottom: calc(var(--spacer) / 8);
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
}
|
|
||||||
|
|
||||||
.output [class*='token'] {
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.output [class*='token'] > figure {
|
|
||||||
display: none;
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
import { FormikContextType, useFormikContext } from 'formik'
|
|
||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import Token from '../../../@shared/Token'
|
|
||||||
import styles from './Output.module.css'
|
|
||||||
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { FormTradeData } from './_types'
|
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
|
|
||||||
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
|
||||||
|
|
||||||
export default function Output({
|
|
||||||
poolAddress,
|
|
||||||
lpSwapFee
|
|
||||||
}: {
|
|
||||||
poolAddress: string
|
|
||||||
lpSwapFee: string
|
|
||||||
}): ReactElement {
|
|
||||||
const { isAssetNetwork } = useAsset()
|
|
||||||
const { poolInfo } = usePool()
|
|
||||||
const [outputWithSlippage, setOutputWithSlippage] = useState<string>('0')
|
|
||||||
// Connect with form
|
|
||||||
const { values }: FormikContextType<FormTradeData> = useFormikContext()
|
|
||||||
|
|
||||||
// Get output values
|
|
||||||
useEffect(() => {
|
|
||||||
if (!poolAddress || !isAssetNetwork) return
|
|
||||||
|
|
||||||
async function getOutput() {
|
|
||||||
if (!values.baseToken || !values.datatoken || !values.output) return
|
|
||||||
|
|
||||||
const output =
|
|
||||||
values.output === 'exactIn'
|
|
||||||
? new Decimal(
|
|
||||||
values.type === 'sell' ? values.baseToken : values.datatoken
|
|
||||||
)
|
|
||||||
.mul(
|
|
||||||
new Decimal(1)
|
|
||||||
.minus(new Decimal(values.slippage).div(new Decimal(100)))
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
.toString()
|
|
||||||
: new Decimal(
|
|
||||||
values.type === 'sell' ? values.datatoken : values.baseToken
|
|
||||||
)
|
|
||||||
.mul(
|
|
||||||
new Decimal(1)
|
|
||||||
.plus(new Decimal(values.slippage).div(new Decimal(100)))
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
.toString()
|
|
||||||
|
|
||||||
setOutputWithSlippage(output)
|
|
||||||
}
|
|
||||||
getOutput()
|
|
||||||
}, [poolAddress, values, isAssetNetwork])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.output}>
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
{values.output === 'exactIn' ? 'Minimum Received' : 'Maximum Sent'}
|
|
||||||
</p>
|
|
||||||
<Token
|
|
||||||
symbol={
|
|
||||||
values.type === 'buy'
|
|
||||||
? values.output === 'exactIn'
|
|
||||||
? poolInfo.datatokenSymbol
|
|
||||||
: poolInfo.baseTokenSymbol
|
|
||||||
: values.output === 'exactIn'
|
|
||||||
? poolInfo.baseTokenSymbol
|
|
||||||
: poolInfo.datatokenSymbol
|
|
||||||
}
|
|
||||||
balance={outputWithSlippage}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>Swap fee</p>
|
|
||||||
<Token
|
|
||||||
symbol={`${
|
|
||||||
values.type === 'buy'
|
|
||||||
? poolInfo.baseTokenSymbol
|
|
||||||
: poolInfo.datatokenSymbol
|
|
||||||
} ${
|
|
||||||
poolInfo.liquidityProviderSwapFee
|
|
||||||
? `(${poolInfo.liquidityProviderSwapFee}%)`
|
|
||||||
: ''
|
|
||||||
}`}
|
|
||||||
balance={lpSwapFee}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
.priceImpact {
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
margin-left: -2rem;
|
|
||||||
margin-right: -2rem;
|
|
||||||
padding: calc(var(--spacer) / 4) var(--spacer);
|
|
||||||
color: var(--color-secondary);
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: calc(var(--spacer) / 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.priceImpact strong {
|
|
||||||
font-weight: var(--font-weight-base);
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert {
|
|
||||||
color: var(--brand-alert-red);
|
|
||||||
}
|
|
||||||
|
|
||||||
.number {
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import Tooltip from '@shared/atoms/Tooltip'
|
|
||||||
import styles from './PriceImpact.module.css'
|
|
||||||
|
|
||||||
export default function PriceImpact({
|
|
||||||
totalValue,
|
|
||||||
tokenAmount,
|
|
||||||
spotPrice
|
|
||||||
}: {
|
|
||||||
/// how much the user actually pays (doesn't matter witch token it is)
|
|
||||||
totalValue: string
|
|
||||||
/// how many tokens the user trades (doesn't matter witch token it is)
|
|
||||||
tokenAmount: string
|
|
||||||
/// the spot price of the traded token (doesn't matter witch token it is))
|
|
||||||
spotPrice: string
|
|
||||||
}): ReactElement {
|
|
||||||
const [priceImpact, setPriceImpact] = useState<string>('0')
|
|
||||||
|
|
||||||
async function getPriceImpact(
|
|
||||||
totalValue: string,
|
|
||||||
tokenAmount: string,
|
|
||||||
spotPrice: string
|
|
||||||
) {
|
|
||||||
const dtotalValue = new Decimal(totalValue)
|
|
||||||
const dTokenAmount = new Decimal(tokenAmount)
|
|
||||||
const dSpotPrice = new Decimal(spotPrice)
|
|
||||||
let priceImpact = Decimal.abs(
|
|
||||||
dtotalValue.div(dTokenAmount.times(dSpotPrice)).minus(1)
|
|
||||||
).mul(100)
|
|
||||||
if (priceImpact.isNaN()) priceImpact = new Decimal(0)
|
|
||||||
return priceImpact.toDecimalPlaces(2, Decimal.ROUND_DOWN)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!totalValue || !tokenAmount || !spotPrice) {
|
|
||||||
setPriceImpact('0')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
async function init() {
|
|
||||||
const newPriceImpact = await getPriceImpact(
|
|
||||||
totalValue,
|
|
||||||
tokenAmount,
|
|
||||||
spotPrice
|
|
||||||
)
|
|
||||||
setPriceImpact(newPriceImpact.toString())
|
|
||||||
}
|
|
||||||
init()
|
|
||||||
}, [totalValue, tokenAmount, spotPrice])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.priceImpact}>
|
|
||||||
<strong>Price Impact</strong>
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
className={`${styles.number} ${
|
|
||||||
parseInt(priceImpact) > 5 && styles.alert
|
|
||||||
}`}
|
|
||||||
>{`${priceImpact}%`}</span>
|
|
||||||
<Tooltip content="The difference between the market price and estimated price due to trade size." />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
.slippage {
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
margin-left: -2rem;
|
|
||||||
margin-right: -2rem;
|
|
||||||
padding: calc(var(--spacer) / 4) var(--spacer);
|
|
||||||
color: var(--color-secondary);
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: calc(var(--spacer) / 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.slippage strong {
|
|
||||||
font-weight: var(--font-weight-base);
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-family: var(--font-family-base);
|
|
||||||
font-weight: var(--font-weight-base);
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: calc(var(--spacer) / 4);
|
|
||||||
color: var(--color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.slippage select {
|
|
||||||
width: fit-content;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
import { FormikContextType, useFormikContext } from 'formik'
|
|
||||||
import React, { ChangeEvent, ReactElement } from 'react'
|
|
||||||
import InputElement from '@shared/FormInput/InputElement'
|
|
||||||
import Tooltip from '@shared/atoms/Tooltip'
|
|
||||||
import styles from './Slippage.module.css'
|
|
||||||
import { FormTradeData } from './_types'
|
|
||||||
import { slippagePresets } from './_constants'
|
|
||||||
|
|
||||||
export default function Slippage({
|
|
||||||
disabled
|
|
||||||
}: {
|
|
||||||
disabled: boolean
|
|
||||||
}): ReactElement {
|
|
||||||
// Connect with form
|
|
||||||
const { setFieldValue, values }: FormikContextType<FormTradeData> =
|
|
||||||
useFormikContext()
|
|
||||||
|
|
||||||
function handleChange(e: ChangeEvent<HTMLSelectElement>) {
|
|
||||||
setFieldValue('slippage', e.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.slippage}>
|
|
||||||
<strong>Slippage Tolerance</strong>
|
|
||||||
<div>
|
|
||||||
<InputElement
|
|
||||||
name="slippage"
|
|
||||||
type="select"
|
|
||||||
size="mini"
|
|
||||||
postfix="%"
|
|
||||||
sortOptions={false}
|
|
||||||
options={slippagePresets}
|
|
||||||
value={values.slippage}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
<Tooltip content="Your transaction will revert if the price changes unfavorably by more than this percentage." />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
.swap {
|
|
||||||
margin-top: -2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.swapButton,
|
|
||||||
.swapButton:hover,
|
|
||||||
.swapButton:focus,
|
|
||||||
.swapButton:active {
|
|
||||||
padding: 0;
|
|
||||||
display: block;
|
|
||||||
width: calc(100% + 4rem);
|
|
||||||
text-align: center;
|
|
||||||
margin-left: -2rem;
|
|
||||||
margin-right: -2rem;
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
padding: calc(var(--spacer) / 3) 0 calc(var(--spacer) / 6) 0;
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.swapButton svg {
|
|
||||||
display: inline-block;
|
|
||||||
width: var(--font-size-large);
|
|
||||||
height: var(--font-size-large);
|
|
||||||
fill: var(--brand-pink);
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
@ -1,355 +0,0 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
|
||||||
import styles from './Swap.module.css'
|
|
||||||
import TradeInput from './TradeInput'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import Arrow from '@images/arrow.svg'
|
|
||||||
import { FormikContextType, useFormikContext } from 'formik'
|
|
||||||
import Output from './Output'
|
|
||||||
import Slippage from './Slippage'
|
|
||||||
import PriceImpact from './PriceImpact'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import { FormTradeData, TradeItem } from './_types'
|
|
||||||
import {
|
|
||||||
calcMaxExactIn,
|
|
||||||
calcMaxExactOut,
|
|
||||||
LoggerInstance,
|
|
||||||
Pool,
|
|
||||||
PoolPriceAndFees
|
|
||||||
} from '@oceanprotocol/lib'
|
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
import { MAX_DECIMALS } from '@utils/constants'
|
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
|
||||||
|
|
||||||
// Decimal.set({ toExpNeg: -15, precision: 5, rounding: Decimal.ROUND_DOWN })
|
|
||||||
|
|
||||||
export default function Swap({
|
|
||||||
asset,
|
|
||||||
balance,
|
|
||||||
setMaximumDt,
|
|
||||||
setMaximumBaseToken,
|
|
||||||
setCoin,
|
|
||||||
isLoading
|
|
||||||
}: {
|
|
||||||
asset: AssetExtended
|
|
||||||
balance: PoolBalance
|
|
||||||
setMaximumDt: (value: string) => void
|
|
||||||
setMaximumBaseToken: (value: string) => void
|
|
||||||
setCoin: (value: string) => void
|
|
||||||
isLoading: boolean
|
|
||||||
}): ReactElement {
|
|
||||||
const { isAssetNetwork } = useAsset()
|
|
||||||
const { web3 } = useWeb3()
|
|
||||||
const { poolInfo, poolData } = usePool()
|
|
||||||
const { appConfig } = useMarketMetadata()
|
|
||||||
|
|
||||||
const [baseTokenItem, setBaseTokenItem] = useState<TradeItem>({
|
|
||||||
amount: '0',
|
|
||||||
token: poolInfo?.baseTokenSymbol,
|
|
||||||
maxAmount: '0',
|
|
||||||
address: poolInfo?.baseTokenAddress
|
|
||||||
})
|
|
||||||
const [dtItem, setDtItem] = useState<TradeItem>({
|
|
||||||
amount: '0',
|
|
||||||
token: poolInfo?.datatokenSymbol,
|
|
||||||
maxAmount: '0',
|
|
||||||
address: poolInfo?.datatokenAddress
|
|
||||||
})
|
|
||||||
const {
|
|
||||||
setFieldValue,
|
|
||||||
values,
|
|
||||||
setErrors,
|
|
||||||
validateForm
|
|
||||||
}: FormikContextType<FormTradeData> = useFormikContext()
|
|
||||||
|
|
||||||
// Values used for calculation of price impact
|
|
||||||
const [spotPrice, setSpotPrice] = useState<string>()
|
|
||||||
const [totalValue, setTotalValue] = useState<string>()
|
|
||||||
const [tokenAmount, setTokenAmount] = useState<string>()
|
|
||||||
const [lpSwapFee, setLpSwapFee] = useState<string>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!asset || !balance || !values?.type || !web3 || !appConfig || !poolInfo)
|
|
||||||
return
|
|
||||||
const poolInstance = new Pool(web3)
|
|
||||||
|
|
||||||
async function calculateMaximum() {
|
|
||||||
const datatokenLiquidity = await poolInstance.getReserve(
|
|
||||||
poolData.id,
|
|
||||||
poolData.datatoken.address,
|
|
||||||
poolData.datatoken.decimals
|
|
||||||
)
|
|
||||||
const baseTokenLiquidity = await poolInstance.getReserve(
|
|
||||||
poolData.id,
|
|
||||||
poolData.baseToken.address,
|
|
||||||
poolData.baseToken.decimals
|
|
||||||
)
|
|
||||||
if (values.type === 'buy') {
|
|
||||||
const maxBaseTokenFromPool = calcMaxExactIn(baseTokenLiquidity)
|
|
||||||
|
|
||||||
const maxBaseTokens = maxBaseTokenFromPool.greaterThan(
|
|
||||||
new Decimal(balance.baseToken)
|
|
||||||
)
|
|
||||||
? balance.baseToken
|
|
||||||
: maxBaseTokenFromPool.toDecimalPlaces(MAX_DECIMALS).toString()
|
|
||||||
|
|
||||||
const maxDt = await poolInstance.getAmountOutExactIn(
|
|
||||||
asset.accessDetails?.addressOrId,
|
|
||||||
poolInfo.baseTokenAddress,
|
|
||||||
poolInfo.datatokenAddress,
|
|
||||||
maxBaseTokens.toString(),
|
|
||||||
appConfig.consumeMarketPoolSwapFee,
|
|
||||||
poolInfo.baseTokenDecimals,
|
|
||||||
poolInfo.datatokenDecimals
|
|
||||||
)
|
|
||||||
const maximumDt = new Decimal(maxDt.tokenAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
setMaximumDt(maximumDt)
|
|
||||||
setMaximumBaseToken(maxBaseTokens)
|
|
||||||
|
|
||||||
setBaseTokenItem((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
amount: balance.baseToken,
|
|
||||||
maxAmount: maxBaseTokens
|
|
||||||
}))
|
|
||||||
|
|
||||||
setDtItem((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
amount: datatokenLiquidity,
|
|
||||||
maxAmount: maximumDt
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
const maxDtFromPool = calcMaxExactIn(datatokenLiquidity)
|
|
||||||
const maxDatatokens = maxDtFromPool.greaterThan(
|
|
||||||
new Decimal(balance.datatoken)
|
|
||||||
)
|
|
||||||
? balance.datatoken
|
|
||||||
: maxDtFromPool.toDecimalPlaces(MAX_DECIMALS).toString()
|
|
||||||
|
|
||||||
const maxBaseTokens = await poolInstance.getAmountOutExactIn(
|
|
||||||
asset.accessDetails?.addressOrId,
|
|
||||||
poolInfo?.datatokenAddress,
|
|
||||||
poolInfo?.baseTokenAddress,
|
|
||||||
maxDatatokens.toString(),
|
|
||||||
appConfig.consumeMarketPoolSwapFee,
|
|
||||||
poolInfo.datatokenDecimals,
|
|
||||||
poolInfo.baseTokenDecimals
|
|
||||||
)
|
|
||||||
const maximumBasetokens = new Decimal(maxBaseTokens.tokenAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
setMaximumDt(maxDatatokens)
|
|
||||||
setMaximumBaseToken(maximumBasetokens)
|
|
||||||
|
|
||||||
setDtItem((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
amount: balance.datatoken,
|
|
||||||
maxAmount: maxDatatokens
|
|
||||||
}))
|
|
||||||
setBaseTokenItem((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
amount: baseTokenLiquidity,
|
|
||||||
maxAmount: maximumBasetokens
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
calculateMaximum()
|
|
||||||
}, [
|
|
||||||
poolData,
|
|
||||||
balance,
|
|
||||||
values.type,
|
|
||||||
setMaximumDt,
|
|
||||||
setMaximumBaseToken,
|
|
||||||
asset,
|
|
||||||
web3,
|
|
||||||
dtItem.token,
|
|
||||||
dtItem.amount,
|
|
||||||
baseTokenItem.token,
|
|
||||||
baseTokenItem.amount,
|
|
||||||
appConfig,
|
|
||||||
poolInfo
|
|
||||||
])
|
|
||||||
|
|
||||||
const switchTokens = () => {
|
|
||||||
setFieldValue('type', values.type === 'buy' ? 'sell' : 'buy')
|
|
||||||
setCoin(
|
|
||||||
values.type === 'sell'
|
|
||||||
? poolInfo.baseTokenSymbol
|
|
||||||
: poolInfo.datatokenSymbol
|
|
||||||
)
|
|
||||||
// don't reset form because we don't want to reset type
|
|
||||||
setFieldValue('datatoken', 0)
|
|
||||||
setFieldValue('baseToken', 0)
|
|
||||||
setErrors({})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleValueChange = async (name: string, value: number) => {
|
|
||||||
try {
|
|
||||||
let tokenIn = ''
|
|
||||||
let tokenOut = ''
|
|
||||||
const poolInstance = new Pool(web3)
|
|
||||||
let newValue: PoolPriceAndFees
|
|
||||||
|
|
||||||
if (name === 'baseToken') {
|
|
||||||
if (values.type === 'sell') {
|
|
||||||
newValue = await poolInstance.getAmountInExactOut(
|
|
||||||
asset.accessDetails.addressOrId,
|
|
||||||
dtItem.address,
|
|
||||||
baseTokenItem.address,
|
|
||||||
value.toString(),
|
|
||||||
appConfig.consumeMarketPoolSwapFee
|
|
||||||
)
|
|
||||||
|
|
||||||
setFieldValue('output', 'exactOut')
|
|
||||||
|
|
||||||
setTotalValue(
|
|
||||||
new Decimal(newValue.tokenAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
setLpSwapFee(
|
|
||||||
new Decimal(newValue.liquidityProviderSwapFeeAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
setTokenAmount(value.toString())
|
|
||||||
|
|
||||||
tokenIn = poolInfo.datatokenAddress
|
|
||||||
tokenOut = poolInfo.baseTokenAddress
|
|
||||||
} else {
|
|
||||||
newValue = await poolInstance.getAmountOutExactIn(
|
|
||||||
asset.accessDetails.addressOrId,
|
|
||||||
baseTokenItem.address,
|
|
||||||
dtItem.address,
|
|
||||||
value.toString(),
|
|
||||||
appConfig.consumeMarketPoolSwapFee
|
|
||||||
)
|
|
||||||
|
|
||||||
setFieldValue('output', 'exactIn')
|
|
||||||
setTotalValue(value.toString())
|
|
||||||
setTokenAmount(
|
|
||||||
new Decimal(newValue.tokenAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
setLpSwapFee(
|
|
||||||
new Decimal(newValue.liquidityProviderSwapFeeAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
tokenIn = poolInfo.baseTokenAddress
|
|
||||||
tokenOut = poolInfo.datatokenAddress
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (values.type === 'sell') {
|
|
||||||
newValue = await poolInstance.getAmountOutExactIn(
|
|
||||||
asset.accessDetails.addressOrId,
|
|
||||||
dtItem.address,
|
|
||||||
baseTokenItem.address,
|
|
||||||
value.toString(),
|
|
||||||
appConfig.consumeMarketPoolSwapFee
|
|
||||||
)
|
|
||||||
|
|
||||||
setFieldValue('output', 'exactIn')
|
|
||||||
setTotalValue(value.toString())
|
|
||||||
setTokenAmount(
|
|
||||||
new Decimal(newValue.tokenAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
setLpSwapFee(
|
|
||||||
new Decimal(newValue.liquidityProviderSwapFeeAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
tokenIn = poolInfo.datatokenAddress
|
|
||||||
tokenOut = poolInfo.baseTokenAddress
|
|
||||||
} else {
|
|
||||||
newValue = await poolInstance.getAmountInExactOut(
|
|
||||||
asset.accessDetails.addressOrId,
|
|
||||||
baseTokenItem.address,
|
|
||||||
dtItem.address,
|
|
||||||
value.toString(),
|
|
||||||
appConfig.consumeMarketPoolSwapFee
|
|
||||||
)
|
|
||||||
|
|
||||||
setFieldValue('output', 'exactOut')
|
|
||||||
|
|
||||||
setTotalValue(
|
|
||||||
new Decimal(newValue.tokenAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
setTokenAmount(value.toString())
|
|
||||||
setLpSwapFee(
|
|
||||||
new Decimal(newValue.liquidityProviderSwapFeeAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
tokenIn = poolInfo.baseTokenAddress
|
|
||||||
tokenOut = poolInfo.datatokenAddress
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await setFieldValue(
|
|
||||||
name === 'baseToken' ? 'datatoken' : 'baseToken',
|
|
||||||
new Decimal(newValue.tokenAmount)
|
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
|
|
||||||
const spotPrice = await poolInstance.getSpotPrice(
|
|
||||||
asset.accessDetails.addressOrId,
|
|
||||||
tokenIn,
|
|
||||||
tokenOut,
|
|
||||||
appConfig.consumeMarketPoolSwapFee
|
|
||||||
)
|
|
||||||
setSpotPrice(spotPrice)
|
|
||||||
validateForm()
|
|
||||||
} catch (ex) {
|
|
||||||
LoggerInstance.error(ex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.swap}>
|
|
||||||
<TradeInput
|
|
||||||
name={values.type === 'sell' ? 'datatoken' : 'baseToken'}
|
|
||||||
item={values.type === 'sell' ? dtItem : baseTokenItem}
|
|
||||||
disabled={!isAssetNetwork || isLoading}
|
|
||||||
handleValueChange={handleValueChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
className={styles.swapButton}
|
|
||||||
style="text"
|
|
||||||
onClick={switchTokens}
|
|
||||||
disabled={!isAssetNetwork || isLoading}
|
|
||||||
>
|
|
||||||
<Arrow />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<TradeInput
|
|
||||||
name={values.type === 'sell' ? 'baseToken' : 'datatoken'}
|
|
||||||
item={values.type === 'sell' ? baseTokenItem : dtItem}
|
|
||||||
disabled={!isAssetNetwork || isLoading}
|
|
||||||
handleValueChange={handleValueChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Output
|
|
||||||
poolAddress={asset.accessDetails?.addressOrId}
|
|
||||||
lpSwapFee={lpSwapFee}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<PriceImpact
|
|
||||||
totalValue={totalValue}
|
|
||||||
tokenAmount={tokenAmount}
|
|
||||||
spotPrice={spotPrice}
|
|
||||||
/>
|
|
||||||
<Slippage disabled={!isAssetNetwork || isLoading} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
.tradeInput {
|
|
||||||
position: relative;
|
|
||||||
padding: var(--spacer) calc(var(--spacer) * 2);
|
|
||||||
margin-left: -2rem;
|
|
||||||
margin-right: -2rem;
|
|
||||||
background: var(--background-highlight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tradeInput input {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tradeInput div[class*='field'] {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tradeInput div[class*='prefix'] {
|
|
||||||
min-width: 6.5rem;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-family: var(--font-family-heading);
|
|
||||||
font-size: var(--font-size-base);
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonMax {
|
|
||||||
position: absolute;
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
bottom: calc(var(--spacer) / 2);
|
|
||||||
right: calc(var(--spacer) * 2);
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
import React, { ChangeEvent, ReactElement } from 'react'
|
|
||||||
import styles from './TradeInput.module.css'
|
|
||||||
import {
|
|
||||||
Field,
|
|
||||||
FieldInputProps,
|
|
||||||
FormikContextType,
|
|
||||||
useFormikContext,
|
|
||||||
useField
|
|
||||||
} from 'formik'
|
|
||||||
import debounce from 'lodash.debounce'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import Input from '@shared/FormInput'
|
|
||||||
import Error from '@shared/FormInput/Error'
|
|
||||||
import { FormTradeData, TradeItem } from './_types'
|
|
||||||
import UserLiquidity from '../UserLiquidity'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
|
|
||||||
export default function TradeInput({
|
|
||||||
name,
|
|
||||||
item,
|
|
||||||
disabled,
|
|
||||||
handleValueChange
|
|
||||||
}: {
|
|
||||||
name: string
|
|
||||||
item: TradeItem
|
|
||||||
disabled: boolean
|
|
||||||
handleValueChange: (name: string, value: number) => void
|
|
||||||
}): ReactElement {
|
|
||||||
const { accountId } = useWeb3()
|
|
||||||
|
|
||||||
// Connect with form
|
|
||||||
const {
|
|
||||||
handleChange,
|
|
||||||
validateForm,
|
|
||||||
values
|
|
||||||
}: FormikContextType<FormTradeData> = useFormikContext()
|
|
||||||
const [field, meta] = useField(name)
|
|
||||||
const isTopField =
|
|
||||||
(name === 'baseToken' && values.type === 'buy') ||
|
|
||||||
(name === 'datatoken' && values.type === 'sell')
|
|
||||||
const titleAvailable = isTopField ? `Your Balance` : `Pool Balance`
|
|
||||||
const titleMaximum = isTopField ? `Maximum to spend` : `Maximum to receive`
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section className={styles.tradeInput}>
|
|
||||||
<UserLiquidity
|
|
||||||
amount={`${item?.amount}`}
|
|
||||||
amountMax={`${item?.maxAmount}`}
|
|
||||||
symbol={item?.token}
|
|
||||||
titleAvailable={titleAvailable}
|
|
||||||
titleMaximum={titleMaximum}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field name={name}>
|
|
||||||
{({ field, form }: { field: FieldInputProps<number>; form: any }) => (
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
max={`${item?.maxAmount}`}
|
|
||||||
min="0"
|
|
||||||
prefix={item?.token}
|
|
||||||
placeholder="0"
|
|
||||||
field={field}
|
|
||||||
form={form}
|
|
||||||
disabled={!accountId || disabled}
|
|
||||||
additionalComponent={<Error meta={meta} />}
|
|
||||||
value={`${field.value}`}
|
|
||||||
{...field}
|
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
handleChange(e)
|
|
||||||
handleValueChange(name, Number(e.target.value))
|
|
||||||
// debounce needed to avoid validating the wrong (pass) value
|
|
||||||
debounce(() => validateForm(), 100)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
{/* {!isTopField && (
|
|
||||||
<Button
|
|
||||||
className={styles.buttonMax}
|
|
||||||
disabled={disabled}
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
onClick={() => {
|
|
||||||
setFieldValue(name, item?.maxAmount)
|
|
||||||
handleValueChange(name, Number(item?.maxAmount))
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Use Max
|
|
||||||
</Button>
|
|
||||||
)} */}
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import { FormTradeData } from './_types'
|
|
||||||
|
|
||||||
export const initialValues: FormTradeData = {
|
|
||||||
baseToken: undefined,
|
|
||||||
datatoken: undefined,
|
|
||||||
type: 'buy',
|
|
||||||
output: 'exactIn',
|
|
||||||
slippage: '5'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const slippagePresets = ['5', '10', '15', '25', '50']
|
|
||||||
|
|
||||||
// validationSchema lives in components/organisms/AssetActions/Trade/FormTrade.tsx
|
|
@ -1,14 +0,0 @@
|
|||||||
export interface FormTradeData extends PoolBalance {
|
|
||||||
// in reference to datatoken, buy = swap from ocean to dt ( buy dt) , sell = swap from dt to ocean (sell dt)
|
|
||||||
type: 'buy' | 'sell'
|
|
||||||
// based on what the user inputs, if he fill the top input it is 'exactIn'
|
|
||||||
output: 'exactIn' | 'exactOut'
|
|
||||||
slippage: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TradeItem {
|
|
||||||
amount: string
|
|
||||||
token: string
|
|
||||||
maxAmount: string
|
|
||||||
address: string
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
|
||||||
import FormTrade from './FormTrade'
|
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import { isValidNumber } from '@utils/numbers'
|
|
||||||
import Decimal from 'decimal.js'
|
|
||||||
import { Datatoken, LoggerInstance, Pool } from '@oceanprotocol/lib'
|
|
||||||
import { usePool } from '@context/Pool'
|
|
||||||
|
|
||||||
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
|
||||||
|
|
||||||
export default function Trade(): ReactElement {
|
|
||||||
const { accountId, balance, web3 } = useWeb3()
|
|
||||||
const { isAssetNetwork } = useAsset()
|
|
||||||
const [tokenBalance, setTokenBalance] = useState<PoolBalance>()
|
|
||||||
const { asset } = useAsset()
|
|
||||||
const { poolInfo } = usePool()
|
|
||||||
|
|
||||||
// Get datatoken balance, and combine with OCEAN balance from hooks into one object
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
!web3 ||
|
|
||||||
!accountId ||
|
|
||||||
!isAssetNetwork ||
|
|
||||||
!balance?.ocean ||
|
|
||||||
!accountId ||
|
|
||||||
!poolInfo?.datatokenAddress
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
async function getTokenBalance() {
|
|
||||||
const datatokenInstance = new Datatoken(web3)
|
|
||||||
const dtBalance = await datatokenInstance.balance(
|
|
||||||
poolInfo.datatokenAddress,
|
|
||||||
accountId
|
|
||||||
)
|
|
||||||
setTokenBalance({
|
|
||||||
baseToken: new Decimal(balance.ocean).toString(),
|
|
||||||
datatoken: new Decimal(dtBalance).toString()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getTokenBalance()
|
|
||||||
}, [
|
|
||||||
web3,
|
|
||||||
balance.ocean,
|
|
||||||
accountId,
|
|
||||||
poolInfo?.datatokenAddress,
|
|
||||||
isAssetNetwork
|
|
||||||
])
|
|
||||||
|
|
||||||
return <FormTrade asset={asset} balance={tokenBalance} />
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
.userLiquidity > div {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-size: var(--font-size-mini);
|
|
||||||
color: var(--color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.userLiquidity span + div {
|
|
||||||
transform: scale(0.8);
|
|
||||||
transform-origin: right center;
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
import React, { ReactElement } from 'react'
|
|
||||||
import PriceUnit from '@shared/Price/PriceUnit'
|
|
||||||
import styles from './UserLiquidity.module.css'
|
|
||||||
|
|
||||||
function UserLiquidityLine({
|
|
||||||
title,
|
|
||||||
amount,
|
|
||||||
symbol
|
|
||||||
}: {
|
|
||||||
title: string
|
|
||||||
amount: string
|
|
||||||
symbol: string
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<span>{title}</span>
|
|
||||||
<PriceUnit price={amount} symbol={symbol} size="small" />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function UserLiquidity({
|
|
||||||
amount,
|
|
||||||
symbol,
|
|
||||||
amountMax,
|
|
||||||
titleAvailable = 'Balance',
|
|
||||||
titleMaximum = 'Maximum'
|
|
||||||
}: {
|
|
||||||
amount: string
|
|
||||||
symbol: string
|
|
||||||
titleAvailable?: string
|
|
||||||
titleMaximum?: string
|
|
||||||
amountMax?: string
|
|
||||||
}): ReactElement {
|
|
||||||
return (
|
|
||||||
<div className={styles.userLiquidity}>
|
|
||||||
<UserLiquidityLine
|
|
||||||
title={titleAvailable}
|
|
||||||
amount={amount}
|
|
||||||
symbol={symbol}
|
|
||||||
/>
|
|
||||||
{amountMax && (
|
|
||||||
<UserLiquidityLine
|
|
||||||
title={titleMaximum}
|
|
||||||
amount={amountMax}
|
|
||||||
symbol={symbol}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -4,8 +4,6 @@ import Consume from './Download'
|
|||||||
import { FileInfo, LoggerInstance, Datatoken } from '@oceanprotocol/lib'
|
import { FileInfo, LoggerInstance, Datatoken } from '@oceanprotocol/lib'
|
||||||
import Tabs, { TabsItem } from '@shared/atoms/Tabs'
|
import Tabs, { TabsItem } from '@shared/atoms/Tabs'
|
||||||
import { compareAsBN } from '@utils/numbers'
|
import { compareAsBN } from '@utils/numbers'
|
||||||
import Pool from './Pool'
|
|
||||||
import Trade from './Trade'
|
|
||||||
import { useAsset } from '@context/Asset'
|
import { useAsset } from '@context/Asset'
|
||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
import Web3Feedback from '@shared/Web3Feedback'
|
import Web3Feedback from '@shared/Web3Feedback'
|
||||||
@ -16,8 +14,6 @@ import { useIsMounted } from '@hooks/useIsMounted'
|
|||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { useFormikContext } from 'formik'
|
import { useFormikContext } from 'formik'
|
||||||
import { FormPublishData } from 'src/components/Publish/_types'
|
import { FormPublishData } from 'src/components/Publish/_types'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import PoolProvider from '@context/Pool'
|
|
||||||
import AssetStats from './AssetStats'
|
import AssetStats from './AssetStats'
|
||||||
|
|
||||||
export default function AssetActions({
|
export default function AssetActions({
|
||||||
@ -148,18 +144,13 @@ export default function AssetActions({
|
|||||||
|
|
||||||
const tabs: TabsItem[] = [{ title: 'Use', content: UseContent }]
|
const tabs: TabsItem[] = [{ title: 'Use', content: UseContent }]
|
||||||
|
|
||||||
asset?.accessDetails?.type === 'dynamic' &&
|
|
||||||
tabs.push({ title: 'Pool', content: <Pool /> })
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PoolProvider>
|
<Tabs items={tabs} className={styles.actions} />
|
||||||
<Tabs items={tabs} className={styles.actions} />
|
<Web3Feedback
|
||||||
<Web3Feedback
|
networkId={asset?.chainId}
|
||||||
networkId={asset?.chainId}
|
isAssetNetwork={isAssetNetwork}
|
||||||
isAssetNetwork={isAssetNetwork}
|
/>
|
||||||
/>
|
|
||||||
</PoolProvider>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import AddToken from '@shared/AddToken'
|
|||||||
import ExplorerLink from '@shared/ExplorerLink'
|
import ExplorerLink from '@shared/ExplorerLink'
|
||||||
import Publisher from '@shared/Publisher'
|
import Publisher from '@shared/Publisher'
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import styles from './MetaAsset.module.css'
|
import styles from './MetaAsset.module.css'
|
||||||
|
|
||||||
export default function MetaAsset({
|
export default function MetaAsset({
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import AssetType from '@shared/AssetType'
|
import AssetType from '@shared/AssetType'
|
||||||
import Time from '@shared/atoms/Time'
|
import Time from '@shared/atoms/Time'
|
||||||
import Publisher from '@shared/Publisher'
|
import Publisher from '@shared/Publisher'
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import styles from './MetaInfo.module.css'
|
import styles from './MetaInfo.module.css'
|
||||||
|
|
||||||
export default function MetaInfo({
|
export default function MetaInfo({
|
||||||
|
@ -3,7 +3,6 @@ import styles from './index.module.css'
|
|||||||
import MetaAsset from './MetaAsset'
|
import MetaAsset from './MetaAsset'
|
||||||
import MetaInfo from './MetaInfo'
|
import MetaInfo from './MetaInfo'
|
||||||
import Nft from '../Nft'
|
import Nft from '../Nft'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
|
|
||||||
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
|
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { ReactElement, useState, useEffect } from 'react'
|
import React, { ReactElement, useState, useEffect } from 'react'
|
||||||
import Link from 'next/link'
|
|
||||||
import Markdown from '@shared/Markdown'
|
import Markdown from '@shared/Markdown'
|
||||||
import MetaFull from './MetaFull'
|
import MetaFull from './MetaFull'
|
||||||
import MetaSecondary from './MetaSecondary'
|
import MetaSecondary from './MetaSecondary'
|
||||||
@ -14,7 +13,6 @@ import EditHistory from './EditHistory'
|
|||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import NetworkName from '@shared/NetworkName'
|
import NetworkName from '@shared/NetworkName'
|
||||||
import content from '../../../../content/purgatory.json'
|
import content from '../../../../content/purgatory.json'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import Button from '@shared/atoms/Button'
|
import Button from '@shared/atoms/Button'
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import {
|
|||||||
computeSettingsValidationSchema
|
computeSettingsValidationSchema
|
||||||
} from './_constants'
|
} from './_constants'
|
||||||
import content from '../../../../content/pages/editComputeDataset.json'
|
import content from '../../../../content/pages/editComputeDataset.json'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
import { setMinterToPublisher, setMinterToDispenser } from '@utils/dispenser'
|
import { setMinterToPublisher, setMinterToDispenser } from '@utils/dispenser'
|
||||||
import { transformComputeFormToServiceComputeOptions } from '@utils/compute'
|
import { transformComputeFormToServiceComputeOptions } from '@utils/compute'
|
||||||
|
@ -16,7 +16,6 @@ import FormEditMetadata from './FormEditMetadata'
|
|||||||
import { mapTimeoutStringToSeconds } from '@utils/ddo'
|
import { mapTimeoutStringToSeconds } from '@utils/ddo'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import content from '../../../../content/pages/editMetadata.json'
|
import content from '../../../../content/pages/editMetadata.json'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { useAbortController } from '@hooks/useAbortController'
|
import { useAbortController } from '@hooks/useAbortController'
|
||||||
import DebugEditMetadata from './DebugEditMetadata'
|
import DebugEditMetadata from './DebugEditMetadata'
|
||||||
import { getOceanConfig } from '@utils/ocean'
|
import { getOceanConfig } from '@utils/ocean'
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user