Skip to content

Commit

Permalink
Merge branch 'main' into loan-refactor-v3
Browse files Browse the repository at this point in the history
  • Loading branch information
onnovisser authored Aug 4, 2023
2 parents f2fe692 + 7bb540a commit d0015b2
Show file tree
Hide file tree
Showing 53 changed files with 602 additions and 310 deletions.
45 changes: 33 additions & 12 deletions centrifuge-app/src/components/OnboardingAuthProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Centrifuge from '@centrifuge/centrifuge-js'
import { useCentrifuge, useEvmProvider, useWallet } from '@centrifuge/centrifuge-react'
import { hexToU8a } from '@polkadot/util'
import { encodeAddress } from '@polkadot/util-crypto'
import { Wallet } from '@subwallet/wallet-connect/types'
import * as React from 'react'
import { useMutation, useQuery } from 'react-query'
Expand All @@ -13,24 +15,30 @@ export const OnboardingAuthContext = React.createContext<{
const AUTHORIZED_ONBOARDING_PROXY_TYPES = ['Any', 'Invest', 'NonTransfer', 'NonProxy']

export function OnboardingAuthProvider({ children }: { children: React.ReactNode }) {
const { selectedWallet, selectedProxies, selectedAccount } = useWallet().substrate
const { selectedAddress } = useWallet().evm
const {
substrate: { selectedWallet, selectedProxies, selectedAccount, evmChainId },
evm: { selectedAddress },
isEvmOnSubstrate,
} = useWallet()
const cent = useCentrifuge()
const provider = useEvmProvider()
const walletAddress = selectedAccount?.address ?? selectedAddress
// onboarding-api expects the wallet address in the native substrate format
const address = selectedAccount?.address
? encodeAddress(hexToU8a(selectedAccount?.address), cent.getChainId())
: selectedAddress
const proxy = selectedProxies?.[0]

const { data: session, refetch: refetchSession } = useQuery(
['session', selectedAccount?.address, proxy?.delegator, selectedAddress],
() => {
if (selectedAccount?.address || selectedAddress) {
if (address) {
if (proxy) {
const rawItem = sessionStorage.getItem(`centrifuge-onboarding-auth-${walletAddress}-${proxy.delegator}`)
const rawItem = sessionStorage.getItem(`centrifuge-onboarding-auth-${address}-${proxy.delegator}`)
if (rawItem) {
return JSON.parse(rawItem)
}
} else {
const rawItem = sessionStorage.getItem(`centrifuge-onboarding-auth-${walletAddress}`)
const rawItem = sessionStorage.getItem(`centrifuge-onboarding-auth-${address}`)
if (rawItem) {
return JSON.parse(rawItem)
}
Expand All @@ -44,9 +52,12 @@ export function OnboardingAuthProvider({ children }: { children: React.ReactNode
try {
if (selectedAccount?.address && selectedWallet?.signer) {
await loginWithSubstrate(selectedAccount?.address, selectedWallet.signer, cent, proxy)
} else if (isEvmOnSubstrate && selectedAddress && provider?.getSigner()) {
await loginWithEvm(selectedAddress, provider.getSigner(), evmChainId)
} else if (selectedAddress && provider?.getSigner()) {
await loginWithEvm(selectedAddress, provider.getSigner())
}
throw new Error('network not supported')
} catch {
} finally {
refetchSession()
Expand Down Expand Up @@ -95,8 +106,10 @@ export function useOnboardingAuth() {
const verified = (await verifiedRes.json()).verified
return { verified }
}
sessionStorage.clear()
return { verified: false }
} catch (error) {
sessionStorage.clear()
return {
verified: false,
}
Expand All @@ -118,7 +131,9 @@ export function useOnboardingAuth() {
}
}

const loginWithSubstrate = async (address: string, signer: Wallet['signer'], cent: Centrifuge, proxy?: any) => {
const loginWithSubstrate = async (hexAddress: string, signer: Wallet['signer'], cent: Centrifuge, proxy?: any) => {
// onboarding-api expects the wallet address in the native substrate format
const address = encodeAddress(hexToU8a(hexAddress), cent.getChainId())
const nonceRes = await fetch(`${import.meta.env.REACT_APP_ONBOARDING_API_URL}/nonce`, {
method: 'POST',
headers: {
Expand All @@ -144,7 +159,7 @@ const loginWithSubstrate = async (address: string, signer: Wallet['signer'], cen
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({ jw3t: token, nonce }),
body: JSON.stringify({ jw3t: token, nonce, network: 'substrate' }),
})
if (authTokenRes.status !== 200) {
throw new Error('Failed to authenticate wallet')
Expand All @@ -168,7 +183,7 @@ const loginWithSubstrate = async (address: string, signer: Wallet['signer'], cen
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({ jw3t: token, nonce }),
body: JSON.stringify({ jw3t: token, nonce, network: 'substrate' }),
})
if (authTokenRes.status !== 200) {
throw new Error('Failed to authenticate wallet')
Expand All @@ -183,7 +198,7 @@ const loginWithSubstrate = async (address: string, signer: Wallet['signer'], cen
}
}

const loginWithEvm = async (address: string, signer: any) => {
const loginWithEvm = async (address: string, signer: any, evmChainId?: number) => {
const nonceRes = await fetch(`${import.meta.env.REACT_APP_ONBOARDING_API_URL}/nonce`, {
method: 'POST',
headers: {
Expand All @@ -203,7 +218,7 @@ Please sign to authenticate your wallet
URI: ${origin}
Version: 1
Chain ID: ${import.meta.env.REACT_APP_TINLAKE_NETWORK === 'mainnet' ? 1 : 5 /* goerli */}
Chain ID: ${evmChainId ? evmChainId : import.meta.env.REACT_APP_TINLAKE_NETWORK === 'mainnet' ? 1 : 5 /* goerli */}
Nonce: ${nonce}
Issued At: ${new Date().toISOString()}`

Expand All @@ -214,7 +229,13 @@ Issued At: ${new Date().toISOString()}`
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({ message, signature: signedMessage, address, nonce }),
body: JSON.stringify({
message,
signature: signedMessage,
address,
nonce,
network: evmChainId ? 'evmOnSubstrate' : 'evm',
}),
})
if (tokenRes.status !== 200) {
throw new Error('Failed to authenticate wallet')
Expand Down
2 changes: 2 additions & 0 deletions centrifuge-app/src/components/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { Head } from './Head'
import { LoadBoundary } from './LoadBoundary'
import { OnboardingAuthProvider } from './OnboardingAuthProvider'
import { OnboardingProvider } from './OnboardingProvider'
import { SupportedBrowserBanner } from './SupportedBrowserBanner'

const queryClient = new QueryClient({
defaultOptions: {
Expand Down Expand Up @@ -118,6 +119,7 @@ export function Root() {
<FabricGlobalStyle />
<CentrifugeProvider config={centConfig}>
<DemoBanner />
<SupportedBrowserBanner />
<WalletProvider
evmChains={evmChains}
subscanUrl={import.meta.env.REACT_APP_SUBSCAN_URL}
Expand Down
34 changes: 34 additions & 0 deletions centrifuge-app/src/components/SupportedBrowserBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Banner, Text } from '@centrifuge/fabric'
import * as React from 'react'

export const SupportedBrowserBanner = () => {
const storageKey = 'browser-banner-seen'
const isSupported = navigator.userAgent.indexOf('Chrome') > -1
const [isOpen, setIsOpen] = React.useState(false)

React.useEffect(() => {
setIsOpen(localStorage.getItem(storageKey) !== 'true')
}, [])

function onClose() {
localStorage.setItem(storageKey, 'true')
setIsOpen(false)
}

if (isSupported) {
return null
}

return (
<Banner
isOpen={isOpen}
onClose={() => onClose()}
title={
<Text as="h3" color="textInverted" variant="heading5">
Change your browser for a fully supported experience. Centrifuge App supports Chromium web browsers (Brave,
Google Chrome or Opera).
</Text>
}
/>
)
}
4 changes: 4 additions & 0 deletions centrifuge-app/src/components/Tooltips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ const tooltipText = {
label: 'Issuer representive name',
body: 'This is the full legal name of the authorized representive of the pool.',
},
appliedWriteOff: {
label: 'Applied write-off',
body: 'The applied write-off is the amount of the outstanding financing that has been written off by the issuer.',
},
}

export type TooltipsProps = {
Expand Down
32 changes: 31 additions & 1 deletion centrifuge-app/src/pages/Loan/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Thumbnail,
truncate,
} from '@centrifuge/fabric'
import BN from 'bn.js'
import * as React from 'react'
import { useHistory, useParams, useRouteMatch } from 'react-router'
import { Identity } from '../../components/Identity'
Expand Down Expand Up @@ -165,8 +166,37 @@ const Loan: React.FC<{ setShowOraclePricing?: () => void }> = ({ setShowOraclePr
{
label: <Tooltips type="outstanding" />,
value:
'outstandingDebt' in loan ? formatBalance(loan.outstandingDebt, pool?.currency.symbol) : 'n/a',
'outstandingDebt' in loan
? isTinlakePool && 'writeOffPercentage' in loan
? formatBalance(
new CurrencyBalance(
loan.outstandingDebt.sub(
loan.outstandingDebt.mul(new BN(loan.writeOffPercentage).div(new BN(100)))
),
pool.currency.decimals
),
pool?.currency.symbol
)
: formatBalance(loan.outstandingDebt, pool?.currency.symbol)
: 'n/a',
},
...(isTinlakePool
? [
{
label: <Tooltips type="appliedWriteOff" />,
value:
'writeOffPercentage' in loan
? formatBalance(
new CurrencyBalance(
loan.outstandingDebt.mul(new BN(loan.writeOffPercentage).div(new BN(100))),
pool.currency.decimals
),
pool?.currency.symbol
)
: 'n/a',
},
]
: []),
]
}
/>
Expand Down
4 changes: 2 additions & 2 deletions centrifuge-app/src/pages/Onboarding/ApprovalStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ export const ApprovalStatus = ({ signedAgreementUrl }: Props) => {
const trancheId = pool.trancheId
const poolName = pool.name

const onboardingStatus = onboardingUser?.poolSteps?.[poolId]?.[trancheId].status?.status
const onboardingStatus = onboardingUser?.poolSteps?.[poolId]?.[trancheId]?.status?.status

const onFocus = () => {
refetchOnboardingUser()
}

React.useEffect(() => {
if (
onboardingUser.poolSteps?.[poolId]?.[trancheId].status.status === 'pending' ||
onboardingUser.poolSteps?.[poolId]?.[trancheId]?.status?.status === 'pending' ||
(onboardingUser.investorType === 'entity' && onboardingUser?.manualKybStatus)
) {
window.addEventListener('focus', onFocus)
Expand Down
88 changes: 53 additions & 35 deletions centrifuge-app/src/pages/Onboarding/queries/useSignRemark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { lastValueFrom } from 'rxjs'
import { useOnboardingAuth } from '../../../components/OnboardingAuthProvider'
import { ethConfig } from '../../../config'
import { Dec } from '../../../utils/Decimal'
import { useSuitableAccounts } from '../../../utils/usePermissions'
import RemarkerAbi from './abi/Remarker.abi.json'

export const useSignRemark = (
Expand All @@ -22,6 +23,7 @@ export const useSignRemark = (
{
txHash: string
blockNumber: string
isEvmOnSubstrate?: boolean
},
unknown
>
Expand All @@ -33,64 +35,80 @@ export const useSignRemark = (
const { updateTransaction, addOrUpdateTransaction } = useTransactions()
const {
connectedType,
isEvmOnSubstrate,
substrate: { selectedAddress, selectedAccount },
} = useWallet()
const [expectedTxFee, setExpectedTxFee] = React.useState(Dec(0))
const balances = useBalances(selectedAddress || '')
const { authToken } = useOnboardingAuth()
const [account] = useSuitableAccounts({ actingAddress: [selectedAddress || ''] })

const substrateMutation = useCentrifugeTransaction('Sign remark', (cent) => cent.remark.signRemark, {
onSuccess: async (_, result) => {
const txHash = result.txHash.toHex()
// @ts-expect-error
const blockNumber = result.blockNumber.toString()
try {
await sendDocumentsToIssuer({ txHash, blockNumber })
let txHash: string
let blockNumber: string
// @ts-expect-error
if (isEvmOnSubstrate && result?.[0]?.wait) {
// @ts-expect-error
const evmResult = await result[0].wait()
txHash = evmResult?.transactionHash
blockNumber = evmResult?.blockNumber.toString()
} else {
txHash = result.txHash.toHex()
// @ts-expect-error
blockNumber = result.blockNumber.toString()
}
await sendDocumentsToIssuer({ txHash, blockNumber, isEvmOnSubstrate })
setIsSubstrateTxLoading(false)
} catch (e) {
setIsSubstrateTxLoading(false)
}
},
})

const signSubstrateRemark = async (args: [message: string]) => {
const getBalanceForSigning = async () => {
const txIdSignRemark = Math.random().toString(36).substr(2)
setIsSubstrateTxLoading(true)
if (balances?.native.balance?.toDecimal().lt(expectedTxFee.mul(1.1))) {
addOrUpdateTransaction({
id: txIdSignRemark,
title: `Get ${balances?.native.currency.symbol}`,
status: 'pending',
args: [],
})
// add just enough native currency to be able to sign remark
const response = await fetch(`${import.meta.env.REACT_APP_ONBOARDING_API_URL}/getBalanceForSigning`, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
})

if (response.status !== 201) {
addOrUpdateTransaction({
id: txIdSignRemark,
title: `Get ${balances?.native.currency.symbol}`,
status: 'pending',
args,
status: 'failed',
args: [],
})
// add just enough native currency to be able to sign remark
const response = await fetch(`${import.meta.env.REACT_APP_ONBOARDING_API_URL}/getBalanceForSigning`, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
setIsSubstrateTxLoading(false)
throw new Error('Insufficient funds')
} else {
addOrUpdateTransaction({
id: txIdSignRemark,
title: `Get ${balances?.native.currency.symbol}`,
status: 'succeeded',
args: [],
})
}
}

if (response.status !== 201) {
addOrUpdateTransaction({
id: txIdSignRemark,
title: `Get ${balances?.native.currency.symbol}`,
status: 'failed',
args,
})
setIsSubstrateTxLoading(false)
throw new Error('Insufficient funds')
} else {
addOrUpdateTransaction({
id: txIdSignRemark,
title: `Get ${balances?.native.currency.symbol}`,
status: 'succeeded',
args,
})
}
const signSubstrateRemark = async (args: [message: string]) => {
setIsSubstrateTxLoading(true)
if (!isEvmOnSubstrate && balances?.native.balance?.toDecimal().lt(expectedTxFee.mul(1.1))) {
await getBalanceForSigning()
}
substrateMutation.execute(args)
substrateMutation.execute(args, { account })
}

useEffect(() => {
Expand Down Expand Up @@ -150,7 +168,7 @@ export const useSignRemark = (
}
}

return connectedType === 'evm'
return connectedType === 'evm' && !isEvmOnSubstrate
? { execute: signEvmRemark, isLoading: isEvmTxLoading }
: { execute: signSubstrateRemark, isLoading: isSubstrateTxLoading }
}
Loading

0 comments on commit d0015b2

Please sign in to comment.