mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Pool tx history (#307)
* graphql Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * ignore generated Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * delete generated Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix travis Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix travis Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix fetch Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix travis Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix fetch Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * update readme Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * pool creator liquidit& statistics Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * graph with the graph Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * cleanup Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix query Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * update poll interval Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * update graph url Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * ocean bump Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * run apollo codegen before starting gatsby * put back graph loading state * typing fix * graph tweak, add error state * readme update * remove unused functions, move graph provider Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix package-lock * fix graph when switching tabs * generate apollo files into one folder * fix loading Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * graph query Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * tx query Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix titles Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix text issues Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix query Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * local pagination Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * return refreshInterval to 10 sec Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * add Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix data set column Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
parent
a2fe2fdee0
commit
79715df435
@ -87,7 +87,8 @@
|
||||
"slugify": "^1.4.6",
|
||||
"swr": "^0.3.11",
|
||||
"use-dark-mode": "^2.3.1",
|
||||
"yup": "^0.32.8"
|
||||
"web3": "^1.3.1",
|
||||
"yup": "^0.32.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
NormalizedCacheObject
|
||||
} from '@apollo/client'
|
||||
import fetch from 'cross-fetch'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
const contentQuery = graphql`
|
||||
query AppQuery {
|
||||
purgatory: allFile(filter: { relativePath: { eq: "purgatory.json" } }) {
|
||||
@ -54,7 +55,7 @@ export default function App({
|
||||
const newClient = new ApolloClient({
|
||||
link: new HttpLink({
|
||||
uri: `${
|
||||
(config as any).subgraphUri
|
||||
(config as ConfigHelperConfig).subgraphUri
|
||||
}/subgraphs/name/oceanprotocol/ocean-subgraph`,
|
||||
fetch
|
||||
}),
|
||||
|
@ -19,8 +19,7 @@ export default function AssetListTitle({
|
||||
const [assetTitle, setAssetTitle] = useState<string>(title)
|
||||
|
||||
useEffect(() => {
|
||||
if (assetTitle || !config?.metadataCacheUri) return
|
||||
|
||||
if (title || !config?.metadataCacheUri) return
|
||||
if (ddo) {
|
||||
const { attributes } = ddo.findServiceByType('metadata')
|
||||
setAssetTitle(attributes.main.name)
|
||||
@ -31,6 +30,8 @@ export default function AssetListTitle({
|
||||
|
||||
async function getDDO() {
|
||||
const ddo = await retrieveDDO(did, config.metadataCacheUri, source.token)
|
||||
|
||||
if (!ddo) return
|
||||
const { attributes } = ddo.findServiceByType('metadata')
|
||||
setAssetTitle(attributes.main.name)
|
||||
}
|
||||
@ -38,9 +39,10 @@ export default function AssetListTitle({
|
||||
!ddo && did && getDDO()
|
||||
|
||||
return () => {
|
||||
console.log('canceled?')
|
||||
source.cancel()
|
||||
}
|
||||
}, [assetTitle, config?.metadataCacheUri, ddo, did])
|
||||
}, [assetTitle, config?.metadataCacheUri, ddo, did, title])
|
||||
|
||||
return (
|
||||
<h3 className={styles.title}>
|
||||
|
@ -1,3 +1,7 @@
|
||||
.time {
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
|
||||
.titleText {
|
||||
white-space: pre;
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { PoolTransaction } from '@oceanprotocol/lib/dist/node/balancer/OceanPool'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import EtherscanLink from '../atoms/EtherscanLink'
|
||||
@ -9,41 +8,61 @@ import styles from './PoolTransactions.module.css'
|
||||
import { useUserPreferences } from '../../providers/UserPreferences'
|
||||
import { Ocean } from '@oceanprotocol/lib'
|
||||
import { formatPrice } from '../atoms/Price/PriceUnit'
|
||||
import { gql } from '@apollo/client'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import {
|
||||
TransactionHistory,
|
||||
TransactionHistoryPoolTransactions
|
||||
} from '../../@types/apollo/TransactionHistory'
|
||||
|
||||
const txHistoryQuery = gql`
|
||||
query Pool($id: ID!, $user: String!) {
|
||||
pool(id: $id) {
|
||||
transactions(orderBy: timestamp, where: { userAddressStr: $user }) {
|
||||
tx
|
||||
timestamp
|
||||
spotPrice
|
||||
event
|
||||
sharesTransferAmount
|
||||
tokens {
|
||||
type
|
||||
value
|
||||
tokenAddress
|
||||
poolToken {
|
||||
tokenId {
|
||||
symbol
|
||||
name
|
||||
}
|
||||
tokenAddress
|
||||
}
|
||||
}
|
||||
import web3 from 'web3'
|
||||
|
||||
const txHistoryQueryByPool = gql`
|
||||
query TransactionHistoryByPool($user: String, $pool: String) {
|
||||
poolTransactions(
|
||||
orderBy: timestamp
|
||||
orderDirection: desc
|
||||
where: { userAddress: $user, poolAddress: $pool }
|
||||
first: 1000
|
||||
) {
|
||||
tx
|
||||
event
|
||||
timestamp
|
||||
poolAddress {
|
||||
datatokenAddress
|
||||
}
|
||||
tokens {
|
||||
value
|
||||
type
|
||||
tokenAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
async function getSymbol(
|
||||
ocean: Ocean,
|
||||
tokenAddress: string,
|
||||
oceanTokenAddress: string
|
||||
) {
|
||||
const txHistoryQuery = gql`
|
||||
query TransactionHistory($user: String) {
|
||||
poolTransactions(
|
||||
orderBy: timestamp
|
||||
orderDirection: desc
|
||||
where: { userAddress: $user }
|
||||
first: 1000
|
||||
) {
|
||||
tx
|
||||
event
|
||||
timestamp
|
||||
poolAddress {
|
||||
datatokenAddress
|
||||
}
|
||||
tokens {
|
||||
value
|
||||
type
|
||||
tokenAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
async function getSymbol(ocean: Ocean, tokenAddress: string) {
|
||||
const symbol =
|
||||
oceanTokenAddress === tokenAddress
|
||||
ocean.pool.oceanAddress.toLowerCase() === tokenAddress.toLowerCase()
|
||||
? 'OCEAN'
|
||||
: await ocean.datatokens.getSymbol(tokenAddress)
|
||||
|
||||
@ -52,52 +71,81 @@ async function getSymbol(
|
||||
|
||||
async function getTitle(
|
||||
ocean: Ocean,
|
||||
row: PoolTransaction,
|
||||
locale: string,
|
||||
oceanTokenAddress: string
|
||||
row: TransactionHistoryPoolTransactions,
|
||||
locale: string
|
||||
) {
|
||||
const addRemoveSymbol = await getSymbol(
|
||||
ocean,
|
||||
row.tokenIn || row.tokenOut,
|
||||
oceanTokenAddress
|
||||
)
|
||||
let title = ''
|
||||
|
||||
const title =
|
||||
row.type === 'join'
|
||||
? `Add ${formatPrice(row.tokenAmountIn, locale)} ${addRemoveSymbol}`
|
||||
: row.type === 'exit'
|
||||
? `Remove ${formatPrice(row.tokenAmountOut, locale)} ${addRemoveSymbol}`
|
||||
: `Swap ${formatPrice(row.tokenAmountIn, locale)} ${await getSymbol(
|
||||
ocean,
|
||||
row.tokenIn,
|
||||
oceanTokenAddress
|
||||
)} for ${formatPrice(row.tokenAmountOut, locale)} ${await getSymbol(
|
||||
ocean,
|
||||
row.tokenOut,
|
||||
oceanTokenAddress
|
||||
)}`
|
||||
switch (row.event) {
|
||||
case 'swap': {
|
||||
const inToken = row.tokens.filter((x) => x.type === 'in')[0]
|
||||
const inTokenSymbol = await getSymbol(ocean, inToken.tokenAddress)
|
||||
const outToken = row.tokens.filter((x) => x.type === 'out')[0]
|
||||
const outTokenSymbol = await getSymbol(ocean, outToken.tokenAddress)
|
||||
title += `Swap ${formatPrice(
|
||||
Math.abs(inToken.value).toString(),
|
||||
locale
|
||||
)}${inTokenSymbol} for ${formatPrice(
|
||||
Math.abs(outToken.value).toString(),
|
||||
locale
|
||||
)}${outTokenSymbol}`
|
||||
break
|
||||
}
|
||||
case 'setup': {
|
||||
const firstToken = row.tokens.filter(
|
||||
(x) =>
|
||||
x.tokenAddress.toLowerCase() === ocean.pool.oceanAddress.toLowerCase()
|
||||
)[0]
|
||||
const firstTokenSymbol = await getSymbol(ocean, firstToken.tokenAddress)
|
||||
const secondToken = row.tokens.filter(
|
||||
(x) =>
|
||||
x.tokenAddress.toLowerCase() !== ocean.pool.oceanAddress.toLowerCase()
|
||||
)[0]
|
||||
const secondTokenSymbol = await getSymbol(ocean, secondToken.tokenAddress)
|
||||
title += `Create pool with ${formatPrice(
|
||||
Math.abs(firstToken.value).toString(),
|
||||
locale
|
||||
)}${firstTokenSymbol} and ${formatPrice(
|
||||
Math.abs(secondToken.value).toString(),
|
||||
locale
|
||||
)}${secondTokenSymbol}`
|
||||
break
|
||||
}
|
||||
case 'join':
|
||||
case 'exit': {
|
||||
for (let i = 0; i < row.tokens.length; i++) {
|
||||
const tokenSymbol = await getSymbol(ocean, row.tokens[i].tokenAddress)
|
||||
if (i > 0) title += '\n'
|
||||
title += `${row.event === 'join' ? 'Add' : 'Remove'} ${formatPrice(
|
||||
Math.abs(row.tokens[i].value).toString(),
|
||||
locale
|
||||
)}${tokenSymbol}`
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return title
|
||||
}
|
||||
|
||||
function Title({ row }: { row: PoolTransaction }) {
|
||||
const { ocean, networkId, config } = useOcean()
|
||||
function Title({ row }: { row: TransactionHistoryPoolTransactions }) {
|
||||
const { ocean, networkId } = useOcean()
|
||||
const [title, setTitle] = useState<string>()
|
||||
const { locale } = useUserPreferences()
|
||||
|
||||
useEffect(() => {
|
||||
if (!ocean || !locale || !row || !config?.oceanTokenAddress) return
|
||||
if (!ocean || !locale || !row) return
|
||||
|
||||
async function init() {
|
||||
const title = await getTitle(ocean, row, locale, config.oceanTokenAddress)
|
||||
const title = await getTitle(ocean, row, locale)
|
||||
setTitle(title)
|
||||
}
|
||||
init()
|
||||
}, [ocean, row, locale, config?.oceanTokenAddress])
|
||||
}, [ocean, row, locale])
|
||||
|
||||
return title ? (
|
||||
<EtherscanLink networkId={networkId} path={`/tx/${row.transactionHash}`}>
|
||||
{title}
|
||||
<EtherscanLink networkId={networkId} path={`/tx/${row.tx}`}>
|
||||
<span className={styles.titleText}>{title}</span>
|
||||
</EtherscanLink>
|
||||
) : null
|
||||
}
|
||||
@ -106,21 +154,24 @@ function getColumns(minimal?: boolean) {
|
||||
return [
|
||||
{
|
||||
name: 'Title',
|
||||
selector: function getTitleRow(row: PoolTransaction) {
|
||||
selector: function getTitleRow(row: TransactionHistoryPoolTransactions) {
|
||||
return <Title row={row} />
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Data Set',
|
||||
selector: function getAssetRow(row: PoolTransaction) {
|
||||
const did = row.dtAddress.replace('0x', 'did:op:')
|
||||
selector: function getAssetRow(row: TransactionHistoryPoolTransactions) {
|
||||
const did = web3.utils
|
||||
.toChecksumAddress(row.poolAddress.datatokenAddress)
|
||||
.replace('0x', 'did:op:')
|
||||
|
||||
return <AssetTitle did={did} />
|
||||
},
|
||||
omit: minimal
|
||||
},
|
||||
{
|
||||
name: 'Time',
|
||||
selector: function getTimeRow(row: PoolTransaction) {
|
||||
selector: function getTimeRow(row: TransactionHistoryPoolTransactions) {
|
||||
return (
|
||||
<Time
|
||||
className={styles.time}
|
||||
@ -142,35 +193,30 @@ export default function PoolTransactions({
|
||||
poolAddress?: string
|
||||
minimal?: boolean
|
||||
}): ReactElement {
|
||||
const { ocean, accountId } = useOcean()
|
||||
const [logs, setLogs] = useState<PoolTransaction[]>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { accountId } = useOcean()
|
||||
const [logs, setLogs] = useState<TransactionHistoryPoolTransactions[]>()
|
||||
|
||||
const { data, loading } = useQuery<TransactionHistory>(
|
||||
poolAddress ? txHistoryQueryByPool : txHistoryQuery,
|
||||
{
|
||||
variables: {
|
||||
user: accountId?.toLowerCase(),
|
||||
pool: poolAddress?.toLowerCase()
|
||||
},
|
||||
pollInterval: 20000
|
||||
}
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
async function getLogs() {
|
||||
if (!ocean || !accountId) return
|
||||
|
||||
setIsLoading(true)
|
||||
const logs = poolAddress
|
||||
? await ocean.pool.getPoolLogs(poolAddress, 0, accountId)
|
||||
: await ocean.pool.getAllPoolLogs(accountId)
|
||||
// sort logs by date, newest first
|
||||
const logsSorted = logs.sort((a, b) => {
|
||||
if (a.timestamp > b.timestamp) return -1
|
||||
if (a.timestamp < b.timestamp) return 1
|
||||
return 0
|
||||
})
|
||||
setLogs(logsSorted)
|
||||
setIsLoading(false)
|
||||
}
|
||||
getLogs()
|
||||
}, [ocean, accountId, poolAddress])
|
||||
if (!data) return
|
||||
setLogs(data.poolTransactions)
|
||||
}, [data, loading])
|
||||
|
||||
return (
|
||||
<Table
|
||||
columns={getColumns(minimal)}
|
||||
data={logs}
|
||||
isLoading={isLoading}
|
||||
isLoading={loading}
|
||||
noTableHead={minimal}
|
||||
dense={minimal}
|
||||
pagination={minimal ? logs?.length >= 4 : logs?.length >= 9}
|
||||
|
@ -3,14 +3,11 @@ import Button from '../../../atoms/Button'
|
||||
import PoolTransactions from '../../../molecules/PoolTransactions'
|
||||
import styles from './Transactions.module.css'
|
||||
import { ReactComponent as Caret } from '../../../../images/caret.svg'
|
||||
import { useAsset } from '../../../../providers/Asset'
|
||||
|
||||
export default function Transactions({
|
||||
poolAddress
|
||||
}: {
|
||||
poolAddress: string
|
||||
}): ReactElement {
|
||||
export default function Transactions(): ReactElement {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const { ddo } = useAsset()
|
||||
function handleClick() {
|
||||
setOpen(!open)
|
||||
}
|
||||
@ -31,7 +28,9 @@ export default function Transactions({
|
||||
{open ? 'Hide' : 'Show'} <Caret />
|
||||
</Button>
|
||||
</h3>
|
||||
{open === true && <PoolTransactions poolAddress={poolAddress} minimal />}
|
||||
{open === true && (
|
||||
<PoolTransactions poolAddress={ddo.price?.address} minimal />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ export default function Pool(): ReactElement {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{accountId && <Transactions poolAddress={price?.address} />}
|
||||
{accountId && <Transactions />}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
@ -68,7 +68,7 @@ function AssetProvider({
|
||||
ddo.price.address
|
||||
)
|
||||
setPrice(newPrice)
|
||||
Logger.log(`Refreshed asset price: ${newPrice?.value}`)
|
||||
Logger.log(`Refreshed asset price: ${newPrice?.value}`, newPrice)
|
||||
}, [ocean, config, ddo, networkId, status])
|
||||
|
||||
const fetchDdo = async (token?: CancelToken) => {
|
||||
|
Loading…
Reference in New Issue
Block a user