@huma-finance/widgets 0.0.79 → 0.0.80-beta.1081

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ import { StellarPoolInfo, TrancheType } from '../../../../../huma-shared/src';
2
+ import { StellarPoolState } from '../../../../../huma-web-shared/src';
3
+ import { default as React } from 'react';
4
+ type Props = {
5
+ poolInfo: StellarPoolInfo;
6
+ poolState: StellarPoolState;
7
+ selectedTranche: TrancheType;
8
+ };
9
+ export declare function ChooseAmount({ poolInfo, poolState, selectedTranche, }: Props): React.ReactElement | null;
10
+ export {};
@@ -0,0 +1,8 @@
1
+ import { StellarPoolInfo, TrancheType } from '../../../../../huma-shared/src';
2
+ import { default as React } from 'react';
3
+ type Props = {
4
+ poolInfo: StellarPoolInfo;
5
+ selectedTranche: TrancheType;
6
+ };
7
+ export declare function Transfer({ poolInfo, selectedTranche, }: Props): React.ReactElement | null;
8
+ export {};
@@ -0,0 +1,10 @@
1
+ import { StellarPoolInfo } from '../../../../../huma-shared/src';
2
+ import { default as React } from 'react';
3
+ type Props = {
4
+ poolInfo: StellarPoolInfo;
5
+ handleAction: (options?: {
6
+ isSuccess?: boolean;
7
+ }) => void;
8
+ };
9
+ export declare function Done({ poolInfo, handleAction }: Props): React.ReactElement;
10
+ export {};
@@ -0,0 +1,19 @@
1
+ import { CloseModalOptions, StellarPoolInfo, TrancheType } from '../../../../../huma-shared/src';
2
+ import { StellarPoolState } from '../../../../../huma-web-shared/src';
3
+ import { default as React } from 'react';
4
+ /**
5
+ * Stellar add redemption props – request to withdraw (redeem) shares from a tranche.
6
+ * @property {StellarPoolInfo} poolInfo The metadata of the pool.
7
+ * @property {StellarPoolState} poolState The current state config of the pool.
8
+ * @property {TrancheType} tranche The tranche to redeem from (junior or senior).
9
+ * @property {function((CloseModalOptions|undefined)):void} handleClose Function to close the widget modal.
10
+ * @property {function():void|undefined} handleSuccess Optional callback when redemption request succeeds.
11
+ */
12
+ export interface StellarLendAddRedemptionProps {
13
+ poolInfo: StellarPoolInfo;
14
+ poolState: StellarPoolState;
15
+ tranche: TrancheType;
16
+ handleClose: (options?: CloseModalOptions) => void;
17
+ handleSuccess?: () => void;
18
+ }
19
+ export declare function StellarLendAddRedemption({ poolInfo, poolState, tranche, handleClose, handleSuccess, }: StellarLendAddRedemptionProps): React.ReactElement | null;
@@ -17,6 +17,7 @@ import { SolanaLendCancelRedemptionProps } from './components/Lend/solanaCancelR
17
17
  import { SolanaEnableAutoRedemptionProps } from './components/Lend/solanaEnableAutoRedemption';
18
18
  import { SolanaLendSupplyProps } from './components/Lend/solanaSupply';
19
19
  import { SolanaLendWithdrawProps } from './components/Lend/solanaWithdraw';
20
+ import { StellarLendAddRedemptionProps } from './components/Lend/stellarAddRedemption';
20
21
  import { StellarLendSupplyProps } from './components/Lend/stellarSupply';
21
22
  import { LendSupplyProps } from './components/Lend/supply';
22
23
  import { LendSupplyPropsV2 } from './components/Lend/supplyV2';
@@ -372,6 +373,17 @@ type StellarLendSupplyWidgetProps = StellarLendSupplyProps & GenericWidgetProps;
372
373
  * @param {StellarLendSupplyWidgetProps} props - Widget props
373
374
  */
374
375
  export declare function StellarLendSupplyWidget(props: StellarLendSupplyWidgetProps): import("@emotion/react/jsx-runtime").JSX.Element;
