From 077f923182630fae8b1137840a0cdba108d01ada Mon Sep 17 00:00:00 2001 From: Onno Visser Date: Tue, 23 Jul 2024 11:12:01 +0200 Subject: [PATCH 1/9] Nav Management: Include pending fees in nav total (#2301) --- .../src/pages/NavManagement/NavManagementAssetTable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/centrifuge-app/src/pages/NavManagement/NavManagementAssetTable.tsx b/centrifuge-app/src/pages/NavManagement/NavManagementAssetTable.tsx index ef4dc2670..99e395164 100644 --- a/centrifuge-app/src/pages/NavManagement/NavManagementAssetTable.tsx +++ b/centrifuge-app/src/pages/NavManagement/NavManagementAssetTable.tsx @@ -187,7 +187,7 @@ export function NavManagementAssetTable({ poolId }: { poolId: string }) { 0 ) const newNavCash = cashLoans.reduce((acc, cur) => acc + cur.outstandingDebt.toFloat(), 0) - const newNav = newNavExternal + newNavCash + poolReserve + const newNav = newNavExternal + newNavCash + poolReserve - pendingFees.toFloat() // Only for single tranche pools const newPrice = newNav / pool.tranches[0].totalIssuance.toFloat() const isTinlakePool = poolId.startsWith('0x') @@ -300,7 +300,7 @@ export function NavManagementAssetTable({ poolId }: { poolId: string }) { current={pool.nav.total.toFloat()} change={newNav - pool.nav.total.toFloat()} pendingFees={pendingFees.toFloat()} - pendingNav={newNav - pendingFees.toFloat()} + pendingNav={newNav} /> {pool.tranches.length === 1 && ( From cede9eb20dfca101a33f0d5224e9fc179e29ba28 Mon Sep 17 00:00:00 2001 From: Katty Barroso <51223655+kattylucy@users.noreply.github.com> Date: Tue, 23 Jul 2024 09:25:32 -0500 Subject: [PATCH 2/9] Use evm inputs for issuers (#2226) * Add EVM input to components * Throw error --- .../components/PoolFees/EditFeesDrawer.tsx | 32 +++++++------------ .../IssuerPool/Access/AssetOriginators.tsx | 11 +++++-- .../pages/IssuerPool/Access/MultisigForm.tsx | 8 +++-- .../Configuration/AddAddressInput.tsx | 32 +++++++++++++------ .../IssuerPool/Investors/InvestorStatus.tsx | 13 ++++---- centrifuge-js/src/utils/index.ts | 2 ++ fabric/src/components/TextInput/index.tsx | 22 +++++++++---- 7 files changed, 72 insertions(+), 48 deletions(-) diff --git a/centrifuge-app/src/components/PoolFees/EditFeesDrawer.tsx b/centrifuge-app/src/components/PoolFees/EditFeesDrawer.tsx index ec9fd78b8..3fa55b252 100644 --- a/centrifuge-app/src/components/PoolFees/EditFeesDrawer.tsx +++ b/centrifuge-app/src/components/PoolFees/EditFeesDrawer.tsx @@ -1,13 +1,12 @@ -import { AddFee, PoolMetadata, Rate } from '@centrifuge/centrifuge-js' -import { useCentrifugeTransaction } from '@centrifuge/centrifuge-react' +import { AddFee, PoolMetadata, Rate, evmToSubstrateAddress } from '@centrifuge/centrifuge-js' +import { useCentEvmChainId, useCentrifugeTransaction } from '@centrifuge/centrifuge-react' import { + AddressInput, Box, Button, Drawer, Flex, Grid, - IconButton, - IconCopy, IconMinusCircle, IconPlusCircle, NumberInput, @@ -22,11 +21,11 @@ import React from 'react' import { useParams } from 'react-router' import { feeCategories } from '../../config' import { Dec } from '../../utils/Decimal' -import { copyToClipboard } from '../../utils/copyToClipboard' +import { isEvmAddress } from '../../utils/address' import { formatPercentage } from '../../utils/formatting' import { usePoolAdmin, useSuitableAccounts } from '../../utils/usePermissions' import { usePool, usePoolFees, usePoolMetadata } from '../../utils/usePools' -import { combine, max, positiveNumber, required, substrateAddress } from '../../utils/validation' +import { combine, max, positiveNumber, required } from '../../utils/validation' import { ButtonGroup } from '../ButtonGroup' type ChargeFeesProps = { @@ -54,6 +53,7 @@ export const EditFeesDrawer = ({ onClose, isOpen }: ChargeFeesProps) => { const { data: poolMetadata, isLoading } = usePoolMetadata(pool) const poolAdmin = usePoolAdmin(poolId) const account = useSuitableAccounts({ poolId, poolRole: ['PoolAdmin'] })[0] + const chainId = useCentEvmChainId() const initialFormData = React.useMemo(() => { return poolFees @@ -116,11 +116,14 @@ export const EditFeesDrawer = ({ onClose, isOpen }: ChargeFeesProps) => { ) }) .map((fee) => { + const destination = isEvmAddress(fee.receivingAddress) + ? evmToSubstrateAddress(fee.receivingAddress, chainId) + : fee.receivingAddress return { poolId, fee: { name: fee.feeName, - destination: fee.receivingAddress, + destination, amount: Rate.fromPercent(Dec(fee?.percentOfNav || 0)), feeId: fee.feeId, feeType: fee.type, @@ -278,24 +281,13 @@ export const EditFeesDrawer = ({ onClose, isOpen }: ChargeFeesProps) => { - + {({ field, meta }: FieldProps) => { return ( - copyToClipboard(values.receivingAddress)} - title="Copy address to clipboard" - > - - - } errorMessage={(meta.touched && meta.error) || ''} /> ) diff --git a/centrifuge-app/src/pages/IssuerPool/Access/AssetOriginators.tsx b/centrifuge-app/src/pages/IssuerPool/Access/AssetOriginators.tsx index 8032c501d..6e6a77a9c 100644 --- a/centrifuge-app/src/pages/IssuerPool/Access/AssetOriginators.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Access/AssetOriginators.tsx @@ -1,6 +1,7 @@ import { addressToHex, computeTrancheId, + evmToSubstrateAddress, getCurrencyLocation, isSameAddress, PoolMetadata, @@ -8,6 +9,7 @@ import { WithdrawAddress, } from '@centrifuge/centrifuge-js' import { + useCentEvmChainId, useCentrifuge, useCentrifugeApi, useCentrifugeConsts, @@ -118,6 +120,7 @@ function AOForm({ poolId: string }) { const [isEditing, setIsEditing] = React.useState(false) + const chainId = useCentEvmChainId() const [account] = useSuitableAccounts({ poolId, actingAddress: [ao.address] }).filter((a) => a.proxies?.length === 2) const identity = useIdentity(ao.address) const api = useCentrifugeApi() @@ -311,8 +314,8 @@ function AOForm({ } execute( [ - addedWithdraw.map((w) => getKeyForReceiver(api, w)), - removedWithdraw.map((w) => getKeyForReceiver(api, w)), + addedWithdraw.filter((w) => Object.keys(w).length !== 0).map((w) => getKeyForReceiver(api, w)), + removedWithdraw.filter((w) => Object.keys(w).length !== 0).map((w) => getKeyForReceiver(api, w)), null, addedPermissions, addedDelegates, @@ -438,7 +441,9 @@ function AOForm({ { - fldArr.push(addressToHex(address)) + fldArr.push( + isEvmAddress(address) ? evmToSubstrateAddress(address, chainId ?? 0) : addressToHex(address) + ) }} /> )} diff --git a/centrifuge-app/src/pages/IssuerPool/Access/MultisigForm.tsx b/centrifuge-app/src/pages/IssuerPool/Access/MultisigForm.tsx index 248839063..0f39d9fd6 100644 --- a/centrifuge-app/src/pages/IssuerPool/Access/MultisigForm.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Access/MultisigForm.tsx @@ -1,16 +1,20 @@ -import { addressToHex } from '@centrifuge/centrifuge-js' +import { evmToSubstrateAddress } from '@centrifuge/centrifuge-js' +import { useCentEvmChainId } from '@centrifuge/centrifuge-react' import { Button, IconMinusCircle, Stack, Text } from '@centrifuge/fabric' import { FieldArray, useFormikContext } from 'formik' import * as React from 'react' import { DataTable } from '../../../components/DataTable' import { Identity } from '../../../components/Identity' +import { isEvmAddress } from '../../../utils/address' import { AddAddressInput } from '../Configuration/AddAddressInput' import { ChangeThreshold } from './ChangeTreshold' import type { PoolManagersInput } from './PoolManagers' type Row = { address: string; index: number } type Props = { isEditing?: boolean; isLoading?: boolean; canRemoveFirst?: boolean } + export function MultisigForm({ isEditing = true, canRemoveFirst = true, isLoading }: Props) { + const chainId = useCentEvmChainId() const form = useFormikContext() const { adminMultisig } = form.values const rows = React.useMemo( @@ -66,7 +70,7 @@ export function MultisigForm({ isEditing = true, canRemoveFirst = true, isLoadin if (adminMultisig.signers.length === 1) { form.setFieldValue('adminMultisig.threshold', 2, false) } - fldArr.push(addressToHex(address)) + fldArr.push(isEvmAddress(address) ? evmToSubstrateAddress(address, chainId ?? 0) : address) }} /> )} diff --git a/centrifuge-app/src/pages/IssuerPool/Configuration/AddAddressInput.tsx b/centrifuge-app/src/pages/IssuerPool/Configuration/AddAddressInput.tsx index 20d10c918..6c7009f4f 100644 --- a/centrifuge-app/src/pages/IssuerPool/Configuration/AddAddressInput.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Configuration/AddAddressInput.tsx @@ -1,6 +1,6 @@ -import { isSameAddress } from '@centrifuge/centrifuge-js' +import { addressToHex, isSameAddress } from '@centrifuge/centrifuge-js' import { useCentrifugeUtils } from '@centrifuge/centrifuge-react' -import { Button, Grid, SearchInput, Shelf, Text } from '@centrifuge/fabric' +import { AddressInput, Button, Grid, Shelf, Text } from '@centrifuge/fabric' import Identicon from '@polkadot/react-identicon' import { useState } from 'react' import { truncate } from '../../../utils/web3' @@ -15,26 +15,40 @@ export function AddAddressInput({ const [address, setAddress] = useState('') const utils = useCentrifugeUtils() - let truncated + let truncated: string | undefined try { truncated = truncate(utils.formatAddress(address)) } catch (e) { - // + truncated = undefined } const exists = !!truncated && existingAddresses.some((addr) => isSameAddress(addr, address)) + function handleChange(e: React.ChangeEvent) { + const newAddress = e.target.value + setAddress(newAddress) + } + + function handleBlur(e: React.FocusEvent) { + const address = e.target.value + if (truncated) { + onAdd(addressToHex(address)) + setAddress('') + } + } + return ( - setAddress(e.target.value)} + onChange={handleChange} + onBlur={handleBlur} /> {address && (truncated ? ( - + @@ -44,7 +58,7 @@ export function AddAddressInput({