From 0b8c2263cdfd5f8281e7539a13f69f5afadcb6b2 Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Mon, 30 Oct 2023 10:21:50 -0400 Subject: [PATCH 01/11] Add ImpactMarket RWR --- packages/huma-shared/src/utils/pool.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/huma-shared/src/utils/pool.ts b/packages/huma-shared/src/utils/pool.ts index c4e4d41c..a879296e 100644 --- a/packages/huma-shared/src/utils/pool.ts +++ b/packages/huma-shared/src/utils/pool.ts @@ -66,6 +66,7 @@ export type PoolInfoType = { subgraph?: string superTokens?: { id: string; symbol: string; decimals: number }[] borrower?: string // For single borrower pools + rwrUploader?: string // For single borrower pools where receivables are uploaded by a different wallet hidden?: boolean // For pools that shouldn't be displayed in the UI order?: number // Ordering in the pool list. Null values are sorted last. disableBorrow?: boolean @@ -458,6 +459,7 @@ export const PoolContractMap: PoolContractMapType = { disableBorrow: true, detailsPage: true, borrower: '0x10FB65dc26a7aCC7CFB4eA3b6E007c8C77591486', + rwrUploader: '0x4c6388346f2a3af2d64461339a5cdd3a3d63ccf5', }, }, [POOL_NAME.ArfCreditPool1]: { From be89942d96ad1cd3b22267a6008c966864408789 Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Fri, 10 Nov 2023 11:32:06 -0500 Subject: [PATCH 02/11] Take min of pool balance or lender position for withdraw --- .../components/Lend/withdraw/2-ChooseAmount.tsx | 8 +++++++- .../src/components/Lend/withdraw/index.tsx | 15 +++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/huma-widget/src/components/Lend/withdraw/2-ChooseAmount.tsx b/packages/huma-widget/src/components/Lend/withdraw/2-ChooseAmount.tsx index 1a7013b1..08270111 100644 --- a/packages/huma-widget/src/components/Lend/withdraw/2-ChooseAmount.tsx +++ b/packages/huma-widget/src/components/Lend/withdraw/2-ChooseAmount.tsx @@ -9,18 +9,24 @@ import { ChooseAmountModal } from '../../ChooseAmountModal' type Props = { lenderPosition: BigNumber + poolBalance: BigNumber poolInfo: PoolInfoType } export function ChooseAmount({ lenderPosition, + poolBalance, poolInfo, }: Props): React.ReactElement | null { const dispatch = useAppDispatch() const { poolUnderlyingToken } = poolInfo const { symbol, decimals } = poolUnderlyingToken const [currentAmount, setCurrentAmount] = useState(0) - const withdrawableAmount = downScale(lenderPosition, decimals) + // Take the minimum of the pool balance or the lender position + const withdrawableAmountBN = lenderPosition.lt(poolBalance) + ? lenderPosition + : poolBalance + const withdrawableAmount = downScale(withdrawableAmountBN, decimals) const handleChangeAmount = useCallback( (newAmount: number) => { diff --git a/packages/huma-widget/src/components/Lend/withdraw/index.tsx b/packages/huma-widget/src/components/Lend/withdraw/index.tsx index 983cf624..677381cf 100644 --- a/packages/huma-widget/src/components/Lend/withdraw/index.tsx +++ b/packages/huma-widget/src/components/Lend/withdraw/index.tsx @@ -3,6 +3,7 @@ import { POOL_NAME, POOL_TYPE, useLenderPosition, + usePoolBalance, usePoolInfo, } from '@huma-finance/shared' import React, { useCallback, useEffect } from 'react' @@ -51,21 +52,23 @@ export function LendWithdraw({ poolType, account, ) + const [poolBalance, refreshPoolBalance] = usePoolBalance(poolName, poolType) useEffect(() => { - if (!step && lenderPosition) { + if (!step && lenderPosition && poolBalance) { dispatch(setStep(WIDGET_STEP.CheckWithdrawable)) } - }, [dispatch, lenderPosition, step]) + }, [dispatch, lenderPosition, poolBalance, step]) const handleWithdrawSuccess = useCallback( (blockNumber: number) => { refreshLenderPosition() + refreshPoolBalance() if (handleSuccess) { handleSuccess(blockNumber) } }, - [handleSuccess, refreshLenderPosition], + [handleSuccess, refreshLenderPosition, refreshPoolBalance], ) if (!poolInfo) { @@ -82,7 +85,11 @@ export function LendWithdraw({ )} {step === WIDGET_STEP.ChooseAmount && ( - + )} {step === WIDGET_STEP.Transfer && } {step === WIDGET_STEP.Done && ( From db63d6b1ac418668949abc5a9902f2d9f823c890 Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Mon, 13 Nov 2023 13:39:04 -0500 Subject: [PATCH 03/11] Cherry pick subgraph service pool stats logic --- packages/huma-sdk/API.md | 14 ++++++ .../huma-sdk/src/services/SubgraphService.ts | 50 +++++++++++++++++++ .../tests/services/SubgraphService.test.ts | 44 ++++++++++++++++ packages/huma-shared/src/utils/number.ts | 19 ++++--- 4 files changed, 120 insertions(+), 7 deletions(-) diff --git a/packages/huma-sdk/API.md b/packages/huma-sdk/API.md index f07efb6c..c9c05738 100644 --- a/packages/huma-sdk/API.md +++ b/packages/huma-sdk/API.md @@ -474,6 +474,7 @@ in Huma's pools that can be drawn down by the borrower.

* [.getCreditEventsForUser(userAddress, chainId, poolName, poolType, event)](#SubgraphService.getCreditEventsForUser) ⇒ Promise.<Array.<CreditEventPayload>> * [.getLastFactorizedAmountFromPool(userAddress, chainId, poolName, poolType)](#SubgraphService.getLastFactorizedAmountFromPool) ⇒ Promise.<number> * [.getRWReceivableInfo(userAddress, chainId, poolName, poolType, pagination)](#SubgraphService.getRWReceivableInfo) ⇒ Promise.<RealWorldReceivableInfoBase> + * [.getPoolStats(chainId, pool)](#SubgraphService.getPoolStats) ⇒ Promise.<{PoolStats}> @@ -534,6 +535,19 @@ in Huma's pools that can be drawn down by the borrower.

| poolType | POOL\_TYPE |

The type of the pool.

| | pagination | [Pagination](#Pagination) |

The pagination option.

| + + +### SubgraphService.getPoolStats(chainId, pool) ⇒ Promise.<{PoolStats}> +

Returns the pool's stats.

+ +**Kind**: static method of [SubgraphService](#SubgraphService) +**Returns**: Promise.<{PoolStats}> -

The pool's stats info.

+ +| Param | Type | Description | +| --- | --- | --- | +| chainId | number |

The ID of the chain.

| +| pool | string |

The address of the pool.

| + ## defaultWrapper() diff --git a/packages/huma-sdk/src/services/SubgraphService.ts b/packages/huma-sdk/src/services/SubgraphService.ts index 42a52e9c..20a01bfb 100644 --- a/packages/huma-sdk/src/services/SubgraphService.ts +++ b/packages/huma-sdk/src/services/SubgraphService.ts @@ -196,6 +196,55 @@ function getRWReceivableInfo( }) } +type PoolStats = { + id: string + amountCreditOriginated: number + amountCreditRepaid: number + amountCreditDefaulted: number +} + +/** + * Returns the pool's stats. + * + * @memberof SubgraphService + * @param {number} chainId - The ID of the chain. + * @param {string} pool - The address of the pool. + * @returns {Promise<{PoolStats}>} The pool's stats info. + */ +function getPoolStats( + chainId: number, + pool: string, +): Promise { + const url = PoolSubgraphMap[chainId]?.subgraph + if (!url) { + return Promise.resolve(undefined) + } + + const PoolStatsQuery = ` + query { + poolStat(id:"${pool?.toLowerCase()}") { + id + amountCreditOriginated + amountCreditRepaid + amountCreditDefaulted + } + } +` + + return requestPost<{ + errors?: unknown + data: { poolStat: PoolStats } + }>(url, JSON.stringify({ query: PoolStatsQuery }), { + withCredentials: false, + }).then((res) => { + if (res.errors) { + console.error(res.errors) + return undefined + } + return res.data.poolStat + }) +} + /** * An object that contains functions to interact with Huma's Subgraph storage. * @namespace SubgraphService @@ -205,4 +254,5 @@ export const SubgraphService = { getCreditEventsForUser, getLastFactorizedAmountFromPool, getRWReceivableInfo, + getPoolStats, } diff --git a/packages/huma-sdk/tests/services/SubgraphService.test.ts b/packages/huma-sdk/tests/services/SubgraphService.test.ts index 0341fd50..5372c7d6 100644 --- a/packages/huma-sdk/tests/services/SubgraphService.test.ts +++ b/packages/huma-sdk/tests/services/SubgraphService.test.ts @@ -192,3 +192,47 @@ describe('getRWReceivableInfo', () => { expect(result).toStrictEqual(rwreceivables) }) }) + +describe('getPoolStats', () => { + beforeEach(() => { + jest.resetAllMocks() + }) + + it('should return undefined if no subgraph url is found', async () => { + const chainId = 12 // ChainId without receivables Subgraph url + const pool = '0xc866A11cf6A3D178624Ff46B8A49202206A7c51B' + + const result = await SubgraphService.getPoolStats(chainId, pool) + expect(result).toStrictEqual(undefined) + }) + + it('should return undefined if requestPost returns error', async () => { + ;(requestPost as jest.Mock).mockResolvedValue({ errors: 'errors' }) + + const chainId = ChainEnum.Goerli + const pool = '0xc866A11cf6A3D178624Ff46B8A49202206A7c51B' + + const result = await SubgraphService.getPoolStats(chainId, pool) + expect(result).toStrictEqual(undefined) + }) + + it('should return pool stats', async () => { + const pool = '0xc866A11cf6A3D178624Ff46B8A49202206A7c51B' + const poolStats = { + id: pool, + amountCreditOriginated: 300, + amountCreditRepaid: 400, + amountCreditDefaulted: 500, + } + ;(requestPost as jest.Mock).mockResolvedValue({ + data: { + poolStats, + }, + }) + + const chainId = ChainEnum.Goerli + + const result = await SubgraphService.getPoolStats(chainId, pool) + expect(result).toStrictEqual(poolStats) + }) +}) diff --git a/packages/huma-shared/src/utils/number.ts b/packages/huma-shared/src/utils/number.ts index 829a7945..5c81e5a9 100644 --- a/packages/huma-shared/src/utils/number.ts +++ b/packages/huma-shared/src/utils/number.ts @@ -2,15 +2,12 @@ import { BigNumber, ethers } from 'ethers' import { isEmpty } from './common' import { scientificToDecimal } from './scientificToDecimal' -const moneyFormatter = new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, -}) - const numberFormatter = new Intl.NumberFormat('en-US') -export const formatMoney = (num: number | string | undefined) => { +export const formatMoney = ( + num: number | string | undefined, + notation?: Intl.NumberFormatOptions['notation'], +) => { if (isEmpty(num) || Number.isNaN(num)) { return num } @@ -20,6 +17,14 @@ export const formatMoney = (num: number | string | undefined) => { if (numCast > 1_000) { numCast = Math.round(numCast) } + + const moneyFormatter = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + minimumFractionDigits: 0, + notation, + }) + return moneyFormatter.format(numCast) } From 1a8e32d3802b0ee39caca8e88c623e15f58ed3f2 Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Mon, 13 Nov 2023 16:21:10 -0500 Subject: [PATCH 04/11] Fix upScale for BigNumber --- packages/huma-shared/src/utils/number.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/huma-shared/src/utils/number.ts b/packages/huma-shared/src/utils/number.ts index 5c81e5a9..f7975da8 100644 --- a/packages/huma-shared/src/utils/number.ts +++ b/packages/huma-shared/src/utils/number.ts @@ -60,13 +60,15 @@ export const downScale = ( } export const upScale = ( - num: string | number, + num: string | number | BigNumber, decimals?: number, ): T => { if (isEmpty(num) || isEmpty(decimals)) { return num as T } - const result = Number(num) * 10 ** decimals! + const result = BigNumber.isBigNumber(num) + ? num.mul(10 ** decimals!) + : Number(num) * 10 ** decimals! if (typeof num === 'string') { return String(result) as T } From a3d1570e2cd6f22cf949645f6afe647129eb69fb Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Mon, 13 Nov 2023 17:52:29 -0500 Subject: [PATCH 05/11] Fix test --- .../huma-sdk/src/services/SubgraphService.ts | 18 +++++++++--------- .../tests/services/SubgraphService.test.ts | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/huma-sdk/src/services/SubgraphService.ts b/packages/huma-sdk/src/services/SubgraphService.ts index 20a01bfb..67f65b4a 100644 --- a/packages/huma-sdk/src/services/SubgraphService.ts +++ b/packages/huma-sdk/src/services/SubgraphService.ts @@ -221,15 +221,15 @@ function getPoolStats( } const PoolStatsQuery = ` - query { - poolStat(id:"${pool?.toLowerCase()}") { - id - amountCreditOriginated - amountCreditRepaid - amountCreditDefaulted - } - } -` + query { + poolStat(id:"${pool?.toLowerCase()}") { + id + amountCreditOriginated + amountCreditRepaid + amountCreditDefaulted + } + } + ` return requestPost<{ errors?: unknown diff --git a/packages/huma-sdk/tests/services/SubgraphService.test.ts b/packages/huma-sdk/tests/services/SubgraphService.test.ts index 5372c7d6..3e862be3 100644 --- a/packages/huma-sdk/tests/services/SubgraphService.test.ts +++ b/packages/huma-sdk/tests/services/SubgraphService.test.ts @@ -218,7 +218,7 @@ describe('getPoolStats', () => { it('should return pool stats', async () => { const pool = '0xc866A11cf6A3D178624Ff46B8A49202206A7c51B' - const poolStats = { + const poolStat = { id: pool, amountCreditOriginated: 300, amountCreditRepaid: 400, @@ -226,13 +226,13 @@ describe('getPoolStats', () => { } ;(requestPost as jest.Mock).mockResolvedValue({ data: { - poolStats, + poolStat, }, }) const chainId = ChainEnum.Goerli const result = await SubgraphService.getPoolStats(chainId, pool) - expect(result).toStrictEqual(poolStats) + expect(result).toStrictEqual(poolStat) }) }) From 347bf1c48c9d6a68b97d6f470c2cc7db26262769 Mon Sep 17 00:00:00 2001 From: shan-57blocks <115970472+shan-57blocks@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:50:04 +0800 Subject: [PATCH 06/11] Superfluid polygon supports (#68) * add superfluid pool info * update HDT address * transform payer address to checksum address * update superfluid polygon subgraph * update superfluid drawdown for polygon * fix tests issue * fix superToken decimals issue * fix approve allowance issue --------- Co-authored-by: shan --- packages/huma-shared/src/utils/pool.ts | 49 ++++++++++++++++--- packages/huma-shared/tests/utils/pool.test.ts | 11 +++-- .../src/components/ApproveAllowanceModal.tsx | 7 +++ .../StreamFactoring/borrow/1-Evaluation.tsx | 7 +-- .../StreamFactoring/borrow/2-ChooseAmount.tsx | 36 ++++++++------ .../borrow/3-ConfirmTransfer.tsx | 11 ++--- .../StreamFactoring/borrow/5-Permit.tsx | 37 +------------- .../StreamFactoring/borrow/index.tsx | 5 +- .../SuperfluidFactoredList.tsx | 4 +- .../SuperfluidUpcomingList.tsx | 4 +- packages/huma-widget/src/index.tsx | 15 ++++-- 11 files changed, 103 insertions(+), 83 deletions(-) diff --git a/packages/huma-shared/src/utils/pool.ts b/packages/huma-shared/src/utils/pool.ts index fafadf99..0c209830 100644 --- a/packages/huma-shared/src/utils/pool.ts +++ b/packages/huma-shared/src/utils/pool.ts @@ -64,7 +64,7 @@ export type PoolInfoType = { } extra?: { subgraph?: string - superTokens?: { id: string; symbol: string; decimals: number }[] + superToken?: { id: string; symbol: string; decimals: number } borrower?: string // For single borrower pools rwrUploader?: string // For single borrower pools where receivables are uploaded by a different wallet hidden?: boolean // For pools that shouldn't be displayed in the UI @@ -314,6 +314,39 @@ export const PoolContractMap: PoolContractMapType = { }, }, }, + [POOL_TYPE.Stream]: { + [POOL_NAME.Superfluid]: { + basePoolConfig: '0x22C024496036A8e97F93E14efa0d8379192bb22c', + pool: '0xF713B5203Cb6f3223830De218c2ed89Ee654b94B', + poolProcessor: '0x6E2f33b6d3F1E2048d078984f7FFF847C0Ed3bEd', + poolFeeManager: '0xd5FD3F917cf8901BeB102d81504033C748c87F19', + poolUnderlyingToken: { + address: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + symbol: 'USDC', + decimals: 6, + icon: 'USDC', + }, + assetAddress: '0xa8B0362cfE0c8e4fd1D74c3512348d6f48d71080', + poolName: POOL_NAME.Superfluid, + poolType: POOL_TYPE.Stream, + poolAbi: STEAM_FACTORING_POOL_ABI, + basePoolConfigAbi: BASE_POOL_CONFIG_ABI, + poolAssetAbi: TRADABLE_STREAM_ABI, + HDT: { + address: '0x30b1f6bca8c6c742ede0ccb4eceb22af4cba58ef', + abi: HDT_ABI, + }, + extra: { + subgraph: + 'https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-matic', + superToken: { + id: '0xcaa7349cea390f89641fe306d93591f87595dc1f', + symbol: 'USDCx', + decimals: 18, + }, + }, + }, + }, }, [ChainEnum.Goerli]: { [POOL_TYPE.CreditLine]: { @@ -513,13 +546,11 @@ export const PoolContractMap: PoolContractMapType = { extra: { subgraph: 'https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-mumbai', - superTokens: [ - { - id: '0x42bb40bf79730451b11f6de1cba222f17b87afd7', - symbol: 'fUSDCx', - decimals: 18, - }, - ], + superToken: { + id: '0x42bb40bf79730451b11f6de1cba222f17b87afd7', + symbol: 'fUSDCx', + decimals: 18, + }, }, }, }, @@ -601,6 +632,8 @@ export const SupplementaryContractsMap: { } } = { [ChainEnum.Polygon]: { + [SupplementaryContracts.MultiSend]: + '0xDa21D2Be30353EC6Aa5AcD37999806cCefaa4C6A', [SupplementaryContracts.RealWorldReceivable]: '0xCf67CcEaC38b5E1880d62b5DB531Ab1E77614E3D', }, diff --git a/packages/huma-shared/tests/utils/pool.test.ts b/packages/huma-shared/tests/utils/pool.test.ts index 7d72d34d..e7712e68 100644 --- a/packages/huma-shared/tests/utils/pool.test.ts +++ b/packages/huma-shared/tests/utils/pool.test.ts @@ -9,10 +9,13 @@ import { } from '../../src/utils/pool' describe('getPoolInfo', () => { - it('returns null if chainId is undefined', () => { - expect( - getPoolInfo(undefined, POOL_TYPE.Stream, POOL_NAME.Superfluid), - ).toBeNull() + it('returns default if chainId is undefined', () => { + const poolInfo = getPoolInfo( + undefined, + POOL_TYPE.Stream, + POOL_NAME.Superfluid, + ) + expect(poolInfo?.pool).toBe('0xF713B5203Cb6f3223830De218c2ed89Ee654b94B') }) it('returns null if poolType or poolName is not found', () => { diff --git a/packages/huma-widget/src/components/ApproveAllowanceModal.tsx b/packages/huma-widget/src/components/ApproveAllowanceModal.tsx index 76800b47..4c2b1bc9 100644 --- a/packages/huma-widget/src/components/ApproveAllowanceModal.tsx +++ b/packages/huma-widget/src/components/ApproveAllowanceModal.tsx @@ -85,6 +85,12 @@ export function ApproveAllowanceModal({ const amountToIncrease = BigNumber.from(targetAllowanceAmount).sub( currentAllowance ?? 0, ) + + if (amountToIncrease.lte(0)) { + handleSuccess() + return + } + send({ contract: poolUnderlyingTokenContract!, method: 'increaseAllowance', @@ -94,6 +100,7 @@ export function ApproveAllowanceModal({ }, [ account, allowanceAmount, + handleSuccess, poolInfo.pool, poolUnderlyingTokenContract, provider, diff --git a/packages/huma-widget/src/components/StreamFactoring/borrow/1-Evaluation.tsx b/packages/huma-widget/src/components/StreamFactoring/borrow/1-Evaluation.tsx index 3577dbb1..eb2ec8d8 100644 --- a/packages/huma-widget/src/components/StreamFactoring/borrow/1-Evaluation.tsx +++ b/packages/huma-widget/src/components/StreamFactoring/borrow/1-Evaluation.tsx @@ -1,10 +1,11 @@ -import { useWeb3React } from '@web3-react/core' +import { getAddress } from '@ethersproject/address' import { PoolInfoType } from '@huma-finance/shared' +import { useWeb3React } from '@web3-react/core' import React, { useEffect } from 'react' import useEA from '../../../hooks/useEA' -import { LoadingModal } from '../../LoadingModal' import { WIDGET_STEP } from '../../../store/widgets.store' +import { LoadingModal } from '../../LoadingModal' import { SignIn } from '../../SignIn' type Props = { @@ -35,7 +36,7 @@ export function Evaluation({ receivable: { address: poolInfo.assetAddress!, }, - payerWalletAddress: payerAddress, + payerWalletAddress: getAddress(payerAddress), superToken, }, }, diff --git a/packages/huma-widget/src/components/StreamFactoring/borrow/2-ChooseAmount.tsx b/packages/huma-widget/src/components/StreamFactoring/borrow/2-ChooseAmount.tsx index 826ff0e3..92258982 100644 --- a/packages/huma-widget/src/components/StreamFactoring/borrow/2-ChooseAmount.tsx +++ b/packages/huma-widget/src/components/StreamFactoring/borrow/2-ChooseAmount.tsx @@ -28,20 +28,24 @@ export function ChooseAmount({ const [chargedFees, setChargedFees] = useState(0) const [currentAmount, setCurrentAmount] = useState(0) const borrowPeriodInSeconds = approval!.terms.intervalInDays * 24 * 60 * 60 + const superTokenDecimals = poolInfo.extra?.superToken?.decimals! + const underlyingTokenDecimals = poolInfo.poolUnderlyingToken.decimals! + // To ensure not to borrow all the available flowrate due to contract limitation + const borrowMaxAmount = Number(approval!.terms.creditLimitFormatted) - 0.01 const getBorrowFlowrateAndAmount = useCallback( (borrowAmount: number) => { const currentFlowRateBN = toBigNumber(currentFlowRate) - const borrowAmountBN = toBigNumber( - upScale(borrowAmount, approval!.token.decimal), + const borrowAmountSuperTokenBN = toBigNumber( + upScale(borrowAmount, superTokenDecimals), ) - const totalAmountInBorrowPeriod = currentFlowRateBN.mul( + const totalAmountSuperTokenInBorrowPeriod = currentFlowRateBN.mul( borrowPeriodInSeconds, ) - let borrowFlowrate = borrowAmountBN + let borrowFlowrate = borrowAmountSuperTokenBN .mul(currentFlowRateBN) - .div(totalAmountInBorrowPeriod) + .div(totalAmountSuperTokenInBorrowPeriod) // To ensure enough flowRate due to round down when convert to string .add(1) @@ -49,26 +53,28 @@ export function ChooseAmount({ if (borrowFlowrate.gte(currentFlowRateBN)) { borrowFlowrate = currentFlowRateBN.sub(1) } - if (borrowAmountBN.gte(approval!.terms.creditLimit)) { - borrowFlowrate = borrowFlowrate.sub(1) - } // As borrowFlowrate adds 1, need to calculate the new accurate borrow amount const newBorrowAmountBN = borrowFlowrate - .mul(totalAmountInBorrowPeriod) + .mul(totalAmountSuperTokenInBorrowPeriod) .div(currentFlowRateBN) - const newBorrowAmount = downScale( - newBorrowAmountBN, - approval!.token.decimal, + const newBorrowAmount = downScale(newBorrowAmountBN, superTokenDecimals) + const newBorrowAmountUnderlyingTokenBN = toBigNumber( + upScale(newBorrowAmount, underlyingTokenDecimals), ) return { borrowFlowrate: borrowFlowrate.toString(), borrowAmount: Number(newBorrowAmount), - borrowAmountBN: newBorrowAmountBN, + borrowAmountBN: newBorrowAmountUnderlyingTokenBN, } }, - [approval, borrowPeriodInSeconds, currentFlowRate], + [ + borrowPeriodInSeconds, + currentFlowRate, + superTokenDecimals, + underlyingTokenDecimals, + ], ) const handleChangeAmount = useCallback( @@ -114,7 +120,7 @@ export function ChooseAmount({ { - const step = CHAINS[chainId!].isTestnet - ? WIDGET_STEP.ApproveAllowance - : WIDGET_STEP.Permit - dispatch(setStep(step)) - }, [chainId, dispatch]) + dispatch(setStep(WIDGET_STEP.ApproveAllowance)) + }, [dispatch]) if (isEmpty(borrowAmount) || isEmpty(approval)) { return null diff --git a/packages/huma-widget/src/components/StreamFactoring/borrow/5-Permit.tsx b/packages/huma-widget/src/components/StreamFactoring/borrow/5-Permit.tsx index 2c941601..733bd02a 100644 --- a/packages/huma-widget/src/components/StreamFactoring/borrow/5-Permit.tsx +++ b/packages/huma-widget/src/components/StreamFactoring/borrow/5-Permit.tsx @@ -1,12 +1,9 @@ import { - CHAINS, - Erc2612, PoolInfoType, SuperfluidPoolProcessor, + SuperfluidPoolProcessor_ABI, useERC2612Permit, useMount, - ERC2612_ABI, - SuperfluidPoolProcessor_ABI, } from '@huma-finance/shared' import { BigNumber, Contract, ethers } from 'ethers' import React from 'react' @@ -25,7 +22,6 @@ import { LoadingModal } from '../../LoadingModal' type Props = { poolInfo: PoolInfoType payerAddress: string - chainId: number borrower: string superToken: string } @@ -33,36 +29,15 @@ type Props = { export function Permit({ poolInfo, payerAddress, - chainId, borrower, superToken, }: Props): React.ReactElement | null { const dispatch = useDispatch() - const { address: tokenAddress } = poolInfo.poolUnderlyingToken const { borrowAmountBN: borrowAmountBNJson, stream } = useAppSelector(selectWidgetState) - const { getERC2612PermitMessage, getTradableStreamPermitMessage } = - useERC2612Permit() + const { getTradableStreamPermitMessage } = useERC2612Permit() const borrowAmountBN = BigNumber.from(borrowAmountBNJson) - const getApproveAllowanceCallData = async () => { - const erc2612PermitResult = await getERC2612PermitMessage( - tokenAddress, - poolInfo.poolProcessor!, - borrowAmountBN.toString()!, - ) - const tokenContract = new Contract(tokenAddress, ERC2612_ABI) as Erc2612 - return tokenContract.interface.encodeFunctionData('permit', [ - poolInfo.poolProcessor!, - borrowAmountBN.toString()!, - erc2612PermitResult.nonce, - erc2612PermitResult.deadline, - erc2612PermitResult.v, - erc2612PermitResult.r, - erc2612PermitResult.s, - ]) - } - const getDrawdownCallData = async () => { const NFTPermitResult = await getTradableStreamPermitMessage( poolInfo.assetAddress!, @@ -113,14 +88,6 @@ export function Permit({ try { const callData = [] const addresses: string[] = [] - - // The token in Goerli hasn't integrated ERC-2612 - if (!CHAINS[chainId].isTestnet) { - const approveAllowanceCallData = await getApproveAllowanceCallData() - addresses.push(tokenAddress) - callData.push(approveAllowanceCallData) - } - const drawdownCalldata = await getDrawdownCallData() addresses.push(poolInfo.poolProcessor!) callData.push(drawdownCalldata) diff --git a/packages/huma-widget/src/components/StreamFactoring/borrow/index.tsx b/packages/huma-widget/src/components/StreamFactoring/borrow/index.tsx index f756bf95..04947f41 100644 --- a/packages/huma-widget/src/components/StreamFactoring/borrow/index.tsx +++ b/packages/huma-widget/src/components/StreamFactoring/borrow/index.tsx @@ -39,7 +39,7 @@ export function StreamFactoringBorrow({ handleSuccess, }: StreamFactoringBorrowProps): React.ReactElement | null { const dispatch = useDispatch() - const { account, chainId } = useWeb3React() + const { account } = useWeb3React() const poolInfo = usePoolInfo(poolName, poolType) const { step, errorMessage } = useAppSelector(selectWidgetState) @@ -71,11 +71,10 @@ export function StreamFactoringBorrow({ {step === WIDGET_STEP.ApproveAllowance && ( )} - {step === WIDGET_STEP.Permit && account && chainId && ( + {step === WIDGET_STEP.Permit && account && ( diff --git a/packages/huma-widget/src/components/SuperfluidFactoring/SuperfluidFactoredList.tsx b/packages/huma-widget/src/components/SuperfluidFactoring/SuperfluidFactoredList.tsx index 386adc6c..4806ae47 100644 --- a/packages/huma-widget/src/components/SuperfluidFactoring/SuperfluidFactoredList.tsx +++ b/packages/huma-widget/src/components/SuperfluidFactoring/SuperfluidFactoredList.tsx @@ -50,9 +50,9 @@ export function SuperfluidFactoredList({ const setItem = useCallback( () => Promise.resolve({ - name: poolInfo?.extra?.superTokens?.[0].symbol ?? '', + name: poolInfo?.extra?.superToken?.symbol ?? '', }), - [poolInfo?.extra?.superTokens], + [poolInfo?.extra?.superToken], ) return ( diff --git a/packages/huma-widget/src/components/SuperfluidFactoring/SuperfluidUpcomingList.tsx b/packages/huma-widget/src/components/SuperfluidFactoring/SuperfluidUpcomingList.tsx index 6c014d08..1ed91c76 100644 --- a/packages/huma-widget/src/components/SuperfluidFactoring/SuperfluidUpcomingList.tsx +++ b/packages/huma-widget/src/components/SuperfluidFactoring/SuperfluidUpcomingList.tsx @@ -106,7 +106,9 @@ export function SuperfluidUpcomingList({ const { data } = useQuery<{ streams: Stream[] }>(GET_RECEIVED_STREAMS, { variables: { receiver: account ? account.toLowerCase() : undefined, - tokenIds: poolInfo?.extra?.superTokens?.map((item) => item.id) ?? [], + tokenIds: poolInfo?.extra?.superToken + ? [poolInfo.extra.superToken.id] + : [], }, }) diff --git a/packages/huma-widget/src/index.tsx b/packages/huma-widget/src/index.tsx index 9194c246..c80a17ff 100644 --- a/packages/huma-widget/src/index.tsx +++ b/packages/huma-widget/src/index.tsx @@ -10,6 +10,7 @@ import { Provider as Eip1193Provider } from '@web3-react/types' import { Provider as AtomProvider } from 'jotai' import { Provider as ReduxProvider } from 'react-redux' +import { useEffect, useState } from 'react' import { ChainSupportProvider } from './components/ChainSupportProvider' import { CreditLineApprove, @@ -63,11 +64,17 @@ type WidgetProps = { function Widget(props: WCProps) { const { children, provider } = props + const [chainId, setChainId] = useState(undefined) - let chainId - if (provider instanceof JsonRpcProvider) { - chainId = provider.network.chainId - } + useEffect(() => { + const getChainId = async () => { + if (provider instanceof JsonRpcProvider) { + const network = await provider.getNetwork() + setChainId(network?.chainId) + } + } + getChainId() + }, [provider]) return ( From a4c68cc023c9005ee9fa70ebed3fd0bce1d3790d Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Wed, 15 Nov 2023 14:45:27 -0500 Subject: [PATCH 07/11] Add totalPoolAssets --- .../huma-sdk/src/services/SubgraphService.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/huma-sdk/src/services/SubgraphService.ts b/packages/huma-sdk/src/services/SubgraphService.ts index 67f65b4a..5e3f822a 100644 --- a/packages/huma-sdk/src/services/SubgraphService.ts +++ b/packages/huma-sdk/src/services/SubgraphService.ts @@ -198,6 +198,7 @@ function getRWReceivableInfo( type PoolStats = { id: string + totalPoolAssets: number amountCreditOriginated: number amountCreditRepaid: number amountCreditDefaulted: number @@ -222,14 +223,14 @@ function getPoolStats( const PoolStatsQuery = ` query { - poolStat(id:"${pool?.toLowerCase()}") { - id - amountCreditOriginated - amountCreditRepaid - amountCreditDefaulted - } - } - ` + poolStat(id:"${pool?.toLowerCase()}") { + id + amountCreditOriginated + amountCreditRepaid + amountCreditDefaulted + totalPoolAssets + } + }` return requestPost<{ errors?: unknown From 50e88d14d795663eda410f4e010a3c14b96b4a23 Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Tue, 21 Nov 2023 12:09:18 -0500 Subject: [PATCH 08/11] Fix upscale for overflow --- packages/huma-shared/src/utils/number.ts | 2 +- packages/huma-shared/src/utils/pool.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/huma-shared/src/utils/number.ts b/packages/huma-shared/src/utils/number.ts index f7975da8..2c897137 100644 --- a/packages/huma-shared/src/utils/number.ts +++ b/packages/huma-shared/src/utils/number.ts @@ -67,7 +67,7 @@ export const upScale = ( return num as T } const result = BigNumber.isBigNumber(num) - ? num.mul(10 ** decimals!) + ? num.mul(BigNumber.from(10).pow(decimals!)) : Number(num) * 10 ** decimals! if (typeof num === 'string') { return String(result) as T diff --git a/packages/huma-shared/src/utils/pool.ts b/packages/huma-shared/src/utils/pool.ts index 0c209830..fba9a7e6 100644 --- a/packages/huma-shared/src/utils/pool.ts +++ b/packages/huma-shared/src/utils/pool.ts @@ -514,6 +514,8 @@ export const PoolContractMap: PoolContractMapType = { abi: HDT_ABI, }, extra: { + borrower: '0xea57a8a51377752ffddaa3db4d13ce8f97677f2d', + rwrUploader: '0xea57a8a51377752ffddaa3db4d13ce8f97677f2d', disableBorrow: true, detailsPage: true, }, From 8485c51b0262799b2c6b7405548c24375d123416 Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Tue, 21 Nov 2023 12:12:25 -0500 Subject: [PATCH 09/11] Add test --- packages/huma-shared/tests/utils/number.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/huma-shared/tests/utils/number.test.ts b/packages/huma-shared/tests/utils/number.test.ts index 41662cd4..ad245d99 100644 --- a/packages/huma-shared/tests/utils/number.test.ts +++ b/packages/huma-shared/tests/utils/number.test.ts @@ -63,6 +63,14 @@ describe('upScale', () => { expect(upScale('123.45', 2)).toBe('12345') expect(upScale(123.45, 2)).toBe(12345) }) + + it('returns the upscaled number if the input is a valid number and decimals would cause overflow', () => { + expect( + upScale(BigNumber.from(10), 18).eq( + BigNumber.from('10000000000000000000'), + ), + ).toBe(true) + }) }) describe('toBigNumber', () => { From 13746d4e79e8d7c241c719694bfe65f935196eb6 Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Mon, 27 Nov 2023 12:26:30 -0500 Subject: [PATCH 10/11] Add raincards test pool --- packages/huma-shared/src/utils/pool.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/huma-shared/src/utils/pool.ts b/packages/huma-shared/src/utils/pool.ts index fba9a7e6..2e9f119f 100644 --- a/packages/huma-shared/src/utils/pool.ts +++ b/packages/huma-shared/src/utils/pool.ts @@ -17,6 +17,7 @@ export enum POOL_NAME { BSOS = 'BSOS', ImpactMarket = 'ImpactMarket', Symplifi = 'Symplifi', + Raincards = 'Raincards', } export enum POOL_TYPE { @@ -139,6 +140,14 @@ export const PoolMap: PoolMapType = { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', estAPY: '20%', }, + [POOL_NAME.Raincards]: { + name: 'Raincards Pool', + borrowDesc: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + lendDesc: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + estAPY: '20%', + }, }, [POOL_TYPE.Invoice]: { [POOL_NAME.RequestNetwork]: { @@ -557,22 +566,22 @@ export const PoolContractMap: PoolContractMapType = { }, }, [POOL_TYPE.CreditLine]: { - [POOL_NAME.ArfUSDCMigrationTest]: { - basePoolConfig: '0xe8338a5e3e58b425249f82594c82b42c2df4c5e9', - pool: '0xbb1b50e1ec5835b3c58944e820e7a5e136141ddc', - poolFeeManager: '0x9f667f613C16542aC8b1e502F4D796774F623D86', + [POOL_NAME.Raincards]: { + basePoolConfig: '0x10b7CBe54178eB6C81b2D84Ac073747BcA744F6C', + pool: '0xf8065dA82cC990325059c436939c6a90C322E9Dd', + poolFeeManager: '0x87534B96FD15EbD6Aa0456F45045B541e5E8889a', poolUnderlyingToken: { - address: '0x9999f7fea5938fd3b1e26a12c3f2fb024e194f97', + address: '0xb961c37ABDDA55929327fa9d20eBDE6BB8B1348E', symbol: 'USDC', decimals: 6, icon: 'USDC', }, - poolName: POOL_NAME.ArfUSDCMigrationTest, + poolName: POOL_NAME.Raincards, poolType: POOL_TYPE.CreditLine, poolAbi: BASE_CREDIT_POOL_ABI, basePoolConfigAbi: BASE_POOL_CONFIG_ABI, HDT: { - address: '0x8bce02521622222Ee13D1Ce2c5E4CCab52ce24Bb', + address: '0x8Ec8f8AFE179032e2929C49eF4f8Ea2d18245B9a', abi: HDT_ABI, }, }, From 4bf85a26aff0a1a9ac251f6b703277291aade0bf Mon Sep 17 00:00:00 2001 From: Michael Liu Date: Fri, 1 Dec 2023 12:21:13 -0500 Subject: [PATCH 11/11] Fix dep conflict --- packages/huma-shared/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/huma-shared/package.json b/packages/huma-shared/package.json index b596f764..f7ec1dca 100644 --- a/packages/huma-shared/package.json +++ b/packages/huma-shared/package.json @@ -38,7 +38,7 @@ "@mui/system": "^5.0.6", "@mui/x-date-pickers": "^5.0.7", "@reduxjs/toolkit": "^1.8.6", - "@requestnetwork/multi-format": "^0.15.10", + "@requestnetwork/multi-format": "0.15.10", "@types/utf8": "^3.0.1", "@walletconnect/ethereum-provider": "1.8.0", "@walletconnect/jsonrpc-http-connection": "^1.0.3",