diff --git a/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx b/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx
index f4a475a23..ff6af92a9 100644
--- a/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx
+++ b/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx
@@ -21,6 +21,7 @@ type Row = {
toAssetName?: string
amount: CurrencyBalance | undefined
hash: string
+ netFlow?: 'positive' | 'negative' | 'neutral'
}
const getTransactionTypeStatus = (type: string): 'default' | 'info' | 'ok' | 'warning' | 'critical' => {
diff --git a/centrifuge-app/src/components/Tooltips.tsx b/centrifuge-app/src/components/Tooltips.tsx
index 2b51b6bf3..e881d0cf9 100644
--- a/centrifuge-app/src/components/Tooltips.tsx
+++ b/centrifuge-app/src/components/Tooltips.tsx
@@ -326,6 +326,10 @@ export const tooltipText = {
label: 'Available balance',
body: 'Unlimited because this is a virtual accounting process.',
},
+ linearAccrual: {
+ label: 'Linear accrual',
+ body: 'If enabled, the price of the asset is updated continuously based on linear accrual from the latest known market price to the value at maturity.',
+ },
}
export type TooltipsProps = {
diff --git a/centrifuge-app/src/config.ts b/centrifuge-app/src/config.ts
index ae8b6bab2..f4f36dac6 100644
--- a/centrifuge-app/src/config.ts
+++ b/centrifuge-app/src/config.ts
@@ -6,7 +6,6 @@ import assetHubLogo from '@centrifuge/fabric/assets/logos/assethub.svg'
import baseLogo from '@centrifuge/fabric/assets/logos/base.svg'
import celoLogo from '@centrifuge/fabric/assets/logos/celo.svg'
import ethereumLogo from '@centrifuge/fabric/assets/logos/ethereum.svg'
-import goerliLogo from '@centrifuge/fabric/assets/logos/goerli.svg'
import sepoliaLogo from '@centrifuge/fabric/assets/logos/sepolia.png'
import * as React from 'react'
import { DefaultTheme } from 'styled-components'
@@ -175,18 +174,6 @@ export const evmChains: EvmChains = {
iconUrl: ethereumLogo,
isTestnet: false,
},
- 5: {
- name: 'Ethereum Goerli',
- nativeCurrency: {
- name: 'Görli Ether',
- symbol: 'görETH',
- decimals: 18,
- },
- blockExplorerUrl: 'https://goerli.etherscan.io/',
- urls: [`https://eth-sepolia.g.alchemy.com/v2/${alchemyKey}`],
- iconUrl: goerliLogo,
- isTestnet: true,
- },
11155111: {
name: 'Ethereum Sepolia',
nativeCurrency: { name: 'Sepolia Ether', symbol: 'sepETH', decimals: 18 },
@@ -203,11 +190,11 @@ export const evmChains: EvmChains = {
iconUrl: baseLogo,
isTestnet: false,
},
- 84531: {
- name: 'Base Goerli',
- nativeCurrency: { name: 'Base Goerli Ether', symbol: 'gbETH', decimals: 18 },
- blockExplorerUrl: 'https://goerli.basescan.org/',
- urls: [`https://goerli.base.org`],
+ 84532: {
+ name: 'Base Sepolia',
+ nativeCurrency: { name: 'Base Sepolia Ether', symbol: 'sbETH', decimals: 18 },
+ blockExplorerUrl: 'https://sepolia.basescan.org/',
+ urls: [`https://sepolia.base.org`],
iconUrl: baseLogo,
isTestnet: true,
},
@@ -223,18 +210,6 @@ export const evmChains: EvmChains = {
iconUrl: arbitrumLogo,
isTestnet: false,
},
- 421613: {
- name: 'Arbitrum Goerli',
- nativeCurrency: {
- name: 'Ether',
- symbol: 'ETH',
- decimals: 18,
- },
- blockExplorerUrl: 'https://goerli.arbiscan.io/',
- urls: [`https://arbitrum-goerli.infura.io/v3/${infuraKey}`],
- iconUrl: arbitrumLogo,
- isTestnet: true,
- },
42220: {
name: 'Celo',
nativeCurrency: {
diff --git a/centrifuge-app/src/pages/IssuerPool/Configuration/index.tsx b/centrifuge-app/src/pages/IssuerPool/Configuration/index.tsx
index fbd506cd9..69af40ae4 100644
--- a/centrifuge-app/src/pages/IssuerPool/Configuration/index.tsx
+++ b/centrifuge-app/src/pages/IssuerPool/Configuration/index.tsx
@@ -5,6 +5,7 @@ import { LayoutBase } from '../../../components/LayoutBase'
import { LoadBoundary } from '../../../components/LoadBoundary'
import { useCanBorrow, usePoolAdmin } from '../../../utils/usePermissions'
import { IssuerPoolHeader } from '../Header'
+import { OnboardingSettings } from '../Investors/OnboardingSettings'
import { Details } from './Details'
import { EpochAndTranches } from './EpochAndTranches'
import { Issuer } from './Issuer'
@@ -39,6 +40,7 @@ function IssuerPoolConfiguration() {
+ {isPoolAdmin && }
{editPoolConfig && }
>
)}
diff --git a/centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx b/centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx
index 8a08822cf..c3bef6656 100644
--- a/centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx
+++ b/centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx
@@ -4,15 +4,26 @@ import {
useCentrifugeApi,
useCentrifugeTransaction,
useGetExplorerUrl,
+ useGetNetworkIcon,
useGetNetworkName,
useNetworkName,
} from '@centrifuge/centrifuge-react'
-import { Accordion, Button, IconExternalLink, Shelf, Stack, Text } from '@centrifuge/fabric'
+import {
+ Accordion,
+ Box,
+ Button,
+ Grid,
+ IconExternalLink,
+ InlineFeedback,
+ Shelf,
+ Spinner,
+ Stack,
+ Text,
+} from '@centrifuge/fabric'
import React from 'react'
import { useParams } from 'react-router'
import { combineLatest, switchMap } from 'rxjs'
import { PageSection } from '../../../components/PageSection'
-import { AnchorTextLink } from '../../../components/TextLink'
import { find } from '../../../utils/helpers'
import { useEvmTransaction } from '../../../utils/tinlake/useEvmTransaction'
import { Domain, useActiveDomains } from '../../../utils/useLiquidityPools'
@@ -36,30 +47,45 @@ export function LiquidityPools() {
const { data: domains, refetch } = useActiveDomains(poolId)
const getName = useGetNetworkName()
-
- const titles = {
- inactive: 'Not active',
- deploying: 'Action needed',
- deployed: 'Active',
- }
+ const getIcon = useGetNetworkIcon()
return (
- ({
- title: (
- <>
- {getName(domain.chainId)} - {titles[getDomainStatus(domain)]}
- >
- ),
- body: ,
- })) ?? []
- }
- />
+
+ {domains ? (
+ domains.map((domain) => (
+
+
+
+ {getName(domain.chainId)}{' '}
+ {getDomainStatus(domain) === 'deploying' && - Action needed}
+
+
+ ),
+ body: ,
+ },
+ ]}
+ />
+ ))
+ ) : (
+
+ )}
+
)
}
@@ -67,7 +93,6 @@ export function LiquidityPools() {
function PoolDomain({ poolId, domain, refetch }: { poolId: string; domain: Domain; refetch: () => void }) {
const pool = usePool(poolId)
const poolAdmin = usePoolAdmin(poolId)
- const getName = useGetNetworkName()
const explorer = useGetExplorerUrl(domain.chainId)
const api = useCentrifugeApi()
@@ -82,7 +107,17 @@ function PoolDomain({ poolId, domain, refetch }: { poolId: string; domain: Domai
)
).pipe(
switchMap((txs) => {
- return cent.wrapSignAndSend(api, txs.length > 1 ? api.tx.utility.batchAll(txs) : txs[0], options)
+ return cent.wrapSignAndSend(
+ api,
+ txs.length > 1
+ ? api.tx.utility.batchAll([
+ api.tx.liquidityPoolsGateway.startBatchMessage({ EVM: domain.chainId }),
+ ...txs,
+ api.tx.liquidityPoolsGateway.endBatchMessage({ EVM: domain.chainId }),
+ ])
+ : txs[0],
+ options
+ )
})
)
}
@@ -99,48 +134,57 @@ function PoolDomain({ poolId, domain, refetch }: { poolId: string; domain: Domai
return (
- {status === 'inactive' ? (
-
- ) : status === 'deploying' ? (
-
- {pool.tranches.map((t) => (
-
- {domain.canTrancheBeDeployed[t.id] && (
-
- )}
- {domain.currencies.map((currency, i) => (
-
- {domain.trancheTokens[t.id] && !domain.liquidityPools[t.id][currency.address] && (
-
- )}
-
- ))}
-
- ))}
-
- ) : (
- pool.tranches.map((tranche) => (
-
-
-
- See {tranche.currency.name} token on {getName(domain.chainId)}
-
-
-
-
- ))
- )}
{domain.hasDeployedLp && (
-
)
}
@@ -157,14 +201,14 @@ function DeployTrancheButton({
onSuccess: () => void
}) {
const pool = usePool(poolId)
- const { execute, isLoading } = useEvmTransaction(`Deploy tranche`, (cent) => cent.liquidityPools.deployTranche, {
+ const { execute, isLoading } = useEvmTransaction(`Deploy token`, (cent) => cent.liquidityPools.deployTranche, {
onSuccess,
})
const tranche = find(pool.tranches, (t) => t.id === trancheId)!
return (
execute([domain.poolManager, poolId, trancheId])} small>
- Deploy tranche: {tranche.currency.name}
+ Deploy {tranche.currency.symbol} token
)
}
@@ -184,11 +228,9 @@ function DeployLPButton({
}) {
const pool = usePool(poolId)
- const { execute, isLoading } = useEvmTransaction(
- `Deploy liquidity pool`,
- (cent) => cent.liquidityPools.deployLiquidityPool,
- { onSuccess }
- )
+ const { execute, isLoading } = useEvmTransaction(`Deploy vault`, (cent) => cent.liquidityPools.deployLiquidityPool, {
+ onSuccess,
+ })
const tranche = find(pool.tranches, (t) => t.id === trancheId)!
return (
@@ -197,7 +239,7 @@ function DeployLPButton({
onClick={() => execute([domain.poolManager, poolId, trancheId, domain.currencies[currencyIndex].address])}
small
>
- Deploy tranche/currency liquidity pool: {tranche.currency.name} / {domain.currencies[currencyIndex].name}
+ Deploy {tranche.currency.symbol} / {domain.currencies[currencyIndex].symbol} vault
)
}
diff --git a/centrifuge-app/src/pages/IssuerPool/Investors/index.tsx b/centrifuge-app/src/pages/IssuerPool/Investors/index.tsx
index 71938da4d..9f1f540b4 100644
--- a/centrifuge-app/src/pages/IssuerPool/Investors/index.tsx
+++ b/centrifuge-app/src/pages/IssuerPool/Investors/index.tsx
@@ -5,7 +5,6 @@ import { useSuitableAccounts } from '../../../utils/usePermissions'
import { IssuerPoolHeader } from '../Header'
import { InvestorStatus } from './InvestorStatus'
import { LiquidityPools } from './LiquidityPools'
-import { OnboardingSettings } from './OnboardingSettings'
export function IssuerPoolInvestorsPage() {
return (
@@ -30,7 +29,6 @@ function IssuerPoolInvestors() {
<>
{canEditInvestors && }
{isPoolAdmin && }
- {isPoolAdmin && }
>
)
}
diff --git a/centrifuge-app/src/pages/Loan/PricingValues.tsx b/centrifuge-app/src/pages/Loan/PricingValues.tsx
index f366dfada..7ae30fa8b 100644
--- a/centrifuge-app/src/pages/Loan/PricingValues.tsx
+++ b/centrifuge-app/src/pages/Loan/PricingValues.tsx
@@ -1,5 +1,6 @@
import { Loan, Pool, TinlakeLoan } from '@centrifuge/centrifuge-js'
import { Card, Stack, Text } from '@centrifuge/fabric'
+import { Tooltips } from '../../components/Tooltips'
import { formatDate, getAge } from '../../utils/date'
import { formatBalance, formatPercentage } from '../../utils/formatting'
import { getLatestPrice } from '../../utils/getLatestPrice'
@@ -33,12 +34,14 @@ export function PricingValues({ loan, pool }: Props) {
}
})
- const days = getAge(new Date(latestOraclePrice.timestamp).toISOString())
-
const borrowerAssetTransactions = assetTransactions?.filter(
(assetTransaction) => assetTransaction.asset.id === `${loan.poolId}-${loan.id}`
)
- const latestPrice = getLatestPrice(latestOraclePrice.value, borrowerAssetTransactions, pool.currency.decimals)
+ const latestPrice = getLatestPrice(latestOraclePrice, borrowerAssetTransactions, pool.currency.decimals)
+
+ const days = latestPrice.timestamp > 0 ? getAge(new Date(latestPrice.timestamp).toISOString()) : undefined
+
+ const accruedPrice = 'currentPrice' in loan && loan.currentPrice
return (
@@ -50,11 +53,21 @@ export function PricingValues({ loan, pool }: Props) {
metrics={[
...('isin' in pricing.priceId ? [{ label: 'ISIN', value: pricing.priceId.isin }] : []),
{
- label: `Latest price${latestOraclePrice.value.isZero() && latestPrice ? ' (settlement)' : ''}`,
- value: latestPrice ? `${formatBalance(latestPrice, pool.currency.symbol, 6, 2)}` : '-',
+ label: `Current price${latestOraclePrice.value.isZero() && latestPrice ? ' (settlement)' : ''}`,
+ value: accruedPrice
+ ? `${formatBalance(accruedPrice || latestPrice, pool.currency.symbol, 6, 2)}`
+ : latestPrice
+ ? `${formatBalance(latestPrice.value, pool.currency.symbol, 6, 2)}`
+ : '-',
+ },
+ {
+ label: ,
+ value: pricing.withLinearPricing ? 'Enabled' : 'Disabled',
},
- { label: 'Price last updated', value: days === '0' ? `${days} ago` : `Today` },
- ...(pricing.interestRate
+ ...(!pricing.withLinearPricing
+ ? [{ label: 'Price last updated', value: days ? `${days} ago` : `Today` }]
+ : [{ label: 'Last manual price update', value: days ? `${days} ago` : `Today` }]),
+ ...(pricing.interestRate.gtn(0)
? [
{
label: 'Interest rate',
diff --git a/centrifuge-app/src/utils/getLatestPrice.ts b/centrifuge-app/src/utils/getLatestPrice.ts
index dbb102c8f..1fd40b230 100644
--- a/centrifuge-app/src/utils/getLatestPrice.ts
+++ b/centrifuge-app/src/utils/getLatestPrice.ts
@@ -1,21 +1,21 @@
import { AssetTransaction, CurrencyBalance } from '@centrifuge/centrifuge-js'
export const getLatestPrice = (
- oracleValue: CurrencyBalance,
+ oracleValue: { value: CurrencyBalance; timestamp: number },
borrowerAssetTransactions: AssetTransaction[] | undefined,
decimals: number
-) => {
- if (!borrowerAssetTransactions) return null
+): { value: CurrencyBalance; timestamp: number } => {
+ if (!borrowerAssetTransactions) return { value: new CurrencyBalance(0, decimals), timestamp: 0 }
- const latestSettlementPrice = borrowerAssetTransactions[borrowerAssetTransactions.length - 1]?.settlementPrice
+ const latestTx = borrowerAssetTransactions[borrowerAssetTransactions.length - 1]
- if (latestSettlementPrice && oracleValue.isZero()) {
- return new CurrencyBalance(latestSettlementPrice, decimals)
+ if (latestTx.settlementPrice && oracleValue.value.isZero()) {
+ return { value: new CurrencyBalance(latestTx.settlementPrice, decimals), timestamp: latestTx.timestamp.getTime() }
}
- if (oracleValue.isZero()) {
- return null
+ if (oracleValue.value.isZero()) {
+ return { value: new CurrencyBalance(0, decimals), timestamp: 0 }
}
- return new CurrencyBalance(oracleValue, 18)
+ return oracleValue
}
diff --git a/centrifuge-js/src/modules/liquidityPools.ts b/centrifuge-js/src/modules/liquidityPools.ts
index 4cb4bbd0a..c5d0b34b0 100644
--- a/centrifuge-js/src/modules/liquidityPools.ts
+++ b/centrifuge-js/src/modules/liquidityPools.ts
@@ -87,12 +87,14 @@ export function getLiquidityPoolsModule(inst: Centrifuge) {
switchMap((rawPool) => {
const pool = rawPool.toPrimitive() as any
const tx = api.tx.utility.batchAll([
+ api.tx.liquidityPoolsGateway.startBatchMessage({ EVM: chainId }),
...(currencyKeysToAdd?.map((key) => api.tx.liquidityPools.addCurrency(key)) ?? []),
api.tx.liquidityPools.addPool(poolId, { EVM: chainId }),
...pool.tranches.ids.flatMap((trancheId: string) => [
api.tx.liquidityPools.addTranche(poolId, trancheId, { EVM: chainId }),
]),
...currencies.map((cur) => api.tx.liquidityPools.allowInvestmentCurrency(poolId, cur.key)),
+ api.tx.liquidityPoolsGateway.endBatchMessage({ EVM: chainId }),
])
return inst.wrapSignAndSend(api, tx, options)
})