diff --git a/centrifuge-app/.env-config/.env.development b/centrifuge-app/.env-config/.env.development
index 57881c1a10..d96792a54c 100644
--- a/centrifuge-app/.env-config/.env.development
+++ b/centrifuge-app/.env-config/.env.development
@@ -1,21 +1,21 @@
-REACT_APP_COLLATOR_WSS_URL=wss://fullnode.development.cntrfg.com
-REACT_APP_DEFAULT_NODE_URL=https://pod-development.k-f.dev
+REACT_APP_COLLATOR_WSS_URL=wss://fullnode.parachain.centrifuge.io
+REACT_APP_DEFAULT_NODE_URL=''
REACT_APP_DEFAULT_UNLIST_POOLS=false
-REACT_APP_FAUCET_URL=https://europe-central2-peak-vista-185616.cloudfunctions.net/faucet-api-dev
+REACT_APP_FAUCET_URL=
REACT_APP_IPFS_GATEWAY=https://centrifuge.mypinata.cloud/
-REACT_APP_IS_DEMO=false
+REACT_APP_IS_DEMO=
REACT_APP_NETWORK=centrifuge
-REACT_APP_ONBOARDING_API_URL=https://europe-central2-peak-vista-185616.cloudfunctions.net/onboarding-api-dev
-REACT_APP_PINNING_API_URL=https://europe-central2-peak-vista-185616.cloudfunctions.net/pinning-api-dev
-REACT_APP_POOL_CREATION_TYPE=immediate
-REACT_APP_RELAY_WSS_URL=wss://fullnode-relay.development.cntrfg.com
-REACT_APP_SUBQUERY_URL=https://api.subquery.network/sq/centrifuge/pools-development
+REACT_APP_ONBOARDING_API_URL=https://europe-central2-centrifuge-production-x.cloudfunctions.net/onboarding-api-production
+REACT_APP_PINNING_API_URL=https://europe-central2-centrifuge-production-x.cloudfunctions.net/pinning-api-production
+REACT_APP_POOL_CREATION_TYPE=propose
+REACT_APP_RELAY_WSS_URL=wss://rpc.polkadot.io
+REACT_APP_SUBQUERY_URL=https://api.subquery.network/sq/centrifuge/pools
REACT_APP_SUBSCAN_URL=https://centrifuge.subscan.io
-REACT_APP_TINLAKE_NETWORK=goerli
+REACT_APP_TINLAKE_NETWORK=mainnet
REACT_APP_INFURA_KEY=bf808e7d3d924fbeb74672d9341d0550
-REACT_APP_ONFINALITY_KEY=0e1c049f-d876-4e77-a45f-b5afdf5739b2
-REACT_APP_WHITELISTED_ACCOUNTS=
-REACT_APP_TINLAKE_SUBGRAPH_URL=https://api.goldsky.com/api/public/project_clhi43ef5g4rw49zwftsvd2ks/subgraphs/main/prod/gn
-REACT_APP_REWARDS_TREE_URL=https://storage.googleapis.com/rad-rewards-trees-kovan-staging/latest.json
+REACT_APP_ONFINALITY_KEY=7e8caebc-b052-402d-87a4-e990b67ed612
+REACT_APP_WHITELISTED_ACCOUNTS=''
+REACT_APP_REWARDS_TREE_URL=https://storage.googleapis.com/rad-rewards-trees-mainnet-production/latest.json
+REACT_APP_MEMBERLIST_ADMIN_PURE_PROXY=kALJqPUHFzDR2VkoQYWefPQyzjGzKznNny2smXGQpSf3aMw19
REACT_APP_WALLETCONNECT_ID=c32fa79350803519804a67fcab0b742a
-REACT_APP_MEMBERLIST_ADMIN_PURE_PROXY=kAJ27w29x7gHM75xajP2yXVLjVBaKmmUTxHwgRuCoAcWaoEiz
+REACT_APP_TINLAKE_SUBGRAPH_URL=https://api.goldsky.com/api/public/project_clhi43ef5g4rw49zwftsvd2ks/subgraphs/main/prod/gn
diff --git a/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx b/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx
index d5032b88f4..6db48b71dc 100644
--- a/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx
+++ b/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx
@@ -1,9 +1,187 @@
-import { Card } from '@centrifuge/fabric'
+import { AssetTransaction, CurrencyBalance } from '@centrifuge/centrifuge-js'
+import { AnchorButton, IconDownload, IconExternalLink, Shelf, Stack, StatusChip, Text } from '@centrifuge/fabric'
+import BN from 'bn.js'
+import { nftMetadataSchema } from '../../schemas'
+import { formatDate } from '../../utils/date'
+import { formatBalance } from '../../utils/formatting'
+import { getCSVDownloadUrl } from '../../utils/getCSVDownloadUrl'
+import { useMetadataMulti } from '../../utils/useMetadata'
+import { useAssetTransactions } from '../../utils/usePools'
+import { DataTable, SortableTableHeader } from '../DataTable'
+import { AnchorTextLink } from '../TextLink'
+
+type Row = {
+ type: string
+ transactionDate: string
+ assetId: string
+ amount: CurrencyBalance | undefined
+ hash: string
+ assetName: string
+}
+
+const getTransactionTypeStatus = (type: string) => {
+ if (type === 'Principal payment' || type === 'Repaid') return 'warning'
+ if (type === 'Interest') return 'ok'
+ return 'default'
+}
+
+export const columns = [
+ {
+ align: 'left',
+ header: 'Type',
+ cell: ({ type }: Row) => {type},
+ },
+ {
+ align: 'left',
+ header: ,
+ cell: ({ transactionDate }: Row) => (
+
+ {formatDate(transactionDate)}
+
+ ),
+ sortKey: 'transactionDate',
+ },
+ {
+ align: 'left',
+ header: 'Asset name',
+ cell: ({ assetId, assetName }: Row) => {
+ const [poolId, id] = assetId.split('-')
+ return (
+
+ {assetName}
+
+ )
+ },
+ },
+ {
+ align: 'right',
+ header: ,
+ cell: ({ amount }: Row) => (
+
+ {amount ? formatBalance(amount, 'USD', 2, 2) : ''}
+
+ ),
+ sortKey: 'amount',
+ },
+ {
+ align: 'right',
+ header: 'View transaction',
+ cell: ({ hash }: Row) => {
+ return (
+
+
+
+ )
+ },
+ },
+]
+
+export const TransactionHistory = ({ poolId, preview = true }: { poolId: string; preview?: boolean }) => {
+ const transactions = useAssetTransactions(poolId, new Date(0))
+
+ const assetMetadata = useMetadataMulti(
+ [...new Set(transactions?.map((transaction) => transaction.asset.metadata))] || [],
+ nftMetadataSchema
+ )
+
+ const getLabelAndAmount = (transaction: AssetTransaction) => {
+ if (transaction.type === 'BORROWED') {
+ return {
+ label: 'Purchase',
+ amount: transaction.amount,
+ }
+ }
+ if (transaction.type === 'REPAID' && !new BN(transaction.interestAmount || 0).isZero()) {
+ return {
+ label: 'Interest',
+ amount: transaction.interestAmount,
+ }
+ }
+
+ return {
+ label: 'Principal payment',
+ amount: transaction.principalAmount,
+ }
+ }
+
+ const csvData = transactions
+ ?.filter(
+ (transaction) => transaction.type !== 'CREATED' && transaction.type !== 'CLOSED' && transaction.type !== 'PRICED'
+ )
+ .map((transaction) => {
+ const { label, amount } = getLabelAndAmount(transaction)
+ const [, id] = transaction.asset.id.split('-')
+ return {
+ Type: label,
+ 'Transaction Date': `"${formatDate(transaction.timestamp, {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ timeZoneName: 'short',
+ })}"`,
+ 'Asset Name': assetMetadata[Number(id) - 1]?.data?.name || '-',
+ Amount: amount ? `"${formatBalance(amount, 'USD', 2, 2)}"` : '-',
+ Transaction: `${import.meta.env.REACT_APP_SUBSCAN_URL}/extrinsic/${transaction.hash}`,
+ }
+ })
+
+ const csvUrl = csvData?.length ? getCSVDownloadUrl(csvData) : ''
+
+ const tableData =
+ transactions
+ ?.filter(
+ (transaction) =>
+ transaction.type !== 'CREATED' && transaction.type !== 'CLOSED' && transaction.type !== 'PRICED'
+ )
+ .sort((a, b) => (a.timestamp > b.timestamp ? -1 : 1))
+ .slice(0, preview ? 8 : Infinity)
+ .map((transaction) => {
+ const [, id] = transaction.asset.id.split('-')
+ const { label, amount } = getLabelAndAmount(transaction)
+ return {
+ type: label,
+ transactionDate: transaction.timestamp,
+ assetId: transaction.asset.id,
+ assetName: assetMetadata[Number(id) - 1]?.data?.name,
+ amount,
+ hash: transaction.hash,
+ }
+ }) || []
-export const TransactionHistory = () => {
return (
-
- Transaction History
-
+
+
+
+ Transaction history
+
+ {transactions?.length && (
+
+ Download
+
+ )}
+
+
+ {transactions?.length! > 8 && preview && (
+
+ View all
+
+ )}
+
)
}
diff --git a/centrifuge-app/src/components/Report/AssetTransactions.tsx b/centrifuge-app/src/components/Report/AssetTransactions.tsx
index 83cc9a11e9..155133082b 100644
--- a/centrifuge-app/src/components/Report/AssetTransactions.tsx
+++ b/centrifuge-app/src/components/Report/AssetTransactions.tsx
@@ -7,9 +7,9 @@ import { getCSVDownloadUrl } from '../../utils/getCSVDownloadUrl'
import { useAssetTransactions } from '../../utils/usePools'
import { DataTable } from '../DataTable'
import { Spinner } from '../Spinner'
-import type { TableDataRow } from './index'
import { ReportContext } from './ReportContext'
import { UserFeedback } from './UserFeedback'
+import type { TableDataRow } from './index'
import { formatAssetTransactionType } from './utils'
export function AssetTransactions({ pool }: { pool: Pool }) {
@@ -26,7 +26,7 @@ export function AssetTransactions({ pool }: { pool: Pool }) {
return transactions?.map((tx) => ({
name: '',
value: [
- tx.assetId.split('-').at(-1)!,
+ tx.asset.id.split('-').at(-1)!,
tx.epochId.split('-').at(-1)!,
formatDate(tx.timestamp.toString()),
formatAssetTransactionType(tx.type),
@@ -77,4 +77,4 @@ export function AssetTransactions({ pool }: { pool: Pool }) {
) : (
)
-}
\ No newline at end of file
+}
diff --git a/centrifuge-app/src/components/Root.tsx b/centrifuge-app/src/components/Root.tsx
index 30ad40e09e..84f5fc6528 100644
--- a/centrifuge-app/src/components/Root.tsx
+++ b/centrifuge-app/src/components/Root.tsx
@@ -5,11 +5,11 @@ import {
TransactionToasts,
WalletProvider,
} from '@centrifuge/centrifuge-react'
-import { FabricProvider, GlobalStyle as FabricGlobalStyle } from '@centrifuge/fabric'
+import { GlobalStyle as FabricGlobalStyle, FabricProvider } from '@centrifuge/fabric'
import * as React from 'react'
import { HelmetProvider } from 'react-helmet-async'
import { QueryClient, QueryClientProvider } from 'react-query'
-import { BrowserRouter as Router, LinkProps, matchPath, Redirect, Route, RouteProps, Switch } from 'react-router-dom'
+import { LinkProps, Redirect, Route, RouteProps, BrowserRouter as Router, Switch, matchPath } from 'react-router-dom'
import { config, evmChains } from '../config'
import PoolsPage from '../pages/Pools'
import { pinToApi } from '../utils/pinToApi'
@@ -131,6 +131,7 @@ const TransactionHistoryPage = React.lazy(() => import('../pages/Portfolio/Trans
const TokenOverviewPage = React.lazy(() => import('../pages/Tokens'))
const PrimePage = React.lazy(() => import('../pages/Prime'))
const PrimeDetailPage = React.lazy(() => import('../pages/Prime/Detail'))
+const PoolTransactionsPage = React.lazy(() => import('../pages/PoolTransactions'))
const routes: RouteProps[] = [
{ path: '/nfts/collection/:cid/object/mint', component: MintNFTPage },
@@ -144,6 +145,7 @@ const routes: RouteProps[] = [
{ path: '/issuer/:pid', component: IssuerPoolPage },
{ path: '/pools/:pid/assets/:aid', component: LoanPage },
{ path: '/pools/tokens', component: TokenOverviewPage },
+ { path: '/pools/:pid/transactions', component: PoolTransactionsPage },
{ path: '/pools/:pid', component: PoolDetailPage },
{ path: '/pools', component: PoolsPage },
{ path: '/history/:address', component: TransactionHistoryPage },
diff --git a/centrifuge-app/src/pages/Loan/PricingValues.tsx b/centrifuge-app/src/pages/Loan/PricingValues.tsx
index 345156f792..1937941b41 100644
--- a/centrifuge-app/src/pages/Loan/PricingValues.tsx
+++ b/centrifuge-app/src/pages/Loan/PricingValues.tsx
@@ -27,7 +27,7 @@ export function PricingValues({ loan, pool }: Props) {
const days = getAge(new Date(pricing.oracle.timestamp).toISOString())
const borrowerAssetTransactions = assetTransactions?.filter(
- (assetTransaction) => assetTransaction.loanId === `${loan.poolId}-${loan.id}`
+ (assetTransaction) => assetTransaction.asset.id === `${loan.poolId}-${loan.id}`
)
const latestPrice = getLatestPrice(pricing.oracle.value, borrowerAssetTransactions, pool.currency.decimals)
diff --git a/centrifuge-app/src/pages/Pool/Overview/index.tsx b/centrifuge-app/src/pages/Pool/Overview/index.tsx
index 47dbc37a12..f69e21ed91 100644
--- a/centrifuge-app/src/pages/Pool/Overview/index.tsx
+++ b/centrifuge-app/src/pages/Pool/Overview/index.tsx
@@ -1,5 +1,5 @@
import { CurrencyBalance, Price } from '@centrifuge/centrifuge-js'
-import { Box, Button, Grid, TextWithPlaceholder } from '@centrifuge/fabric'
+import { Box, Button, Card, Grid, TextWithPlaceholder } from '@centrifuge/fabric'
import Decimal from 'decimal.js-light'
import * as React from 'react'
import { useParams } from 'react-router'
@@ -163,7 +163,9 @@ export function PoolDetailOverview() {
}>
-
+
+
+
diff --git a/centrifuge-app/src/pages/PoolTransactions.tsx b/centrifuge-app/src/pages/PoolTransactions.tsx
new file mode 100644
index 0000000000..bb860855ef
--- /dev/null
+++ b/centrifuge-app/src/pages/PoolTransactions.tsx
@@ -0,0 +1,29 @@
+import { Box, Stack, Text } from '@centrifuge/fabric'
+import { useParams } from 'react-router'
+import { LayoutBase } from '../components/LayoutBase'
+import { LayoutSection } from '../components/LayoutBase/LayoutSection'
+import { TransactionHistory } from '../components/PoolOverview/TransactionHistory'
+import { usePool, usePoolMetadata } from '../utils/usePools'
+
+const PoolTransactions = () => {
+ const { pid: poolId } = useParams<{ pid: string }>()
+ const pool = usePool(poolId)
+ const { data: metadata } = usePoolMetadata(pool)
+
+ return (
+
+
+
+
+ {metadata?.pool?.name}
+
+
+
+
+
+
+
+ )
+}
+
+export default PoolTransactions
diff --git a/centrifuge-app/src/utils/usePools.ts b/centrifuge-app/src/utils/usePools.ts
index f54997748b..7a98a0ba7c 100644
--- a/centrifuge-app/src/utils/usePools.ts
+++ b/centrifuge-app/src/utils/usePools.ts
@@ -117,7 +117,7 @@ export function useBorrowerAssetTransactions(poolId: string, assetId: string, fr
return assetTransactions.pipe(
map((transactions: AssetTransaction[]) =>
- transactions.filter((transaction) => transaction.assetId.split('-')[1] === assetId)
+ transactions.filter((transaction) => transaction.asset.id.split('-')[1] === assetId)
)
)
},
diff --git a/centrifuge-js/src/modules/pools.ts b/centrifuge-js/src/modules/pools.ts
index e9bf8c6fe9..8383c4ccb7 100644
--- a/centrifuge-js/src/modules/pools.ts
+++ b/centrifuge-js/src/modules/pools.ts
@@ -10,22 +10,22 @@ import { SolverResult, calculateOptimalSolution } from '..'
import { Centrifuge } from '../Centrifuge'
import { Account, TransactionOptions } from '../types'
import {
- AssetTransactionType,
- InvestorTransactionType,
- SubqueryAssetTransaction,
- SubqueryCurrencyBalances,
- SubqueryInvestorTransaction,
- SubqueryPoolSnapshot,
- SubqueryTrancheBalances,
- SubqueryTrancheSnapshot,
+ AssetTransactionType,
+ InvestorTransactionType,
+ SubqueryAssetTransaction,
+ SubqueryCurrencyBalances,
+ SubqueryInvestorTransaction,
+ SubqueryPoolSnapshot,
+ SubqueryTrancheBalances,
+ SubqueryTrancheSnapshot,
} from '../types/subquery'
import {
- addressToHex,
- computeTrancheId,
- getDateMonthsFromNow,
- getDateYearsFromNow,
- getRandomUint,
- isSameAddress,
+ addressToHex,
+ computeTrancheId,
+ getDateMonthsFromNow,
+ getDateYearsFromNow,
+ getRandomUint,
+ isSameAddress,
} from '../utils'
import { CurrencyBalance, Perquintill, Price, Rate, TokenBalance } from '../utils/BN'
import { Dec } from '../utils/Decimal'
@@ -731,11 +731,17 @@ export type AssetTransaction = {
poolId: string
accountId: string
epochId: string
- loanId: string
type: AssetTransactionType
amount: CurrencyBalance | undefined
settlementPrice: string | null
quantity: string | null
+ principalAmount: CurrencyBalance | undefined
+ interestAmount: CurrencyBalance | undefined
+ hash: string
+ asset: {
+ id: string
+ metadata: string
+ }
}
type Holder = {
@@ -2521,13 +2527,19 @@ export function getPoolsModule(inst: Centrifuge) {
timestamp: { greaterThan: $from, lessThan: $to },
}) {
nodes {
- assetId
+ principalAmount
+ interestAmount
epochId
type
timestamp
amount
settlementPrice
quantity
+ hash
+ asset {
+ id
+ metadata
+ }
}
}
}
@@ -2546,6 +2558,8 @@ export function getPoolsModule(inst: Centrifuge) {
return data!.assetTransactions.nodes.map((tx) => ({
...tx,
amount: tx.amount ? new CurrencyBalance(tx.amount, currency.decimals) : undefined,
+ principalAmount: tx.principalAmount ? new CurrencyBalance(tx.principalAmount, currency.decimals) : undefined,
+ interestAmount: tx.interestAmount ? new CurrencyBalance(tx.interestAmount, currency.decimals) : undefined,
timestamp: new Date(`${tx.timestamp}+00:00`),
})) as unknown as AssetTransaction[]
})
@@ -2933,11 +2947,11 @@ export function getPoolsModule(inst: Centrifuge) {
}
> = {}
// oracles.forEach(() => {
- // const { timestamp, value } = oracle[1].toPrimitive() as any
- // oraclePrices[(oracle[0].toHuman() as any)[0].Isin] = {
- // timestamp,
- // value: new CurrencyBalance(value, currency.decimals),
- // }
+ // const { timestamp, value } = oracle[1].toPrimitive() as any
+ // oraclePrices[(oracle[0].toHuman() as any)[0].Isin] = {
+ // timestamp,
+ // value: new CurrencyBalance(value, currency.decimals),
+ // }
// })
const activeLoansPortfolio: Record<
diff --git a/centrifuge-js/src/types/subquery.ts b/centrifuge-js/src/types/subquery.ts
index 4cc7707737..75be6a2871 100644
--- a/centrifuge-js/src/types/subquery.ts
+++ b/centrifuge-js/src/types/subquery.ts
@@ -83,11 +83,16 @@ export type SubqueryAssetTransaction = {
poolId: string
accountId: string
epochId: string
- assetId: string
type: AssetTransactionType
- amount?: number | null
+ amount: CurrencyBalance | undefined
+ principalAmount: CurrencyBalance | undefined
+ interestAmount: CurrencyBalance | undefined
settlementPrice: string | null
quantity: string | null
+ asset: {
+ id: string
+ metadata: string
+ }
}
export type SubqueryTrancheBalances = {