From 3ce899ad26399a93656b42e0905cffaeb0bafeed Mon Sep 17 00:00:00 2001 From: sophian Date: Wed, 31 Jul 2024 17:55:29 -0400 Subject: [PATCH] Clean up and fix form submissions --- .../src/pages/Loan/ExternalFinanceForm.tsx | 60 ++++++++++--------- .../src/pages/Loan/ExternalRepayForm.tsx | 36 ++++++----- centrifuge-app/src/pages/Loan/FinanceForm.tsx | 2 +- centrifuge-app/src/pages/Loan/RepayForm.tsx | 29 ++++----- .../src/pages/Loan/SourceSelect.tsx | 2 +- centrifuge-js/src/modules/pools.ts | 6 +- 6 files changed, 71 insertions(+), 64 deletions(-) diff --git a/centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx b/centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx index c7d2cd14b..dcb3a67cd 100644 --- a/centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx +++ b/centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx @@ -9,6 +9,7 @@ import { } from '@centrifuge/centrifuge-js' import { useCentrifugeApi, useCentrifugeTransaction, wrapProxyCallsForAccount } from '@centrifuge/centrifuge-react' import { Box, Button, CurrencyInput, InlineFeedback, Shelf, Stack, Text } from '@centrifuge/fabric' +import { BN } from 'bn.js' import Decimal from 'decimal.js-light' import { Field, FieldProps, Form, FormikProvider, useFormik } from 'formik' import * as React from 'react' @@ -42,32 +43,38 @@ export function ExternalFinanceForm({ loan, source }: { loan: ExternalLoan; sour const sourceLoan = loans?.find((l) => l.id === source) as CreatedLoan | ActiveLoan const { execute: doFinanceTransaction, isLoading: isFinanceLoading } = useCentrifugeTransaction( 'Purchase asset', - (cent) => - ( - args: [poolId: string, loanId: string, quantity: Price, price: CurrencyBalance, interest: CurrencyBalance], - options - ) => { - if (!account) throw new Error('No borrower') - const [poolId, loanId, quantity, price, interest] = args - let financeTx - if (source === 'reserve') { - financeTx = cent.pools.financeExternalLoan([poolId, loanId, quantity, price], { batch: true }) - } else { - const repay = { quantity, price, interest } - let borrow = { quantity: quantity, price } - financeTx = cent.pools.transferLoanDebt([poolId, sourceLoan.id, loan.id, repay, borrow], { batch: true }) - } - return combineLatest([financeTx, withdraw.getBatch(financeForm), poolFees.getBatch(financeForm)]).pipe( - switchMap(([loanTx, withdrawBatch, poolFeesBatch]) => { - let batch = [...withdrawBatch, ...poolFeesBatch] - let tx = wrapProxyCallsForAccount(api, loanTx, account, 'Borrow') - if (batch.length) { - tx = api.tx.utility.batchAll([tx, ...batch]) - } - return cent.wrapSignAndSend(api, tx, { ...options, proxies: undefined }) - }) + (cent) => (args: [poolId: string, loanId: string, quantity: Price, price: CurrencyBalance], options) => { + if (!account) throw new Error('No borrower') + const [poolId, loanId, quantity, price] = args + let financeTx + if (source === 'reserve') { + financeTx = cent.pools.financeExternalLoan([poolId, loanId, quantity, price], { batch: true }) + } else { + const principal = new CurrencyBalance( + price.toDecimal().mul(quantity.toDecimal()).toString(), + pool.currency.decimals ) - }, + const repay = { principal, interest: new BN(0), unscheduled: new BN(0) } + const borrow = { + quantity, + price, + interest: new BN(0), + unscheduled: new BN(0), + } + // TODO: Fix TransferDebtAmountMismatched + financeTx = cent.pools.transferLoanDebt([poolId, sourceLoan.id, loan.id, repay, borrow], { batch: true }) + } + return combineLatest([financeTx, withdraw.getBatch(financeForm), poolFees.getBatch(financeForm)]).pipe( + switchMap(([loanTx, withdrawBatch, poolFeesBatch]) => { + let batch = [...withdrawBatch, ...poolFeesBatch] + let tx = wrapProxyCallsForAccount(api, loanTx, account, 'Borrow') + if (batch.length) { + tx = api.tx.utility.batchAll([tx, ...batch]) + } + return cent.wrapSignAndSend(api, tx, { ...options, proxies: undefined }) + }) + ) + }, { onSuccess: () => { financeForm.resetForm() @@ -85,8 +92,7 @@ export function ExternalFinanceForm({ loan, source }: { loan: ExternalLoan; sour onSubmit: (values, actions) => { const price = CurrencyBalance.fromFloat(values.price, pool.currency.decimals) const quantity = Price.fromFloat(values.quantity) - const interest = new CurrencyBalance(0, pool.currency.decimals) - doFinanceTransaction([loan.poolId, loan.id, quantity, price, interest], { + doFinanceTransaction([loan.poolId, loan.id, quantity, price], { account, }) actions.setSubmitting(false) diff --git a/centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx b/centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx index ba541d27f..b5b644c24 100644 --- a/centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx +++ b/centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx @@ -34,37 +34,41 @@ export function ExternalRepayForm({ loan, destination }: { loan: ExternalLoan; d const destinationLoan = loans?.find((l) => l.id === destination) as ActiveLoan const { execute: doRepayTransaction, isLoading: isRepayLoading } = useCentrifugeTransaction( - 'Repay asset', + 'Sell asset', (cent) => ( - args: [ - loanId: string, - poolId: string, - quantity: Price, - interest: CurrencyBalance, - amountAdditional: CurrencyBalance, - price: CurrencyBalance - ], + args: [quantity: Price, interest: CurrencyBalance, amountAdditional: CurrencyBalance, price: CurrencyBalance], options ) => { - const [loanId, poolId, quantity, interest, amountAdditional, price] = args + const [quantity, interest, amountAdditional, price] = args let repayTx if (destination === 'reserve') { repayTx = cent.pools.repayExternalLoanPartially( - [poolId, loanId, quantity, interest, amountAdditional, price], + [pool.id, loan.id, quantity, interest, amountAdditional, price], { batch: true, } ) } else { - const repay = { quantity, price, interest } - let borrow = { quantity, price } - repayTx = cent.pools.transferLoanDebt([poolId, loan.id, destinationLoan.id, repay, borrow], { batch: true }) + const repay = { quantity, price, interest, unscheduled: amountAdditional } + let borrow = { + amount: new CurrencyBalance( + quantity + .toDecimal() + .mul(price.toDecimal()) + .add(interest.toDecimal()) + .add(amountAdditional.toDecimal()) + .toString(), + pool.currency.decimals + ), + } + // TODO: Fix TransferDebtAmountMismatched + repayTx = cent.pools.transferLoanDebt([pool.id, loan.id, destinationLoan.id, repay, borrow], { batch: true }) } return combineLatest([cent.getApi(), repayTx, poolFees.getBatch(repayForm)]).pipe( switchMap(([api, repayTx, batch]) => { if (batch.length) { - return cent.wrapSignAndSend(api, api.tx.utility.batchAll([repayTx, ...batch], options)) + return cent.wrapSignAndSend(api, api.tx.utility.batchAll([repayTx, ...batch]), options) } return cent.wrapSignAndSend(api, repayTx, options) }) @@ -101,7 +105,7 @@ export function ExternalRepayForm({ loan, destination }: { loan: ExternalLoan; d const amountAdditional = CurrencyBalance.fromFloat(values.amountAdditional || 0, pool.currency.decimals) const quantity = Price.fromFloat(values.quantity || 0) - doRepayTransaction([loan.poolId, loan.id, quantity, interest, amountAdditional, price], { + doRepayTransaction([quantity, interest, amountAdditional, price], { account, }) actions.setSubmitting(false) diff --git a/centrifuge-app/src/pages/Loan/FinanceForm.tsx b/centrifuge-app/src/pages/Loan/FinanceForm.tsx index b19c8f876..915740261 100644 --- a/centrifuge-app/src/pages/Loan/FinanceForm.tsx +++ b/centrifuge-app/src/pages/Loan/FinanceForm.tsx @@ -112,7 +112,7 @@ function InternalFinanceForm({ loan, source }: { loan: LoanType; source: string const categoryHex = Buffer.from(financeForm.values.category).toString('hex') financeTx = cent.wrapSignAndSend(api, api.tx.remarks.remark([{ Named: categoryHex }], tx), { batch: true }) } else { - const repay = { principal, interest: new BN(0) } + const repay = { principal, interest: new BN(0), unscheduled: new BN(0) } let borrow = { amount: principal } financeTx = cent.pools.transferLoanDebt([poolId, sourceLoan.id, loan.id, repay, borrow], { batch: true }) } diff --git a/centrifuge-app/src/pages/Loan/RepayForm.tsx b/centrifuge-app/src/pages/Loan/RepayForm.tsx index 68e9a2565..45f70eefc 100644 --- a/centrifuge-app/src/pages/Loan/RepayForm.tsx +++ b/centrifuge-app/src/pages/Loan/RepayForm.tsx @@ -69,31 +69,26 @@ function InternalRepayForm({ loan, destination }: { loan: ActiveLoan; destinatio const { execute: doRepayTransaction, isLoading: isRepayLoading } = useCentrifugeTransaction( isCashLoan(loan) ? 'Withdraw funds' : 'Repay asset', (cent) => - ( - args: [ - loanId: string, - poolId: string, - principal: CurrencyBalance, - interest: CurrencyBalance, - amountAdditional: CurrencyBalance - ], - options - ) => { - const [loanId, poolId, principal, interest, amountAdditional] = args + (args: [principal: CurrencyBalance, interest: CurrencyBalance, amountAdditional: CurrencyBalance], options) => { + const [principal, interest, amountAdditional] = args let repayTx if (destination === 'reserve') { - repayTx = cent.pools.repayLoanPartially([loanId, poolId, principal, interest, amountAdditional], { + repayTx = cent.pools.repayLoanPartially([pool.id, loan.id, principal, interest, amountAdditional], { batch: true, }) } else if (destination === 'other') { if (!repayForm.values.category) throw new Error('No category selected') - const tx = api.tx.loans.decreaseDebt(poolId, loan.id, { internal: principal }) + const tx = api.tx.loans.decreaseDebt(pool.id, loan.id, { internal: principal }) const categoryHex = Buffer.from(repayForm.values.category).toString('hex') repayTx = cent.wrapSignAndSend(api, api.tx.remarks.remark([{ Named: categoryHex }], tx), { batch: true }) } else { - const repay = { principal, interest } - let borrow = { amount: principal } - repayTx = cent.pools.transferLoanDebt([poolId, loan.id, destinationLoan.id, repay, borrow], { batch: true }) + const repay = { principal, interest, unscheduled: amountAdditional } + const borrowAmount = new CurrencyBalance( + principal.add(interest).add(amountAdditional), + pool.currency.decimals + ) + let borrow = { amount: borrowAmount } + repayTx = cent.pools.transferLoanDebt([pool.id, loan.id, destinationLoan.id, repay, borrow], { batch: true }) } return combineLatest([cent.getApi(), repayTx, poolFees.getBatch(repayForm)]).pipe( switchMap(([api, repayTx, batch]) => { @@ -129,7 +124,7 @@ function InternalRepayForm({ loan, destination }: { loan: ActiveLoan; destinatio const additionalAmount = CurrencyBalance.fromFloat(values.amountAdditional || 0, pool.currency.decimals) const principal = CurrencyBalance.fromFloat(values.principal || 0, pool.currency.decimals) - doRepayTransaction([loan.poolId, loan.id, principal, interest, additionalAmount], { + doRepayTransaction([principal, interest, additionalAmount], { account, forceProxyType: 'Borrow', }) diff --git a/centrifuge-app/src/pages/Loan/SourceSelect.tsx b/centrifuge-app/src/pages/Loan/SourceSelect.tsx index cb5f0636d..b3f010cb9 100644 --- a/centrifuge-app/src/pages/Loan/SourceSelect.tsx +++ b/centrifuge-app/src/pages/Loan/SourceSelect.tsx @@ -8,7 +8,7 @@ import { useBorrower } from '../../utils/usePermissions' type SourceSelectProps = { loan: Loan - value: string + value: 'reserve' | 'other' | string onChange: (option: string) => void action: 'repay' | 'finance' } diff --git a/centrifuge-js/src/modules/pools.ts b/centrifuge-js/src/modules/pools.ts index 5005650bc..5fa362aed 100644 --- a/centrifuge-js/src/modules/pools.ts +++ b/centrifuge-js/src/modules/pools.ts @@ -1844,7 +1844,9 @@ export function getPoolsModule(inst: Centrifuge) { poolId: string, fromLoanId: string, toLoanId: string, - repay: { principal: BN; interest: BN } | { quantity: BN; price: BN; interest: BN }, + repay: + | { principal: BN; interest: BN; unscheduled: BN } + | { quantity: BN; price: BN; interest: BN; unscheduled: BN }, borrow: { quantity: BN; price: BN } | { amount: BN } ], options?: TransactionOptions @@ -1863,7 +1865,7 @@ export function getPoolsModule(inst: Centrifuge) { ? { external: { quantity: repay.quantity.toString(), settlementPrice: repay.price.toString() } } : { internal: repay.principal.toString() }, interest: repay.interest.toString(), - unscheduled: '0', + unscheduled: repay.unscheduled.toString(), }, 'amount' in borrow ? { internal: borrow.amount.toString() }