376
+ /**
377
+ * Lend pool add redemption widget props for Stellar pools
378
+ * @typedef {Object} StellarLendAddRedemptionWidgetProps
379
+ */
380
+ type StellarLendAddRedemptionWidgetProps = StellarLendAddRedemptionProps & GenericWidgetProps;
381
+ /**
382
+ * Lend pool add redemption widget for Stellar pools
383
+ *
384
+ * @param {StellarLendAddRedemptionWidgetProps} props - Widget props
385
+ */
386
+ export declare function StellarLendAddRedemptionWidget(props: StellarLendAddRedemptionWidgetProps): import("@emotion/react/jsx-runtime").JSX.Element;
375
387
  /**
376
388
  * Borrow widget props for Stellar pools
377
389
  * @typedef {Object} StellarLendSupplyWidgetProps
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huma-finance/widgets",
3
- "version": "0.0.79",
3
+ "version": "0.0.80-beta.1081+4c21b05",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -22,9 +22,9 @@
22
22
  "@ethersproject/contracts": "^5.7.0",
23
23
  "@ethersproject/experimental": "^5.7.0",
24
24
  "@ethersproject/units": "^5.6.0",
25
- "@huma-finance/sdk": "^0.0.79",
26
- "@huma-finance/shared": "^0.0.79",
27
- "@huma-finance/web-shared": "^0.0.79",
25
+ "@huma-finance/sdk": "^0.0.80-beta.1081+4c21b05",
26
+ "@huma-finance/shared": "^0.0.80-beta.1081+4c21b05",
27
+ "@huma-finance/web-shared": "^0.0.80-beta.1081+4c21b05",
28
28
  "@mui/x-date-pickers": "^5.0.7",
29
29
  "@notifi-network/notifi-frontend-client": "^1.1.2",
30
30
  "@notifi-network/notifi-react": "^1.1.2",
@@ -190,5 +190,5 @@
190
190
  "optionalDependencies": {
191
191
  "encoding": "^0.1.13"
192
192
  },
193
- "gitHead": "abf1c7b3b79f984bdb33383ada83360bf1cc4fdc"
193
+ "gitHead": "4c21b05f4e272d6e91d0eb286d518b2c7b71d5c4"
194
194
  }
@@ -6,6 +6,7 @@ import {
6
6
  import { useHumaProgram } from '@huma-finance/web-shared'
7
7
  import {
8
8
  ASSOCIATED_TOKEN_PROGRAM_ID,
9
+ createAssociatedTokenAccountIdempotentInstruction,
9
10
  createAssociatedTokenAccountInstruction,
10
11
  getAccount,
11
12
  TOKEN_2022_PROGRAM_ID,
@@ -89,6 +90,16 @@ export function Transfer({
89
90
  }
90
91
  }
91
92
 
93
+ tx.add(
94
+ createAssociatedTokenAccountIdempotentInstruction(
95
+ publicKey,
96
+ lenderTrancheToken,
97
+ publicKey,
98
+ new PublicKey(trancheMint),
99
+ TOKEN_2022_PROGRAM_ID,
100
+ ),
101
+ )
102
+
92
103
  if (!poolIsClosed) {
93
104
  const disburseTx = await program.methods
94
105
  .disburse()
@@ -0,0 +1,137 @@
1
+ import {
2
+ formatNumber,
3
+ StellarPoolInfo,
4
+ tokenDecimalUtils,
5
+ TrancheType,
6
+ } from '@huma-finance/shared'
7
+ import {
8
+ fetchStellarDepositRecord,
9
+ getStellarSharesFromUnderlyingTokenAmount,
10
+ StellarConnectionContext,
11
+ StellarPoolState,
12
+ } from '@huma-finance/web-shared'
13
+ import React, { useCallback, useContext, useEffect, useState } from 'react'
14
+ import { useAppDispatch } from '../../../hooks/useRedux'
15
+ import {
16
+ setRedeemAmount,
17
+ setRedeemShares,
18
+ setStep,
19
+ } from '../../../store/widgets.reducers'
20
+ import { WIDGET_STEP } from '../../../store/widgets.store'
21
+ import { InputAmountModal } from '../../InputAmountModal'
22
+ import { LoadingModal } from '../../LoadingModal'
23
+
24
+ type Props = {
25
+ poolInfo: StellarPoolInfo
26
+ poolState: StellarPoolState
27
+ selectedTranche: TrancheType
28
+ }
29
+
30
+ export function ChooseAmount({
31
+ poolInfo,
32
+ poolState,
33
+ selectedTranche,
34
+ }: Props): React.ReactElement | null {
35
+ const dispatch = useAppDispatch()
36
+ const { address: stellarAddress } = useContext(StellarConnectionContext)
37
+ const [currentAmount, setCurrentAmount] = useState<number | string>(0)
38
+ const [principal, setPrincipal] = useState<bigint | null>(null)
39
+ const [isLoadingDepositRecord, setIsLoadingDepositRecord] = useState(true)
40
+
41
+ const { symbol, decimals: underlyingDecimals } = poolInfo.underlyingToken
42
+ const { trancheDecimals } = poolInfo
43
+
44
+ const totalAssets = BigInt(
45
+ selectedTranche === 'senior'
46
+ ? poolState.seniorTrancheAssets ?? 0
47
+ : poolState.juniorTrancheAssets ?? 0,
48
+ )
49
+ const totalSupply = BigInt(
50
+ selectedTranche === 'senior'
51
+ ? poolState.seniorTrancheTokenSupply ?? 0
52
+ : poolState.juniorTrancheTokenSupply ?? 0,
53
+ )
54
+
55
+ useEffect(() => {
56
+ let cancelled = false
57
+ async function load() {
58
+ if (!stellarAddress) {
59
+ setIsLoadingDepositRecord(false)
60
+ return
61
+ }
62
+ setIsLoadingDepositRecord(true)
63
+ try {
64
+ const record = await fetchStellarDepositRecord(
65
+ poolInfo,
66
+ selectedTranche,
67
+ stellarAddress,
68
+ )
69
+ if (!cancelled) {
70
+ setPrincipal(record?.principal ?? 0n)
71
+ }
72
+ } finally {
73
+ if (!cancelled) {
74
+ setIsLoadingDepositRecord(false)
75
+ }
76
+ }
77
+ }
78
+ load()
79
+ return () => {
80
+ cancelled = true
81
+ }
82
+ }, [poolInfo, selectedTranche, stellarAddress])
83
+
84
+ const maxUnderlyingFormatted = useCallback(() => {
85
+ if (principal == null) return 0
86
+ return Number(tokenDecimalUtils.formatUnits(principal, underlyingDecimals))
87
+ }, [principal, underlyingDecimals])
88
+
89
+ const handleChangeAmount = useCallback(
90
+ (amount: number) => {
91
+ setCurrentAmount(amount)
92
+ dispatch(setRedeemAmount(amount))
93
+ if (amount <= 0 || totalAssets <= 0n) {
94
+ dispatch(setRedeemShares(0))
95
+ return
96
+ }
97
+ const underlyingRaw = tokenDecimalUtils.parseUnits(
98
+ String(amount),
99
+ underlyingDecimals,
100
+ )
101
+ const sharesRaw = getStellarSharesFromUnderlyingTokenAmount(
102
+ underlyingRaw,
103
+ totalAssets,
104
+ totalSupply,
105
+ )
106
+ const sharesFormatted = Number(
107
+ tokenDecimalUtils.formatUnits(sharesRaw, trancheDecimals),
108
+ )
109
+ dispatch(setRedeemShares(sharesFormatted))
110
+ },
111
+ [dispatch, underlyingDecimals, trancheDecimals, totalAssets, totalSupply],
112
+ )
113
+
114
+ const handleAction = useCallback(() => {
115
+ dispatch(setStep(WIDGET_STEP.Transfer))
116
+ }, [dispatch])
117
+
118
+ if (isLoadingDepositRecord) {
119
+ return <LoadingModal title='Redemption' />
120
+ }
121
+
122
+ const maxUnderlying = maxUnderlyingFormatted()
123
+
124
+ return (
125
+ <InputAmountModal
126
+ title='Redemption'
127
+ subTitle={`Enter amount of ${symbol} to withdraw from the ${selectedTranche} tranche`}
128
+ tokenSymbol={symbol}
129
+ currentAmount={currentAmount}
130
+ handleChangeAmount={handleChangeAmount}
131
+ maxAmount={maxUnderlying}
132
+ maxAmountTitle={`${formatNumber(maxUnderlying)} ${symbol} requestable`}
133
+ handleAction={handleAction}
134
+ actionText='REQUEST'
135
+ />
136
+ )
137
+ }
@@ -0,0 +1,70 @@
1
+ import {
2
+ STELLAR_CHAINS_INFO,
3
+ StellarPoolInfo,
4
+ tokenDecimalUtils,
5
+ TrancheType,
6
+ } from '@huma-finance/shared'
7
+ import { Client as TrancheVaultClient } from '@huma-finance/soroban-tranche-vault'
8
+ import AssembledTransaction from '@stellar/stellar-sdk'
9
+ import React, { useCallback, useContext, useEffect, useState } from 'react'
10
+
11
+ import {
12
+ getClientCommonParams,
13
+ StellarConnectionContext,
14
+ } from '@huma-finance/web-shared'
15
+ import { useAppDispatch, useAppSelector } from '../../../hooks/useRedux'
16
+ import { setStep } from '../../../store/widgets.reducers'
17
+ import { selectWidgetState } from '../../../store/widgets.selectors'
18
+ import { WIDGET_STEP } from '../../../store/widgets.store'
19
+ import { StellarTxSendModal } from '../../StellarTxSendModal'
20
+
21
+ type Props = {
22
+ poolInfo: StellarPoolInfo
23
+ selectedTranche: TrancheType
24
+ }
25
+
26
+ export function Transfer({
27
+ poolInfo,
28
+ selectedTranche,
29
+ }: Props): React.ReactElement | null {
30
+ const dispatch = useAppDispatch()
31
+ const [tx, setTx] = useState<typeof AssembledTransaction | null>(null)
32
+ const { address: stellarAddress } = useContext(StellarConnectionContext)
33
+ const { redeemShares } = useAppSelector(selectWidgetState)
34
+ const decimals = poolInfo.trancheDecimals
35
+ const sharesBN = tokenDecimalUtils.parseUnits(
36
+ String(redeemShares ?? 0),
37
+ decimals,
38
+ )
39
+
40
+ const handleSuccess = useCallback(async () => {
41
+ dispatch(setStep(WIDGET_STEP.Done))
42
+ }, [dispatch])
43
+
44
+ useEffect(() => {
45
+ async function getTx() {
46
+ if (!stellarAddress || sharesBN <= BigInt(0)) {
47
+ return
48
+ }
49
+
50
+ const chainMetadata = STELLAR_CHAINS_INFO[poolInfo.chainId]
51
+ const trancheVaultClient = new TrancheVaultClient({
52
+ publicKey: stellarAddress,
53
+ contractId:
54
+ selectedTranche === 'senior'
55
+ ? poolInfo.seniorTranche!
56
+ : poolInfo.juniorTranche,
57
+ ...getClientCommonParams(chainMetadata, stellarAddress),
58
+ })
59
+ const assembledTx = await trancheVaultClient.add_redemption_request({
60
+ caller: stellarAddress,
61
+ lender: stellarAddress,
62
+ shares: sharesBN,
63
+ })
64
+ setTx(assembledTx)
65
+ }
66
+ getTx()
67
+ }, [poolInfo, selectedTranche, stellarAddress, sharesBN])
68
+
69
+ return <StellarTxSendModal tx={tx} handleSuccess={handleSuccess} />
70
+ }
@@ -0,0 +1,33 @@
1
+ import { formatNumber, StellarPoolInfo } from '@huma-finance/shared'
2
+ import React, { useCallback } from 'react'
3
+ import { useAppSelector } from '../../../hooks/useRedux'
4
+ import { selectWidgetState } from '../../../store/widgets.selectors'
5
+ import { StellarTxDoneModal } from '../../StellarTxDoneModal'
6
+
7
+ type Props = {
8
+ poolInfo: StellarPoolInfo
9
+ handleAction: (options?: { isSuccess?: boolean }) => void
10
+ }
11
+
12
+ export function Done({ poolInfo, handleAction }: Props): React.ReactElement {
13
+ const { redeemAmount, txHash } = useAppSelector(selectWidgetState)
14
+ const { symbol } = poolInfo.underlyingToken
15
+
16
+ const content = [
17
+ `${formatNumber(redeemAmount ?? 0)} ${symbol} requested for withdrawal`,
18
+ ]
19
+
20
+ const handleUserAction = useCallback(() => {
21
+ handleAction({ isSuccess: true })
22
+ }, [handleAction])
23
+
24
+ return (
25
+ <StellarTxDoneModal
26
+ chainId={poolInfo.chainId}
27
+ handleAction={handleUserAction}
28
+ content={content}
29
+ txHash={txHash}
30
+ buttonText='DONE'
31
+ />
32
+ )
33
+ }
@@ -0,0 +1,88 @@
1
+ import {
2
+ CloseModalOptions,
3
+ StellarPoolInfo,
4
+ TrancheType,
5
+ } from '@huma-finance/shared'
6
+ import {
7
+ StellarConnectionContext,
8
+ StellarPoolState,
9
+ } from '@huma-finance/web-shared'
10
+ import React, { useContext, useEffect } from 'react'
11
+ import { useDispatch } from 'react-redux'
12
+
13
+ import { useAppSelector } from '../../../hooks/useRedux'
14
+ import { setStep } from '../../../store/widgets.reducers'
15
+ import { selectWidgetState } from '../../../store/widgets.selectors'
16
+ import { WIDGET_STEP } from '../../../store/widgets.store'
17
+ import { ErrorModal } from '../../ErrorModal'
18
+ import { WidgetWrapper } from '../../WidgetWrapper'
19
+ import { ChooseAmount } from './1-ChooseAmount'
20
+ import { Transfer } from './2-Transfer'
21
+ import { Done } from './3-Done'
22
+
23
+ /**
24
+ * Stellar add redemption props – request to withdraw (redeem) shares from a tranche.
25
+ * @property {StellarPoolInfo} poolInfo The metadata of the pool.
26
+ * @property {StellarPoolState} poolState The current state config of the pool.
27
+ * @property {TrancheType} tranche The tranche to redeem from (junior or senior).
28
+ * @property {function((CloseModalOptions|undefined)):void} handleClose Function to close the widget modal.
29
+ * @property {function():void|undefined} handleSuccess Optional callback when redemption request succeeds.
30
+ */
31
+ export interface StellarLendAddRedemptionProps {
32
+ poolInfo: StellarPoolInfo
33
+ poolState: StellarPoolState
34
+ tranche: TrancheType
35
+ handleClose: (options?: CloseModalOptions) => void
36
+ handleSuccess?: () => void
37
+ }
38
+
39
+ export function StellarLendAddRedemption({
40
+ poolInfo,
41
+ poolState,
42
+ tranche,
43
+ handleClose,
44
+ handleSuccess,
45
+ }: StellarLendAddRedemptionProps): React.ReactElement | null {
46
+ const dispatch = useDispatch()
47
+ const { address: stellarAddress } = useContext(StellarConnectionContext)
48
+ const { step, errorMessage } = useAppSelector(selectWidgetState)
49
+
50
+ useEffect(() => {
51
+ if (!step && stellarAddress) {
52
+ dispatch(setStep(WIDGET_STEP.ChooseAmount))
53
+ }
54
+ }, [dispatch, step, stellarAddress])
55
+
56
+ const title = 'Redemption'
57
+
58
+ return (
59
+ <WidgetWrapper
60
+ isOpen
61
+ loadingTitle={title}
62
+ handleClose={handleClose}
63
+ handleSuccess={handleSuccess}
64
+ >
65
+ {step === WIDGET_STEP.ChooseAmount && (
66
+ <ChooseAmount
67
+ poolInfo={poolInfo}
68
+ poolState={poolState}
69
+ selectedTranche={tranche}
70
+ />
71
+ )}
72
+ {step === WIDGET_STEP.Transfer && (
73
+ <Transfer poolInfo={poolInfo} selectedTranche={tranche} />
74
+ )}
75
+ {step === WIDGET_STEP.Done && (
76
+ <Done poolInfo={poolInfo} handleAction={handleClose} />
77
+ )}
78
+ {step === WIDGET_STEP.Error && (
79
+ <ErrorModal
80
+ title={title}
81
+ errorReason='Sorry there was an error'
82
+ errorMessage={errorMessage}
83
+ handleOk={handleClose}
84
+ />
85
+ )}
86
+ </WidgetWrapper>
87
+ )
88
+ }
package/src/index.tsx CHANGED
@@ -77,6 +77,10 @@ import {
77
77
  SolanaLendWithdraw,
78
78
  SolanaLendWithdrawProps,
79
79
  } from './components/Lend/solanaWithdraw'
