diff --git a/packages/huma-widget/API.md b/packages/huma-widget/API.md
index 963d5d6..8217748 100644
--- a/packages/huma-widget/API.md
+++ b/packages/huma-widget/API.md
@@ -3,6 +3,8 @@
- StellarLendAddRedemption()
Stellar add redemption props – request to withdraw (redeem) shares from a tranche.
+- StellarLendWithdraw()
+Stellar lend pool withdraw props – disburse (pool open) or withdraw after pool closure.
- InvoiceFactoringBorrowWidget(props) ⇒
Invoice factoring borrow widget
- InvoiceFactoringPaymentWidget(props) ⇒
@@ -56,6 +58,8 @@ To be used when re-enabling autopay and other pool actions that require allowanc
Lend pool supply widget for Stellar pools
- StellarLendAddRedemptionWidget(props)
Lend pool add redemption widget for Stellar pools
+- StellarLendWithdrawWidget(props)
+Lend pool withdraw widget for Stellar pools (disburse when pool open, withdraw_after_pool_closure when closed)
- StellarBorrowWidget(props)
Borrow widget for Stellar pools
- SolanaEnableAutoRedemptionWidget(props)
@@ -171,6 +175,8 @@ To be used when re-enabling autopay and other pool actions that require allowanc
Lend pool supply widget props for Stellar pools
- StellarLendAddRedemptionWidgetProps :
Object
Lend pool add redemption widget props for Stellar pools
+- StellarLendWithdrawWidgetProps :
Object
+Lend pool withdraw widget props for Stellar pools
- StellarLendSupplyWidgetProps :
Object
Borrow widget props for Stellar pools
- SolanaEnableAutoRedemptionWidgetProps :
Object
@@ -193,6 +199,22 @@ To be used when re-enabling autopay and other pool actions that require allowanc
| handleClose | function | Function to close the widget modal.
|
| handleSuccess | function | Optional callback when redemption request succeeds.
|
+
+
+## StellarLendWithdraw()
+Stellar lend pool withdraw props – disburse (pool open) or withdraw after pool closure.
+
+**Kind**: global function
+**Properties**
+
+| Name | Type | Description |
+| --- | --- | --- |
+| poolInfo | StellarPoolInfo | The metadata of the pool.
|
+| poolState | StellarPoolState | The current state config of the pool.
|
+| tranche | TrancheType | The tranche to withdraw from (junior or senior).
|
+| handleClose | function | Function to close the widget modal.
|
+| handleSuccess | function | Optional callback when withdraw succeeds.
|
+
## InvoiceFactoringBorrowWidget(props) ⇒
@@ -499,6 +521,17 @@ To be used when re-enabling autopay and other pool actions that require allowanc
| --- | --- | --- |
| props | [StellarLendAddRedemptionWidgetProps](#StellarLendAddRedemptionWidgetProps) | Widget props
|
+
+
+## StellarLendWithdrawWidget(props)
+Lend pool withdraw widget for Stellar pools (disburse when pool open, withdraw_after_pool_closure when closed)
+
+**Kind**: global function
+
+| Param | Type | Description |
+| --- | --- | --- |
+| props | [StellarLendWithdrawWidgetProps](#StellarLendWithdrawWidgetProps) | Widget props
|
+
## StellarBorrowWidget(props)
@@ -1213,6 +1246,12 @@ To be used when re-enabling autopay and other pool actions that require allowanc
## StellarLendAddRedemptionWidgetProps : Object
Lend pool add redemption widget props for Stellar pools
+**Kind**: global typedef
+
+
+## StellarLendWithdrawWidgetProps : Object
+Lend pool withdraw widget props for Stellar pools
+
**Kind**: global typedef
diff --git a/packages/huma-widget/src/components/Lend/stellarWithdraw/1-Confirm.tsx b/packages/huma-widget/src/components/Lend/stellarWithdraw/1-Confirm.tsx
new file mode 100644
index 0000000..e49ea5b
--- /dev/null
+++ b/packages/huma-widget/src/components/Lend/stellarWithdraw/1-Confirm.tsx
@@ -0,0 +1,60 @@
+import { StellarPoolInfo } from '@huma-finance/shared'
+import { Box, css, useTheme } from '@mui/material'
+import React from 'react'
+import { BottomButton } from '../../BottomButton'
+import { WrapperModal } from '../../WrapperModal'
+
+type Props = {
+ poolInfo: StellarPoolInfo
+ withdrawableAmountFormatted: string
+ onConfirm: () => void
+}
+
+export function Confirm({
+ poolInfo,
+ withdrawableAmountFormatted,
+ onConfirm,
+}: Props): React.ReactElement {
+ const theme = useTheme()
+ const { symbol } = poolInfo.underlyingToken
+
+ const styles = {
+ itemWrapper: css`
+ margin-top: ${theme.spacing(9)};
+ color: ${theme.palette.text.primary};
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 175%;
+ letter-spacing: 0.15px;
+ `,
+ item: css`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: ${theme.spacing(3)};
+ `,
+ itemValue: css`
+ font-size: 20px;
+ font-weight: 700;
+ `,
+ }
+
+ return (
+
+
+
+ Available to withdraw
+
+ {withdrawableAmountFormatted} {symbol}
+
+
+
+
+ WITHDRAW
+
+
+ )
+}
diff --git a/packages/huma-widget/src/components/Lend/stellarWithdraw/2-Transfer.tsx b/packages/huma-widget/src/components/Lend/stellarWithdraw/2-Transfer.tsx
new file mode 100644
index 0000000..8762c2e
--- /dev/null
+++ b/packages/huma-widget/src/components/Lend/stellarWithdraw/2-Transfer.tsx
@@ -0,0 +1,67 @@
+import {
+ STELLAR_CHAINS_INFO,
+ StellarPoolInfo,
+ TrancheType,
+} from '@huma-finance/shared'
+import { Client as TrancheVaultClient } from '@huma-finance/soroban-tranche-vault'
+import React, { useCallback, useContext, useEffect, useState } from 'react'
+
+import {
+ getClientCommonParams,
+ StellarConnectionContext,
+} from '@huma-finance/web-shared'
+import { useAppDispatch } from '../../../hooks/useRedux'
+import { setStep } from '../../../store/widgets.reducers'
+import { WIDGET_STEP } from '../../../store/widgets.store'
+import { StellarTxSendModal } from '../../StellarTxSendModal'
+
+type Props = {
+ poolInfo: StellarPoolInfo
+ tranche: TrancheType
+ poolIsClosed: boolean
+}
+
+export function Transfer({
+ poolInfo,
+ tranche,
+ poolIsClosed,
+}: Props): React.ReactElement | null {
+ const dispatch = useAppDispatch()
+ const { address: stellarAddress } = useContext(StellarConnectionContext)
+ const [tx, setTx] = useState
+ > | null>(null)
+
+ const handleSuccess = useCallback(async () => {
+ dispatch(setStep(WIDGET_STEP.Done))
+ }, [dispatch])
+
+ useEffect(() => {
+ async function getTx() {
+ if (!stellarAddress) {
+ return
+ }
+
+ const chainMetadata = STELLAR_CHAINS_INFO[poolInfo.chainId]
+ const contractId =
+ tranche === 'senior' ? poolInfo.seniorTranche! : poolInfo.juniorTranche
+ const trancheVaultClient = new TrancheVaultClient({
+ publicKey: stellarAddress,
+ contractId,
+ ...getClientCommonParams(chainMetadata, stellarAddress),
+ })
+
+ const assembledTx = poolIsClosed
+ ? await trancheVaultClient.withdraw_after_pool_closure({
+ lender: stellarAddress,
+ })
+ : await trancheVaultClient.disburse({
+ lender: stellarAddress,
+ })
+ setTx(assembledTx)
+ }
+ getTx()
+ }, [poolInfo, tranche, poolIsClosed, stellarAddress])
+
+ return
+}
diff --git a/packages/huma-widget/src/components/Lend/stellarWithdraw/3-Done.tsx b/packages/huma-widget/src/components/Lend/stellarWithdraw/3-Done.tsx
new file mode 100644
index 0000000..5322bcd
--- /dev/null
+++ b/packages/huma-widget/src/components/Lend/stellarWithdraw/3-Done.tsx
@@ -0,0 +1,38 @@
+import { formatNumber, StellarPoolInfo } from '@huma-finance/shared'
+import React, { useCallback } from 'react'
+import { useAppSelector } from '../../../hooks/useRedux'
+import { selectWidgetState } from '../../../store/widgets.selectors'
+import { StellarTxDoneModal } from '../../StellarTxDoneModal'
+
+type Props = {
+ poolInfo: StellarPoolInfo
+ withdrawAmount?: number
+ handleAction: (options?: { isSuccess?: boolean }) => void
+}
+
+export function Done({
+ poolInfo,
+ withdrawAmount,
+ handleAction,
+}: Props): React.ReactElement {
+ const { txHash } = useAppSelector(selectWidgetState)
+ const { symbol } = poolInfo.underlyingToken
+
+ const content = [
+ `${formatNumber(withdrawAmount ?? 0)} ${symbol} withdrawn to your wallet`,
+ ]
+
+ const handleUserAction = useCallback(() => {
+ handleAction({ isSuccess: true })
+ }, [handleAction])
+
+ return (
+
+ )
+}
diff --git a/packages/huma-widget/src/components/Lend/stellarWithdraw/index.tsx b/packages/huma-widget/src/components/Lend/stellarWithdraw/index.tsx
new file mode 100644
index 0000000..792358e
--- /dev/null
+++ b/packages/huma-widget/src/components/Lend/stellarWithdraw/index.tsx
@@ -0,0 +1,170 @@
+import {
+ CloseModalOptions,
+ formatNumberFixed,
+ STELLAR_CHAINS_INFO,
+ StellarPoolInfo,
+ tokenDecimalUtils,
+ TrancheType,
+} from '@huma-finance/shared'
+import { Client as TrancheVaultClient } from '@huma-finance/soroban-tranche-vault'
+import {
+ StellarConnectionContext,
+ StellarPoolState,
+} from '@huma-finance/web-shared'
+import React, { useCallback, useContext, useEffect, useState } from 'react'
+import { useDispatch } from 'react-redux'
+
+import { useAppSelector } from '../../../hooks/useRedux'
+import { setStep, setWithdrawAmount } from '../../../store/widgets.reducers'
+import { selectWidgetState } from '../../../store/widgets.selectors'
+import { WIDGET_STEP } from '../../../store/widgets.store'
+import { ErrorModal } from '../../ErrorModal'
+import { WidgetWrapper } from '../../WidgetWrapper'
+import { Confirm } from './1-Confirm'
+import { Transfer } from './2-Transfer'
+import { Done } from './3-Done'
+
+/**
+ * Stellar lend pool withdraw props – disburse (pool open) or withdraw after pool closure.
+ * @property {StellarPoolInfo} poolInfo The metadata of the pool.
+ * @property {StellarPoolState} poolState The current state config of the pool.
+ * @property {TrancheType} tranche The tranche to withdraw from (junior or senior).
+ * @property {function((CloseModalOptions|undefined)):void} handleClose Function to close the widget modal.
+ * @property {function():void|undefined} handleSuccess Optional callback when withdraw succeeds.
+ */
+export interface StellarLendWithdrawProps {
+ poolInfo: StellarPoolInfo
+ poolState: StellarPoolState
+ tranche: TrancheType
+ handleClose: (options?: CloseModalOptions) => void
+ handleSuccess?: () => void
+}
+
+export function StellarLendWithdraw({
+ poolInfo,
+ poolState,
+ tranche,
+ handleClose,
+ handleSuccess,
+}: StellarLendWithdrawProps): React.ReactElement | null {
+ const dispatch = useDispatch()
+ const { address: stellarAddress } = useContext(StellarConnectionContext)
+ const { step, errorMessage, withdrawAmount } =
+ useAppSelector(selectWidgetState)
+ const [withdrawableAmount, setWithdrawableAmount] = useState(
+ BigInt(0),
+ )
+ const [isLoadingWithdrawable, setIsLoadingWithdrawable] = useState(true)
+
+ const { symbol, decimals } = poolInfo.underlyingToken
+ const title = `Withdraw ${symbol}`
+ const poolIsClosed = poolState?.status === 'closed'
+ const withdrawableAmountFormatted = formatNumberFixed(
+ tokenDecimalUtils.formatUnits(withdrawableAmount, decimals),
+ 2,
+ )
+
+ useEffect(() => {
+ if (!step && stellarAddress) {
+ dispatch(setStep(WIDGET_STEP.ConfirmWithdrawOnly))
+ }
+ }, [dispatch, step, stellarAddress])
+
+ useEffect(() => {
+ async function fetchWithdrawable() {
+ if (!stellarAddress || !poolInfo) {
+ setIsLoadingWithdrawable(false)
+ return
+ }
+ setIsLoadingWithdrawable(true)
+ try {
+ const chainMetadata = STELLAR_CHAINS_INFO[poolInfo.chainId]
+ const contractId =
+ tranche === 'senior'
+ ? poolInfo.seniorTranche!
+ : poolInfo.juniorTranche
+ const client = new TrancheVaultClient({
+ publicKey: stellarAddress,
+ contractId,
+ networkPassphrase: chainMetadata.networkPassphrase,
+ rpcUrl: chainMetadata.rpc,
+ })
+ const res = await client.get_latest_redemption_record({
+ lender: stellarAddress,
+ })
+ const record = res.result
+ const withdrawable =
+ BigInt(record.total_amount_processed) -
+ BigInt(record.total_amount_withdrawn)
+ setWithdrawableAmount(withdrawable)
+ } catch (err) {
+ console.error('Failed to fetch withdrawable amount:', err)
+ setWithdrawableAmount(BigInt(0))
+ } finally {
+ setIsLoadingWithdrawable(false)
+ }
+ }
+ fetchWithdrawable()
+ }, [stellarAddress, poolInfo, tranche])
+
+ const handleConfirmWithdraw = useCallback(() => {
+ dispatch(setWithdrawAmount(Number(withdrawableAmountFormatted)))
+ dispatch(setStep(WIDGET_STEP.Transfer))
+ }, [dispatch, withdrawableAmountFormatted])
+
+ const handleWithdrawSuccess = useCallback(() => {
+ handleSuccess?.()
+ }, [handleSuccess])
+
+ if (isLoadingWithdrawable && step === WIDGET_STEP.ConfirmWithdrawOnly) {
+ return (
+
+ )
+ }
+
+ return (
+
+ {step === WIDGET_STEP.ConfirmWithdrawOnly && (
+
+ )}
+ {step === WIDGET_STEP.Transfer && (
+
+ )}
+ {step === WIDGET_STEP.Done && (
+
+ )}
+ {step === WIDGET_STEP.Error && (
+
+ )}
+
+ )
+}
diff --git a/packages/huma-widget/src/index.tsx b/packages/huma-widget/src/index.tsx
index 1d0ced2..b96ab97 100644
--- a/packages/huma-widget/src/index.tsx
+++ b/packages/huma-widget/src/index.tsx
@@ -85,6 +85,10 @@ import {
StellarLendSupply,
StellarLendSupplyProps,
} from './components/Lend/stellarSupply'
+import {
+ StellarLendWithdraw,
+ StellarLendWithdrawProps,
+} from './components/Lend/stellarWithdraw'
import { LendSupply, LendSupplyProps } from './components/Lend/supply'
import { LendSupplyPropsV2, LendSupplyV2 } from './components/Lend/supplyV2'
import { LendWithdraw, LendWithdrawProps } from './components/Lend/withdraw'
@@ -739,6 +743,28 @@ export function StellarLendAddRedemptionWidget(
)
}
+/**
+ * Lend pool withdraw widget props for Stellar pools
+ * @typedef {Object} StellarLendWithdrawWidgetProps
+ */
+type StellarLendWithdrawWidgetProps = StellarLendWithdrawProps &
+ GenericWidgetProps
+
+/**
+ * Lend pool withdraw widget for Stellar pools (disburse when pool open, withdraw_after_pool_closure when closed)
+ *
+ * @param {StellarLendWithdrawWidgetProps} props - Widget props
+ */
+export function StellarLendWithdrawWidget(
+ props: StellarLendWithdrawWidgetProps,
+) {
+ return (
+
+
+
+ )
+}
+
/**
* Borrow widget props for Stellar pools
* @typedef {Object} StellarLendSupplyWidgetProps