diff --git a/centrifuge-app/.env-config/.env.ff-prod b/centrifuge-app/.env-config/.env.ff-prod index 2cd9cc716..08482b5a5 100644 --- a/centrifuge-app/.env-config/.env.ff-prod +++ b/centrifuge-app/.env-config/.env.ff-prod @@ -8,7 +8,7 @@ REACT_APP_ONBOARDING_API_URL=https://europe-central2-centrifuge-production-x.clo 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://subql.embrio.tech +REACT_APP_SUBQUERY_URL=https://api.centrifuge.io REACT_APP_SUBSCAN_URL=https://centrifuge.subscan.io REACT_APP_TINLAKE_NETWORK=mainnet REACT_APP_INFURA_KEY=8ed99a9a115349bbbc01dcf3a24edc96 diff --git a/centrifuge-app/.env-config/.env.production b/centrifuge-app/.env-config/.env.production index 18d7de6e5..7dadec3d9 100644 --- a/centrifuge-app/.env-config/.env.production +++ b/centrifuge-app/.env-config/.env.production @@ -8,7 +8,7 @@ REACT_APP_ONBOARDING_API_URL=https://europe-central2-centrifuge-production-x.clo 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://subql.embrio.tech +REACT_APP_SUBQUERY_URL=https://api.centrifuge.io REACT_APP_SUBSCAN_URL=https://centrifuge.subscan.io REACT_APP_TINLAKE_NETWORK=mainnet REACT_APP_INFURA_KEY=8ed99a9a115349bbbc01dcf3a24edc96 diff --git a/centrifuge-app/src/components/DebugFlags/config.ts b/centrifuge-app/src/components/DebugFlags/config.ts index 2eddcf28f..6c365bc6d 100644 --- a/centrifuge-app/src/components/DebugFlags/config.ts +++ b/centrifuge-app/src/components/DebugFlags/config.ts @@ -48,6 +48,7 @@ export type Key = | 'poolCreationType' | 'showTokenYields' | 'showOracleTx' + | 'showGmp' export const flagsConfig = { address: { @@ -129,6 +130,10 @@ export const flagsConfig = { default: false, type: 'checkbox', }, + showGmp: { + default: false, + type: 'checkbox', + }, } satisfies Record export const genericFlagsConfig = flagsConfig as Record diff --git a/centrifuge-app/src/components/InvestRedeem/InvestRedeem.tsx b/centrifuge-app/src/components/InvestRedeem/InvestRedeem.tsx index 5d92ce4e7..9412f5a77 100644 --- a/centrifuge-app/src/components/InvestRedeem/InvestRedeem.tsx +++ b/centrifuge-app/src/components/InvestRedeem/InvestRedeem.tsx @@ -20,6 +20,7 @@ import { useTheme } from 'styled-components' import { ethConfig } from '../../config' import { formatBalance } from '../../utils/formatting' import { useAddress } from '../../utils/useAddress' +import { useGmp } from '../../utils/useGmp' import { useActiveDomains } from '../../utils/useLiquidityPools' import { usePool, usePoolMetadata } from '../../utils/usePools' import { LiquidityRewardsContainer } from '../LiquidityRewards/LiquidityRewardsContainer' @@ -88,6 +89,7 @@ type InputProps = { function InvestRedeemInput({ defaultView: defaultViewProp }: InputProps) { const { state } = useInvestRedeem() + const { render: renderGmp } = useGmp() const pool = usePool(state.poolId) let defaultView = defaultViewProp if (state.order && !defaultView) { @@ -101,6 +103,7 @@ function InvestRedeemInput({ defaultView: defaultViewProp }: InputProps) { return ( + {renderGmp(state.poolId, state.trancheId)} () - // | 'investWithPermit' + const [pendingActionState, setPendingAction] = React.useState() const { isLoading: isLpsLoading, data: lps } = useLiquidityPools(poolId, trancheId) const { data: lpInvest, @@ -48,6 +45,7 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children const tranche = pool.tranches.find((t) => t.id === trancheId) const { data: metadata, isLoading: isMetadataLoading } = usePoolMetadata(pool) const trancheMeta = metadata?.tranches?.[trancheId] + const chainId = provider?.network.chainId || 1 if (!tranche) throw new Error(`Token not found. Pool id: ${poolId}, token id: ${trancheId}`) @@ -77,9 +75,9 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children const minOrder = consts.orderBook.minFulfillment.toDecimal() const invest = useEvmTransaction('Invest', (cent) => cent.liquidityPools.increaseInvestOrder) - // const investWithPermit = useEvmTransaction('Invest', (cent) => cent.liquidityPools.increaseInvestOrderWithPermit) + const investWithPermit = useEvmTransaction('Invest', (cent) => cent.liquidityPools.increaseInvestOrderWithPermit) const redeem = useEvmTransaction('Redeem', (cent) => cent.liquidityPools.increaseRedeemOrder) - const collectInvest = useEvmTransaction('Collect', (cent) => cent.liquidityPools.mint) + const collectInvest = useEvmTransaction('Claim', (cent) => cent.liquidityPools.mint) const collectRedeem = useEvmTransaction('Withdraw', (cent) => cent.liquidityPools.withdraw) const approve = useEvmTransaction('Approve', (cent) => cent.liquidityPools.approveForCurrency) const cancelInvest = useEvmTransaction('Cancel order', (cent) => cent.liquidityPools.cancelInvestOrder) @@ -89,7 +87,7 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children const txActions = { invest, - // investWithPermit, + investWithPermit, redeem, collect: collectType === 'invest' @@ -118,10 +116,11 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children function doAction( name: InvestRedeemAction, fn: (arg: T) => any[] | Promise, - opt?: TransactionRequest + opt?: TransactionRequest, + gmp?: { poolId: string; trancheId: string } // enable gmp to display pending Axelar messages ): (args?: T) => void { return (args) => { - txActions[name]?.execute(fn(args!) as any, opt) + txActions[name]?.execute(fn(args!) as any, opt, gmp) setPendingAction(name) } } @@ -151,8 +150,7 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children } }, [lps]) - const supportsPermits = - !PERMITS_DISABLED && lpInvest?.currencySupportsPermit && !isSmartContractWallet && selectedWallet?.id !== 'finoa' + const supportsPermits = lpInvest?.currencySupportsPermit && !isSmartContractWallet && selectedWallet?.id !== 'finoa' const canChangeOrder = false // LP contracts don't support changing orders const state: InvestRedeemState = { @@ -202,8 +200,9 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children : Dec(0), collectType, needsToCollectBeforeOrder: true, - needsPoolCurrencyApproval: (amount) => - lpInvest ? lpInvest.lpCurrencyAllowance.toFloat() < amount && !supportsPermits : false, + needsPoolCurrencyApproval: (amount) => { + return lpInvest ? lpInvest.lpCurrencyAllowance.toFloat() < amount && !supportsPermits : false + }, needsTrancheTokenApproval: () => false, canChangeOrder, canCancelOrder: !(lpInvest?.pendingCancelDepositRequest || lpInvest?.pendingCancelRedeemRequest), @@ -229,35 +228,35 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children else if (lpInvest.lpCurrencyAllowance.lt(assets) && supportsPermits && pendingAction !== 'approvePoolCurrency') { const signer = provider!.getSigner() const connectedCent = cent.connectEvm(evmAddress!, signer) - const permit = await connectedCent.liquidityPools.signPermit([ - lpInvest.lpAddress, - lpInvest.currency.address, - assets, - ]) + const permit = await connectedCent.liquidityPools.signPermit([lpInvest.currency.address, assets, chainId]) console.log('permit', permit) - // investWithPermit.execute([lpInvest.lpAddress, assets, permit]) - // setPendingAction('investWithPermit') + investWithPermit.execute( + [lpInvest.lpAddress, assets, lpInvest?.currency.address, permit, chainId], + {}, + { poolId, trancheId } + ) + setPendingAction('investWithPermit') } else { - invest.execute([lpInvest.lpAddress, assets]) + invest.execute([lpInvest.lpAddress, assets, chainId], {}, { poolId, trancheId }) setPendingAction('invest') } }, redeem: async (newOrder: BN) => { if (!lpInvest) return - redeem.execute([lpInvest.lpAddress, newOrder]) + redeem.execute([lpInvest.lpAddress, newOrder, chainId], {}, { poolId, trancheId }) setPendingAction('redeem') }, collect: doAction('collect', () => - collectType === 'invest' ? [lpInvest?.lpAddress, lpInvest?.maxMint] : [lpInvest?.lpAddress, lpInvest?.maxWithdraw] + collectType === 'invest' ? [lpInvest?.lpAddress, chainId] : [lpInvest?.lpAddress, chainId] ), approvePoolCurrency: doAction('approvePoolCurrency', (amount) => [ - lpInvest?.lpAddress, lpInvest?.currency.address, amount.toString(), + chainId, ]), approveTrancheToken: () => {}, - cancelInvest: doAction('cancelInvest', () => [lpInvest?.lpAddress]), - cancelRedeem: doAction('cancelRedeem', () => [lpInvest?.lpAddress]), + cancelInvest: doAction('cancelInvest', () => [lpInvest?.lpAddress, chainId], undefined, { poolId, trancheId }), + cancelRedeem: doAction('cancelRedeem', () => [lpInvest?.lpAddress, chainId], undefined, { poolId, trancheId }), selectPoolCurrency(symbol) { setLpIndex(lps!.findIndex((lp) => lp.currency.symbol === symbol)) }, diff --git a/centrifuge-app/src/components/Report/CashflowStatement.tsx b/centrifuge-app/src/components/Report/CashflowStatement.tsx index 56b100678..9647f85bd 100644 --- a/centrifuge-app/src/components/Report/CashflowStatement.tsx +++ b/centrifuge-app/src/components/Report/CashflowStatement.tsx @@ -17,6 +17,7 @@ import { Spinner } from '../Spinner' import { ReportContext } from './ReportContext' import { UserFeedback } from './UserFeedback' import type { TableDataRow } from './index' +import { getColumnHeader } from './utils' type Row = TableDataRow & { formatter?: (v: any) => any @@ -83,29 +84,6 @@ export function CashflowStatement({ pool }: { pool: Pool }) { return [] } - const getColumnHeader = (timestamp: string) => { - if (groupBy === 'day' || groupBy === 'daily') { - return new Date(timestamp).toLocaleDateString('en-US', { - day: 'numeric', - month: 'short', - year: 'numeric', - }) - } else if (groupBy === 'month') { - return new Date(timestamp).toLocaleDateString('en-US', { - month: 'long', - year: 'numeric', - }) - } else if (groupBy === 'quarter') { - const date = new Date(timestamp) - return `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}` - } else if (groupBy === 'year') { - return new Date(timestamp).toLocaleDateString('en-US', { - year: 'numeric', - }) - } - return '' - } - return [ { align: 'left', @@ -125,7 +103,7 @@ export function CashflowStatement({ pool }: { pool: Pool }) { poolStates.map((state, index) => ({ align: 'right', timestamp: state.timestamp, - header: getColumnHeader(state.timestamp), + header: getColumnHeader(state.timestamp, groupBy), cell: (row: Row) => ( {row.formatter ? row.formatter((row.value as any)[index]) : (row.value as any)[index]} diff --git a/centrifuge-app/src/components/Report/ProfitAndLoss.tsx b/centrifuge-app/src/components/Report/ProfitAndLoss.tsx index 565178e12..cadd57ca5 100644 --- a/centrifuge-app/src/components/Report/ProfitAndLoss.tsx +++ b/centrifuge-app/src/components/Report/ProfitAndLoss.tsx @@ -16,6 +16,7 @@ import { Spinner } from '../Spinner' import { ReportContext } from './ReportContext' import { UserFeedback } from './UserFeedback' import type { TableDataRow } from './index' +import { getColumnHeader } from './utils' type Row = TableDataRow & { formatter?: (v: any) => any @@ -75,29 +76,6 @@ export function ProfitAndLoss({ pool }: { pool: Pool }) { return [] } - const getColumnHeader = (timestamp: string) => { - if (groupBy === 'day' || groupBy === 'daily') { - return new Date(timestamp).toLocaleDateString('en-US', { - day: 'numeric', - month: 'short', - year: 'numeric', - }) - } else if (groupBy === 'month') { - return new Date(timestamp).toLocaleDateString('en-US', { - month: 'long', - year: 'numeric', - }) - } else if (groupBy === 'quarter') { - const date = new Date(timestamp) - return `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}` - } else if (groupBy === 'year') { - return new Date(timestamp).toLocaleDateString('en-US', { - year: 'numeric', - }) - } - return '' - } - return [ { align: 'left', @@ -117,7 +95,7 @@ export function ProfitAndLoss({ pool }: { pool: Pool }) { poolStates.map((state, index) => ({ align: 'right', timestamp: state.timestamp, - header: getColumnHeader(state.timestamp), + header: getColumnHeader(state.timestamp, groupBy), cell: (row: Row) => ( {row.formatter ? row.formatter((row.value as any)[index]) : (row.value as any)[index]} diff --git a/centrifuge-app/src/components/Report/utils.tsx b/centrifuge-app/src/components/Report/utils.tsx index e3564d6bd..34f364ff7 100644 --- a/centrifuge-app/src/components/Report/utils.tsx +++ b/centrifuge-app/src/components/Report/utils.tsx @@ -155,3 +155,26 @@ export function convertCSV(values: any[], columnConfig: any[]) { }) ) } + +export const getColumnHeader = (timestamp: string, groupBy: string) => { + if (groupBy === 'day' || groupBy === 'daily') { + return new Date(timestamp).toLocaleDateString('en-US', { + day: 'numeric', + month: 'short', + year: 'numeric', + }) + } else if (groupBy === 'month') { + return new Date(timestamp).toLocaleDateString('en-US', { + month: 'long', + year: 'numeric', + }) + } else if (groupBy === 'quarter') { + const date = new Date(timestamp) + return `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}` + } else if (groupBy === 'year') { + return new Date(timestamp).toLocaleDateString('en-US', { + year: 'numeric', + }) + } + return '' +} diff --git a/centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx b/centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx index c3bef6656..40349edf3 100644 --- a/centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx @@ -175,7 +175,7 @@ function PoolDomain({ poolId, domain, refetch }: { poolId: string; domain: Domai ) : ( pool.tranches.map((tranche) => ( - +