Skip to content

Commit

Permalink
Merge branch 'develop' into subgraph-poolstats
Browse files Browse the repository at this point in the history
  • Loading branch information
mliu authored Nov 15, 2023
2 parents a4c68cc + 347bf1c commit ff56ca0
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 83 deletions.
49 changes: 41 additions & 8 deletions packages/huma-shared/src/utils/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]: {
Expand Down Expand Up @@ -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,
},
},
},
},
Expand Down Expand Up @@ -601,6 +632,8 @@ export const SupplementaryContractsMap: {
}
} = {
[ChainEnum.Polygon]: {
[SupplementaryContracts.MultiSend]:
'0xDa21D2Be30353EC6Aa5AcD37999806cCefaa4C6A',
[SupplementaryContracts.RealWorldReceivable]:
'0xCf67CcEaC38b5E1880d62b5DB531Ab1E77614E3D',
},
Expand Down
11 changes: 7 additions & 4 deletions packages/huma-shared/tests/utils/pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
7 changes: 7 additions & 0 deletions packages/huma-widget/src/components/ApproveAllowanceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -94,6 +100,7 @@ export function ApproveAllowanceModal({
}, [
account,
allowanceAmount,
handleSuccess,
poolInfo.pool,
poolUnderlyingTokenContract,
provider,
Expand Down
Original file line number Diff line number Diff line change
@@ -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 = {
Expand Down Expand Up @@ -35,7 +36,7 @@ export function Evaluation({
receivable: {
address: poolInfo.assetAddress!,
},
payerWalletAddress: payerAddress,
payerWalletAddress: getAddress(payerAddress),
superToken,
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,47 +28,53 @@ 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)

// Can not borrow all the available flowrate
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(
Expand Down Expand Up @@ -114,7 +120,7 @@ export function ChooseAmount({
<ChooseAmountModal
title='Choose Amount'
description1='Access up to 100% of your stream flowrate'
sliderMax={Number(approval.terms.creditLimitFormatted)}
sliderMax={borrowMaxAmount}
currentAmount={currentAmount}
tokenSymbol={approval.token.symbol}
topLeft='Fees'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { CHAINS, isEmpty } from '@huma-finance/shared'
import { useWeb3React } from '@web3-react/core'
import { isEmpty } from '@huma-finance/shared'
import React, { useCallback } from 'react'

import { useAppDispatch, useAppSelector } from '../../../hooks/useRedux'
Expand All @@ -10,15 +9,11 @@ import { ConfirmTransferModal } from '../../ConfirmTransferModal'

export function ConfirmTransfer(): React.ReactElement | null {
const dispatch = useAppDispatch()
const { chainId } = useWeb3React()
const { borrowAmount, approval } = useAppSelector(selectWidgetState)

const handleAction = useCallback(() => {
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -25,44 +22,22 @@ import { LoadingModal } from '../../LoadingModal'
type Props = {
poolInfo: PoolInfoType
payerAddress: string
chainId: number
borrower: string
superToken: string
}

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!,
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -71,11 +71,10 @@ export function StreamFactoringBorrow({
{step === WIDGET_STEP.ApproveAllowance && (
<ApproveAllowance poolInfo={poolInfo} />
)}
{step === WIDGET_STEP.Permit && account && chainId && (
{step === WIDGET_STEP.Permit && account && (
<Permit
poolInfo={poolInfo}
payerAddress={payerAddress}
chainId={chainId}
borrower={account}
superToken={superToken}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
: [],
},
})

Expand Down
15 changes: 11 additions & 4 deletions packages/huma-widget/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -63,11 +64,17 @@ type WidgetProps = {

function Widget(props: WCProps<WidgetProps>) {
const { children, provider } = props
const [chainId, setChainId] = useState<number | undefined>(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 (
<ThemeProvider theme={themeHuma}>
Expand Down

0 comments on commit ff56ca0

Please sign in to comment.