Skip to content

Commit

Permalink
Merge branch 'main' of github.com:centrifuge/apps into hotfix-financi…
Browse files Browse the repository at this point in the history
…ng-and-subql
  • Loading branch information
sophialittlejohn committed Sep 6, 2024
2 parents fbd533b + f2e0fa4 commit 75d1314
Show file tree
Hide file tree
Showing 14 changed files with 841 additions and 108 deletions.
5 changes: 5 additions & 0 deletions centrifuge-app/src/components/DebugFlags/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type Key =
| 'poolCreationType'
| 'showTokenYields'
| 'showOracleTx'
| 'showGmp'

export const flagsConfig = {
address: {
Expand Down Expand Up @@ -129,6 +130,10 @@ export const flagsConfig = {
default: false,
type: 'checkbox',
},
showGmp: {
default: false,
type: 'checkbox',
},
} satisfies Record<Key, DebugFlagConfig>

export const genericFlagsConfig = flagsConfig as Record<string, DebugFlagConfig>
3 changes: 3 additions & 0 deletions centrifuge-app/src/components/InvestRedeem/InvestRedeem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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) {
Expand All @@ -101,6 +103,7 @@ function InvestRedeemInput({ defaultView: defaultViewProp }: InputProps) {

return (
<Stack>
{renderGmp(state.poolId, state.trancheId)}
<Flex
style={{
boxShadow: `inset 0 -2px 0 ${theme.colors.borderPrimary}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import { usePendingCollect, usePool, usePoolMetadata } from '../../utils/usePool
import { InvestRedeemContext } from './InvestRedeemProvider'
import { InvestRedeemAction, InvestRedeemActions, InvestRedeemState, InvestRedeemProviderProps as Props } from './types'

const PERMITS_DISABLED = true

export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children }: Props) {
const centAddress = useAddress('substrate')
const evmAddress = useAddress('evm')
Expand All @@ -34,8 +32,7 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children
const centOrder = usePendingCollect(poolId, trancheId, centAddress)
const pool = usePool(poolId) as Pool
const cent = useCentrifuge()
const [pendingActionState, setPendingAction] = React.useState<InvestRedeemAction>()
// | 'investWithPermit'
const [pendingActionState, setPendingAction] = React.useState<InvestRedeemAction | 'investWithPermit'>()
const { isLoading: isLpsLoading, data: lps } = useLiquidityPools(poolId, trancheId)
const {
data: lpInvest,
Expand All @@ -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}`)

Expand Down Expand Up @@ -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)
Expand All @@ -89,7 +87,7 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children

const txActions = {
invest,
// investWithPermit,
investWithPermit,
redeem,
collect:
collectType === 'invest'
Expand Down Expand Up @@ -118,10 +116,11 @@ export function InvestRedeemLiquidityPoolsProvider({ poolId, trancheId, children
function doAction<T = any>(
name: InvestRedeemAction,
fn: (arg: T) => any[] | Promise<any[]>,
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)
}
}
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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),
Expand All @@ -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))
},
Expand Down
12 changes: 10 additions & 2 deletions centrifuge-app/src/pages/IssuerPool/Investors/LiquidityPools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ function PoolDomain({ poolId, domain, refetch }: { poolId: string; domain: Domai
</ConnectionGuard>
) : (
pool.tranches.map((tranche) => (
<a href={explorer.address(domain.trancheTokens[tranche.id])} target="_blank">
<a href={explorer.address(domain.trancheTokens[tranche.id])} target="_blank" rel="noopener noreferrer">
<Button variant="secondary" small style={{ width: '100%' }}>
<Shelf gap={1}>
<span>View {tranche.currency.symbol} token</span>
Expand Down Expand Up @@ -252,14 +252,22 @@ function EnableButton({ poolId, domain }: { poolId: string; domain: Domain }) {
(cent) => cent.liquidityPools.enablePoolOnDomain
)

const tokenPricesToUpdate = Object.entries(domain.liquidityPools).flatMap(([tid, poolsByCurrency]) => {
return domain.currencies.map((cur) => [tid, cur.key] satisfies [string, CurrencyKey])
})

const currenciesToAdd = domain.currencies
.filter((cur) => domain.currencyNeedsAdding[cur.address])
.map((cur) => cur.key)

return (
<Button
loading={isLoading}
onClick={() => execute([poolId, domain.chainId, currenciesToAdd], { account: poolAdmin })}
onClick={() =>
execute([poolId, domain.chainId, currenciesToAdd, tokenPricesToUpdate, domain.chainId], {
account: poolAdmin,
})
}
small
>
Enable
Expand Down
1 change: 1 addition & 0 deletions centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export function ExternalFinanceForm({ loan, source }: { loan: ExternalLoan; sour

React.useEffect(() => {
financeForm.validateForm()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [source])

const financeFormRef = React.useRef<HTMLFormElement>(null)
Expand Down
5 changes: 3 additions & 2 deletions centrifuge-app/src/pages/Loan/FinanceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,9 @@ function Mux({
})),
]}
value={index.toString()}
onChange={(event) => setSelectedAddressIndex(currencyKey, parseInt(event.target.value))}
onChange={(event) => {
setSelectedAddressIndex(currencyKey, parseInt(event.target.value))
}}
small
/>
</Flex>
Expand Down Expand Up @@ -538,7 +540,6 @@ export function useWithdraw(poolId: string, borrower: CombinedSubstrateAccount,
},
}
}

return {
render: () => (
<Mux
Expand Down
23 changes: 19 additions & 4 deletions centrifuge-app/src/pages/NavManagement/NavManagementAssetTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ActiveLoan, CreatedLoan, CurrencyBalance, ExternalLoan } from '@centrifuge/centrifuge-js'
import { ActiveLoan, CreatedLoan, CurrencyBalance, CurrencyKey, ExternalLoan } from '@centrifuge/centrifuge-js'
import { useCentrifugeApi, useCentrifugeQuery, useCentrifugeTransaction } from '@centrifuge/centrifuge-react'
import {
Box,
Expand All @@ -15,7 +15,7 @@ import {
import { BN } from 'bn.js'
import { Field, FieldProps, FormikProvider, useFormik } from 'formik'
import * as React from 'react'
import { switchMap } from 'rxjs'
import { combineLatest, switchMap } from 'rxjs'
import daiLogo from '../../assets/images/dai-logo.svg'
import usdcLogo from '../../assets/images/usdc-logo.svg'
import { ButtonGroup } from '../../components/ButtonGroup'
Expand All @@ -25,6 +25,7 @@ import { AssetName } from '../../components/LoanList'
import { RouterTextLink } from '../../components/TextLink'
import { formatBalance } from '../../utils/formatting'
import { useLiquidity } from '../../utils/useLiquidity'
import { useActiveDomains } from '../../utils/useLiquidityPools'
import { useSuitableAccounts } from '../../utils/usePermissions'
import { usePool, usePoolAccountOrders, usePoolFees } from '../../utils/usePools'
import { usePoolsForWhichAccountIsFeeder } from '../../utils/usePoolsForWhichAccountIsFeeder'
Expand All @@ -49,6 +50,7 @@ type Row = FormValues['feed'][0] | ActiveLoan | CreatedLoan
const MAX_COLLECT = 100 // maximum number of transactions to collect in one batch

export function NavManagementAssetTable({ poolId }: { poolId: string }) {
const { data: domains } = useActiveDomains(poolId)
const allowedPools = usePoolsForWhichAccountIsFeeder()
const isFeeder = !!allowedPools?.find((p) => p.id === poolId)
const [isEditing, setIsEditing] = React.useState(false)
Expand Down Expand Up @@ -91,8 +93,20 @@ export function NavManagementAssetTable({ poolId }: { poolId: string }) {
const { execute, isLoading } = useCentrifugeTransaction(
'Update NAV',
(cent) => (args: [values: FormValues], options) => {
return cent.pools.closeEpoch([poolId, false], { batch: true }).pipe(
switchMap((closeTx) => {
const domain = domains?.find((domain) => domain.isActive && domain.hasDeployedLp)
const updateTokenPrices = domain
? Object.entries(domain.liquidityPools).flatMap(([tid, poolsByCurrency]) => {
return domain.currencies
.filter((cur) => !!poolsByCurrency[cur.address])
.map((cur) => [tid, cur.key] satisfies [string, CurrencyKey])
.map(([tid, curKey]) =>
cent.liquidityPools.updateTokenPrice([poolId, tid, curKey, domain.chainId], { batch: true })
)
})
: []

return combineLatest([cent.pools.closeEpoch([poolId, false], { batch: true }), ...updateTokenPrices]).pipe(
switchMap(([closeTx, ...updateTokenPricesTxs]) => {
const [values] = args
const batch = [
...values.feed
Expand All @@ -103,6 +117,7 @@ export function NavManagementAssetTable({ poolId }: { poolId: string }) {
}),
api.tx.oraclePriceCollection.updateCollection(poolId),
api.tx.loans.updatePortfolioValuation(poolId),
...updateTokenPricesTxs,
]

if (liquidityAdminAccount && orders?.length) {
Expand Down
16 changes: 13 additions & 3 deletions centrifuge-app/src/utils/tinlake/useEvmTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { TransactionRequest, TransactionResponse } from '@ethersproject/providers'
import * as React from 'react'
import { Observable, lastValueFrom, tap } from 'rxjs'
import { useGmp } from '../useGmp'

export function useEvmTransaction<T extends Array<any>>(
title: string,
Expand All @@ -26,8 +27,14 @@ export function useEvmTransaction<T extends Array<any>>(
const centrifuge = useCentrifuge()
const provider = useEvmProvider()
const pendingTransaction = React.useRef<{ id: string; args: T; options?: TransactionRequest }>()
const { setGmpHash, gmpHash } = useGmp()

async function doTransaction(id: string, args: T, txOptions?: TransactionRequest) {
async function doTransaction(
id: string,
args: T,
txOptions?: TransactionRequest,
gmpOptions?: { poolId: string; trancheId: string }
) {
try {
const signer = provider!.getSigner()
const connectedCent = centrifuge.connectEvm(selectedAddress!, signer)
Expand All @@ -36,6 +43,9 @@ export function useEvmTransaction<T extends Array<any>>(
const lastResult = await lastValueFrom(
transaction(args, txOptions).pipe(
tap((result) => {
if (!gmpHash && gmpOptions) {
setGmpHash(result.hash, gmpOptions.poolId, gmpOptions.trancheId, selectedAddress!)
}
updateTransaction(id, { status: 'pending', hash: result.hash })
})
)
Expand All @@ -50,7 +60,7 @@ export function useEvmTransaction<T extends Array<any>>(
}
}

function execute(args: T, options?: TransactionRequest) {
function execute(args: T, options?: TransactionRequest, gmp?: { poolId: string; trancheId: string }) {
const id = Math.random().toString(36).substring(2)
const tx: Transaction = {
id,
Expand All @@ -66,7 +76,7 @@ export function useEvmTransaction<T extends Array<any>>(
pendingTransaction.current = { id, args, options }
showWallets(chainId ?? 1)
} else {
doTransaction(id, args, options)
doTransaction(id, args, options, gmp)
}
return id
}
Expand Down
Loading

0 comments on commit 75d1314

Please sign in to comment.