80
+ import {
81
+ StellarLendAddRedemption,
82
+ StellarLendAddRedemptionProps,
83
+ } from './components/Lend/stellarAddRedemption'
80
84
  import {
81
85
  StellarLendSupply,
82
86
  StellarLendSupplyProps,
@@ -713,6 +717,28 @@ export function StellarLendSupplyWidget(props: StellarLendSupplyWidgetProps) {
713
717
  )
714
718
  }
715
719
 
720
+ /**
721
+ * Lend pool add redemption widget props for Stellar pools
722
+ * @typedef {Object} StellarLendAddRedemptionWidgetProps
723
+ */
724
+ type StellarLendAddRedemptionWidgetProps = StellarLendAddRedemptionProps &
725
+ GenericWidgetProps
726
+
727
+ /**
728
+ * Lend pool add redemption widget for Stellar pools
729
+ *
730
+ * @param {StellarLendAddRedemptionWidgetProps} props - Widget props
731
+ */
732
+ export function StellarLendAddRedemptionWidget(
733
+ props: StellarLendAddRedemptionWidgetProps,
734
+ ) {
735
+ return (
736
+ <GenericWidget {...props}>
737
+ <StellarLendAddRedemption {...props} />
738
+ </GenericWidget>
739
+ )
740
+ }
741
+
716
742
  /**
717
743
  * Borrow widget props for Stellar pools
718
744
  * @typedef {Object} StellarLendSupplyWidgetProps