@huma-finance/widgets 0.0.78-beta.1034 → 0.0.78-beta.1044
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.
- package/dist/index.js +12133 -10900
- package/dist/src/components/Lend/solanaWithdraw/1-Option.d.ts +12 -0
- package/dist/src/components/Lend/solanaWithdraw/2-WithdrawAndDepositConfirm.d.ts +15 -0
- package/dist/src/components/Lend/solanaWithdraw/{1-ConfirmTransfer.d.ts → 3-WithdrawOnlyConfirm.d.ts} +1 -1
- package/dist/src/components/Lend/solanaWithdraw/4-TransferAndDeposit.d.ts +13 -0
- package/dist/src/components/Lend/solanaWithdraw/{3-Done.d.ts → 6-Done.d.ts} +3 -1
- package/dist/src/components/Lend/solanaWithdraw/components/Apy.d.ts +7 -0
- package/dist/src/components/Lend/solanaWithdraw/components/Benefit.d.ts +2 -0
- package/dist/src/components/Lend/solanaWithdraw/components/CommitSwitcher.d.ts +12 -0
- package/dist/src/components/Lend/solanaWithdraw/components/ModeSelector.d.ts +12 -0
- package/dist/src/components/Lend/solanaWithdraw/components/SelectModeTitle.d.ts +2 -0
- package/dist/src/components/Lend/solanaWithdraw/index.d.ts +10 -0
- package/dist/src/components/TxDoneModal.d.ts +1 -1
- package/dist/src/components/WidgetWrapper.d.ts +2 -1
- package/dist/src/components/icons/index.d.ts +7 -0
- package/dist/src/store/widgets.store.d.ts +3 -0
- package/package.json +5 -5
- package/src/components/Lend/solanaWithdraw/1-Option.tsx +180 -0
- package/src/components/Lend/solanaWithdraw/2-WithdrawAndDepositConfirm.tsx +208 -0
- package/src/components/Lend/solanaWithdraw/{1-ConfirmTransfer.tsx → 3-WithdrawOnlyConfirm.tsx} +2 -2
- package/src/components/Lend/solanaWithdraw/4-TransferAndDeposit.tsx +274 -0
- package/src/components/Lend/solanaWithdraw/{3-Done.tsx → 6-Done.tsx} +27 -3
- package/src/components/Lend/solanaWithdraw/components/Apy.tsx +126 -0
- package/src/components/Lend/solanaWithdraw/components/Benefit.tsx +63 -0
- package/src/components/Lend/solanaWithdraw/components/CommitSwitcher.tsx +198 -0
- package/src/components/Lend/solanaWithdraw/components/ModeSelector.tsx +148 -0
- package/src/components/Lend/solanaWithdraw/components/SelectModeTitle.tsx +61 -0
- package/src/components/Lend/solanaWithdraw/index.tsx +102 -12
- package/src/components/TxDoneModal.tsx +3 -3
- package/src/components/WidgetWrapper.tsx +3 -1
- package/src/components/icons/huma-no-empty-space.svg +15 -0
- package/src/components/icons/index.tsx +49 -14
- package/src/components/icons/minus-sign-inactive.svg +4 -0
- package/src/components/icons/minus-sign.svg +14 -0
- package/src/components/icons/mode-classic.svg +3 -0
- package/src/components/icons/mode-maxi.svg +3 -0
- package/src/components/icons/plus-sign-inactive.svg +4 -0
- package/src/components/icons/plus-sign.svg +14 -0
- package/src/hooks/useLogOnFirstMount.ts +1 -1
- package/src/store/widgets.store.ts +3 -0
- /package/dist/src/components/Lend/solanaWithdraw/{2-Transfer.d.ts → 5-Transfer.d.ts} +0 -0
- /package/src/components/Lend/solanaWithdraw/{2-Transfer.tsx → 5-Transfer.tsx} +0 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { BN } from '@coral-xyz/anchor'
|
|
2
|
+
import {
|
|
3
|
+
getSolanaNetworkType,
|
|
4
|
+
getTokenAccounts,
|
|
5
|
+
PermissionlessDepositCommitment,
|
|
6
|
+
PermissionlessDepositMode,
|
|
7
|
+
PermissionlessService,
|
|
8
|
+
SOLANA_CHAIN_INFO_PERMISSIONLESS,
|
|
9
|
+
SolanaPoolInfo,
|
|
10
|
+
TrancheType,
|
|
11
|
+
} from '@huma-finance/shared'
|
|
12
|
+
import {
|
|
13
|
+
checkIsDev,
|
|
14
|
+
logErrorRaw,
|
|
15
|
+
useHumaProgram,
|
|
16
|
+
usePermissionlessLenderModeATA,
|
|
17
|
+
usePermissionlessLenderStateAccount,
|
|
18
|
+
usePermissionlessProgram,
|
|
19
|
+
} from '@huma-finance/web-shared'
|
|
20
|
+
import {
|
|
21
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
22
|
+
createAssociatedTokenAccountIdempotentInstruction,
|
|
23
|
+
createAssociatedTokenAccountInstruction,
|
|
24
|
+
getAccount,
|
|
25
|
+
TOKEN_2022_PROGRAM_ID,
|
|
26
|
+
TOKEN_PROGRAM_ID,
|
|
27
|
+
TokenAccountNotFoundError,
|
|
28
|
+
TokenInvalidAccountOwnerError,
|
|
29
|
+
} from '@solana/spl-token'
|
|
30
|
+
import { useConnection, useWallet } from '@solana/wallet-adapter-react'
|
|
31
|
+
import { ComputeBudgetProgram, PublicKey, Transaction } from '@solana/web3.js'
|
|
32
|
+
import React, { useCallback, useEffect, useState } from 'react'
|
|
33
|
+
import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
|
|
34
|
+
import { useAppDispatch } from '../../../hooks/useRedux'
|
|
35
|
+
import { setStep } from '../../../store/widgets.reducers'
|
|
36
|
+
import { WIDGET_STEP } from '../../../store/widgets.store'
|
|
37
|
+
import { SolanaTxSendModal } from '../../SolanaTxSendModal'
|
|
38
|
+
|
|
39
|
+
type Props = {
|
|
40
|
+
poolInfo: SolanaPoolInfo
|
|
41
|
+
selectedTranche: TrancheType
|
|
42
|
+
poolIsClosed: boolean
|
|
43
|
+
permissionlessMode: PermissionlessDepositMode
|
|
44
|
+
withdrawableAmount: BN
|
|
45
|
+
depositCommitment: PermissionlessDepositCommitment
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function TransferAndDeposit({
|
|
49
|
+
poolInfo,
|
|
50
|
+
selectedTranche,
|
|
51
|
+
poolIsClosed,
|
|
52
|
+
permissionlessMode,
|
|
53
|
+
withdrawableAmount,
|
|
54
|
+
depositCommitment,
|
|
55
|
+
}: Props): React.ReactElement | null {
|
|
56
|
+
useLogOnFirstMount('RedepositTransaction')
|
|
57
|
+
const { publicKey } = useWallet()
|
|
58
|
+
const dispatch = useAppDispatch()
|
|
59
|
+
const { connection } = useConnection()
|
|
60
|
+
const program = useHumaProgram(poolInfo.chainId)
|
|
61
|
+
const programPermissionless = usePermissionlessProgram()
|
|
62
|
+
const [transaction, setTransaction] = useState<Transaction>()
|
|
63
|
+
const { lenderStateAccount, isLoaded: isLoadedLenderStateAccount } =
|
|
64
|
+
usePermissionlessLenderStateAccount(poolInfo.chainId, permissionlessMode)
|
|
65
|
+
const solanaChainInfoPermissionless =
|
|
66
|
+
SOLANA_CHAIN_INFO_PERMISSIONLESS[poolInfo.chainId]
|
|
67
|
+
const { lenderClassicModeTokenATA, lenderMaxiModeTokenATA } =
|
|
68
|
+
usePermissionlessLenderModeATA(poolInfo.chainId)
|
|
69
|
+
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
async function getTx() {
|
|
72
|
+
if (
|
|
73
|
+
!publicKey ||
|
|
74
|
+
transaction ||
|
|
75
|
+
!connection ||
|
|
76
|
+
!isLoadedLenderStateAccount ||
|
|
77
|
+
!lenderClassicModeTokenATA ||
|
|
78
|
+
!lenderMaxiModeTokenATA
|
|
79
|
+
) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const tx = new Transaction()
|
|
84
|
+
const { underlyingTokenATA, seniorTrancheATA, juniorTrancheATA } =
|
|
85
|
+
getTokenAccounts(poolInfo, publicKey)
|
|
86
|
+
const trancheMint =
|
|
87
|
+
selectedTranche === 'senior'
|
|
88
|
+
? poolInfo.seniorTrancheMint
|
|
89
|
+
: poolInfo.juniorTrancheMint
|
|
90
|
+
const lenderTrancheToken =
|
|
91
|
+
selectedTranche === 'senior' ? seniorTrancheATA : juniorTrancheATA
|
|
92
|
+
|
|
93
|
+
// Create user token account if it doesn't exist
|
|
94
|
+
let createdAccounts = false
|
|
95
|
+
try {
|
|
96
|
+
await getAccount(
|
|
97
|
+
connection,
|
|
98
|
+
underlyingTokenATA,
|
|
99
|
+
undefined,
|
|
100
|
+
TOKEN_PROGRAM_ID,
|
|
101
|
+
)
|
|
102
|
+
} catch (error: unknown) {
|
|
103
|
+
// TokenAccountNotFoundError can be possible if the associated address has already received some lamports,
|
|
104
|
+
// becoming a system account. Assuming program derived addressing is safe, this is the only case for the
|
|
105
|
+
// TokenInvalidAccountOwnerError in this code path.
|
|
106
|
+
// Source: https://solana.stackexchange.com/questions/802/checking-to-see-if-a-token-account-exists-using-anchor-ts
|
|
107
|
+
if (
|
|
108
|
+
error instanceof TokenAccountNotFoundError ||
|
|
109
|
+
error instanceof TokenInvalidAccountOwnerError
|
|
110
|
+
) {
|
|
111
|
+
// As this isn't atomic, it's possible others can create associated accounts meanwhile.
|
|
112
|
+
createdAccounts = true
|
|
113
|
+
tx.add(
|
|
114
|
+
createAssociatedTokenAccountInstruction(
|
|
115
|
+
publicKey,
|
|
116
|
+
underlyingTokenATA,
|
|
117
|
+
publicKey,
|
|
118
|
+
new PublicKey(poolInfo.underlyingMint.address),
|
|
119
|
+
TOKEN_PROGRAM_ID,
|
|
120
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
121
|
+
),
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!poolIsClosed) {
|
|
127
|
+
const disburseTx = await program.methods
|
|
128
|
+
.disburse()
|
|
129
|
+
.accountsPartial({
|
|
130
|
+
lender: publicKey,
|
|
131
|
+
humaConfig: poolInfo.humaConfig,
|
|
132
|
+
poolConfig: poolInfo.poolConfig,
|
|
133
|
+
underlyingMint: poolInfo.underlyingMint.address,
|
|
134
|
+
trancheMint,
|
|
135
|
+
poolUnderlyingToken: poolInfo.poolUnderlyingTokenAccount,
|
|
136
|
+
lenderUnderlyingToken: underlyingTokenATA,
|
|
137
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
138
|
+
})
|
|
139
|
+
.transaction()
|
|
140
|
+
tx.add(disburseTx)
|
|
141
|
+
} else {
|
|
142
|
+
const withdrawAfterPoolClosureTx = await program.methods
|
|
143
|
+
.withdrawAfterPoolClosure()
|
|
144
|
+
.accountsPartial({
|
|
145
|
+
lender: publicKey,
|
|
146
|
+
humaConfig: poolInfo.humaConfig,
|
|
147
|
+
poolConfig: poolInfo.poolConfig,
|
|
148
|
+
underlyingMint: poolInfo.underlyingMint.address,
|
|
149
|
+
trancheMint,
|
|
150
|
+
poolUnderlyingToken: poolInfo.poolUnderlyingTokenAccount,
|
|
151
|
+
lenderUnderlyingToken: underlyingTokenATA,
|
|
152
|
+
lenderTrancheToken,
|
|
153
|
+
underlyingTokenProgram: TOKEN_PROGRAM_ID,
|
|
154
|
+
trancheTokenProgram: TOKEN_2022_PROGRAM_ID,
|
|
155
|
+
})
|
|
156
|
+
.transaction()
|
|
157
|
+
tx.add(withdrawAfterPoolClosureTx)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const permissionlessModeConfig =
|
|
161
|
+
permissionlessMode === PermissionlessDepositMode.CLASSIC
|
|
162
|
+
? solanaChainInfoPermissionless.classicModeConfig
|
|
163
|
+
: solanaChainInfoPermissionless.maxiModeConfig
|
|
164
|
+
const permissonlessLenderModeTokenATA =
|
|
165
|
+
permissionlessMode === PermissionlessDepositMode.CLASSIC
|
|
166
|
+
? lenderClassicModeTokenATA
|
|
167
|
+
: lenderMaxiModeTokenATA
|
|
168
|
+
|
|
169
|
+
if (!lenderStateAccount) {
|
|
170
|
+
const createLenderAccountInstruction =
|
|
171
|
+
await programPermissionless.methods
|
|
172
|
+
.createLenderAccounts()
|
|
173
|
+
.accountsPartial({
|
|
174
|
+
lender: publicKey,
|
|
175
|
+
humaConfig: solanaChainInfoPermissionless.humaConfig,
|
|
176
|
+
poolConfig: solanaChainInfoPermissionless.poolConfig,
|
|
177
|
+
modeConfig: permissionlessModeConfig,
|
|
178
|
+
lenderModeToken: permissonlessLenderModeTokenATA,
|
|
179
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
180
|
+
})
|
|
181
|
+
.transaction()
|
|
182
|
+
tx.add(createLenderAccountInstruction)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
tx.add(
|
|
186
|
+
createAssociatedTokenAccountIdempotentInstruction(
|
|
187
|
+
publicKey,
|
|
188
|
+
permissonlessLenderModeTokenATA,
|
|
189
|
+
publicKey,
|
|
190
|
+
new PublicKey(
|
|
191
|
+
permissionlessMode === PermissionlessDepositMode.CLASSIC
|
|
192
|
+
? solanaChainInfoPermissionless.classicModeMint
|
|
193
|
+
: solanaChainInfoPermissionless.maxiModeMint,
|
|
194
|
+
),
|
|
195
|
+
TOKEN_PROGRAM_ID,
|
|
196
|
+
),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
const depositTx = await programPermissionless.methods
|
|
200
|
+
.deposit(withdrawableAmount, depositCommitment, false)
|
|
201
|
+
.accountsPartial({
|
|
202
|
+
depositor: publicKey,
|
|
203
|
+
humaConfig: solanaChainInfoPermissionless.humaConfig,
|
|
204
|
+
poolConfig: solanaChainInfoPermissionless.poolConfig,
|
|
205
|
+
modeConfig: permissionlessModeConfig,
|
|
206
|
+
underlyingMint: solanaChainInfoPermissionless.underlyingMint,
|
|
207
|
+
underlyingTokenProgram: TOKEN_PROGRAM_ID,
|
|
208
|
+
modeTokenProgram: TOKEN_PROGRAM_ID,
|
|
209
|
+
})
|
|
210
|
+
.transaction()
|
|
211
|
+
tx.add(depositTx)
|
|
212
|
+
|
|
213
|
+
if (createdAccounts) {
|
|
214
|
+
tx.instructions.unshift(
|
|
215
|
+
ComputeBudgetProgram.setComputeUnitLimit({
|
|
216
|
+
units: poolIsClosed ? 145_000 : 105_000,
|
|
217
|
+
}),
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
setTransaction(tx)
|
|
222
|
+
}
|
|
223
|
+
getTx()
|
|
224
|
+
}, [
|
|
225
|
+
connection,
|
|
226
|
+
depositCommitment,
|
|
227
|
+
isLoadedLenderStateAccount,
|
|
228
|
+
lenderClassicModeTokenATA,
|
|
229
|
+
lenderMaxiModeTokenATA,
|
|
230
|
+
lenderStateAccount,
|
|
231
|
+
permissionlessMode,
|
|
232
|
+
poolInfo,
|
|
233
|
+
poolIsClosed,
|
|
234
|
+
program.methods,
|
|
235
|
+
programPermissionless.methods,
|
|
236
|
+
publicKey,
|
|
237
|
+
selectedTranche,
|
|
238
|
+
solanaChainInfoPermissionless,
|
|
239
|
+
transaction,
|
|
240
|
+
withdrawableAmount,
|
|
241
|
+
])
|
|
242
|
+
|
|
243
|
+
const handleSuccess = useCallback(
|
|
244
|
+
async (options?: { signature: string }) => {
|
|
245
|
+
const isDev = checkIsDev()
|
|
246
|
+
if (publicKey && options?.signature) {
|
|
247
|
+
try {
|
|
248
|
+
await PermissionlessService.updatePermissionlessDeposit(
|
|
249
|
+
getSolanaNetworkType(poolInfo.chainId),
|
|
250
|
+
isDev,
|
|
251
|
+
publicKey.toString(),
|
|
252
|
+
poolInfo.chainId,
|
|
253
|
+
options?.signature,
|
|
254
|
+
)
|
|
255
|
+
} catch (error) {
|
|
256
|
+
logErrorRaw(error, {
|
|
257
|
+
message: 'Failed to update permissionless deposit',
|
|
258
|
+
})
|
|
259
|
+
console.error('Failed to update permissionless deposit', error)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
dispatch(setStep(WIDGET_STEP.Done))
|
|
263
|
+
},
|
|
264
|
+
[dispatch, poolInfo.chainId, publicKey],
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<SolanaTxSendModal
|
|
269
|
+
tx={transaction}
|
|
270
|
+
chainId={poolInfo.chainId}
|
|
271
|
+
handleSuccess={handleSuccess}
|
|
272
|
+
/>
|
|
273
|
+
)
|
|
274
|
+
}
|
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
import { BN } from '@coral-xyz/anchor'
|
|
2
2
|
import {
|
|
3
|
+
configUtil,
|
|
3
4
|
formatMoneyFixed,
|
|
4
5
|
SolanaTokenUtils,
|
|
5
6
|
UnderlyingTokenInfo,
|
|
6
7
|
} from '@huma-finance/shared'
|
|
8
|
+
import { Link } from '@mui/material'
|
|
7
9
|
import React from 'react'
|
|
8
|
-
import {
|
|
10
|
+
import { ClaimAndStakeOption, WithdrawOption } from '.'
|
|
9
11
|
import useLogOnFirstMount from '../../../hooks/useLogOnFirstMount'
|
|
12
|
+
import { TxDoneModal } from '../../TxDoneModal'
|
|
10
13
|
|
|
11
14
|
type Props = {
|
|
12
15
|
poolUnderlyingToken: UnderlyingTokenInfo
|
|
13
16
|
withdrawAmount: BN
|
|
17
|
+
option: ClaimAndStakeOption
|
|
14
18
|
handleAction: () => void
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
export function Done({
|
|
18
22
|
poolUnderlyingToken,
|
|
19
23
|
withdrawAmount,
|
|
24
|
+
option,
|
|
20
25
|
handleAction,
|
|
21
26
|
}: Props): React.ReactElement {
|
|
22
|
-
useLogOnFirstMount(
|
|
27
|
+
useLogOnFirstMount(
|
|
28
|
+
option.id === WithdrawOption.WITHDRAW_AND_REDEPOSIT
|
|
29
|
+
? 'RedepositSuccess'
|
|
30
|
+
: 'WithdrawSuccess',
|
|
31
|
+
)
|
|
23
32
|
const { symbol } = poolUnderlyingToken
|
|
24
33
|
const withdrawAmountFormatted = formatMoneyFixed(
|
|
25
34
|
SolanaTokenUtils.formatUnits(withdrawAmount, poolUnderlyingToken.decimals),
|
|
@@ -27,7 +36,22 @@ export function Done({
|
|
|
27
36
|
)
|
|
28
37
|
|
|
29
38
|
const content = [
|
|
30
|
-
|
|
39
|
+
option.id === WithdrawOption.WITHDRAW_AND_REDEPOSIT ? (
|
|
40
|
+
<>
|
|
41
|
+
You have withdrawn {withdrawAmountFormatted} {symbol} and redeposited to
|
|
42
|
+
Huma Permissionless.{' '}
|
|
43
|
+
<Link
|
|
44
|
+
href={configUtil.dappLink}
|
|
45
|
+
target='_blank'
|
|
46
|
+
rel='noopener noreferrer'
|
|
47
|
+
>
|
|
48
|
+
Go to Huma Permissionless
|
|
49
|
+
</Link>{' '}
|
|
50
|
+
to view your deposit.
|
|
51
|
+
</>
|
|
52
|
+
) : (
|
|
53
|
+
`You successfully withdrew ${withdrawAmountFormatted} ${symbol}.`
|
|
54
|
+
),
|
|
31
55
|
]
|
|
32
56
|
|
|
33
57
|
return <TxDoneModal handleAction={handleAction} content={content} />
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { toPercentage } from '@huma-finance/shared'
|
|
2
|
+
import InfoOutlineIcon from '@mui/icons-material/InfoOutlined'
|
|
3
|
+
import { Box, css, Tooltip, useTheme } from '@mui/material'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import { HumaNoEmptySpaceIcon, UsdcIcon } from '../../../icons'
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
usdcApy: number | undefined
|
|
9
|
+
humaRewardsApy: number | undefined
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Apy({ usdcApy, humaRewardsApy }: Props): React.ReactElement {
|
|
13
|
+
const theme = useTheme()
|
|
14
|
+
|
|
15
|
+
const styles = {
|
|
16
|
+
container: css`
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
margin-top: ${theme.spacing(2)};
|
|
20
|
+
`,
|
|
21
|
+
usdcApy: css`
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: space-between;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: ${theme.spacing(0.5)};
|
|
26
|
+
`,
|
|
27
|
+
usdcApyTitle: css`
|
|
28
|
+
display: flex;
|
|
29
|
+
justify-content: space-between;
|
|
30
|
+
align-items: center;
|
|
31
|
+
gap: ${theme.spacing(0.5)};
|
|
32
|
+
color: #b8b8b8;
|
|
33
|
+
font-size: 16px;
|
|
34
|
+
font-weight: 500;
|
|
35
|
+
line-height: 150%;
|
|
36
|
+
letter-spacing: 0.15px;
|
|
37
|
+
`,
|
|
38
|
+
usdcApyValue: css`
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: ${theme.spacing(0.5)};
|
|
42
|
+
color: #b8b8b8;
|
|
43
|
+
font-size: 16px;
|
|
44
|
+
font-weight: 500;
|
|
45
|
+
line-height: 150%;
|
|
46
|
+
letter-spacing: 0.15px;
|
|
47
|
+
|
|
48
|
+
& > svg {
|
|
49
|
+
width: 16px;
|
|
50
|
+
height: 16px;
|
|
51
|
+
}
|
|
52
|
+
`,
|
|
53
|
+
humaRewardsApy: css`
|
|
54
|
+
display: flex;
|
|
55
|
+
justify-content: space-between;
|
|
56
|
+
align-items: center;
|
|
57
|
+
gap: ${theme.spacing(0.5)};
|
|
58
|
+
`,
|
|
59
|
+
humaRewardsApyValue: css`
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
gap: ${theme.spacing(0.5)};
|
|
63
|
+
color: #b8b8b8;
|
|
64
|
+
font-size: 16px;
|
|
65
|
+
font-weight: 500;
|
|
66
|
+
line-height: 150%;
|
|
67
|
+
letter-spacing: 0.15px;
|
|
68
|
+
|
|
69
|
+
& > svg {
|
|
70
|
+
width: 16px;
|
|
71
|
+
height: 16px;
|
|
72
|
+
}
|
|
73
|
+
`,
|
|
74
|
+
infoIcon: css`
|
|
75
|
+
width: 16px;
|
|
76
|
+
height: 16px;
|
|
77
|
+
color: #686868;
|
|
78
|
+
`,
|
|
79
|
+
humaRewardsApyTitle: css`
|
|
80
|
+
display: flex;
|
|
81
|
+
justify-content: space-between;
|
|
82
|
+
align-items: center;
|
|
83
|
+
gap: ${theme.spacing(0.5)};
|
|
84
|
+
color: #b8b8b8;
|
|
85
|
+
font-size: 16px;
|
|
86
|
+
font-weight: 500;
|
|
87
|
+
line-height: 150%;
|
|
88
|
+
letter-spacing: 0.15px;
|
|
89
|
+
`,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<Box css={styles.container}>
|
|
94
|
+
<Box css={styles.usdcApy}>
|
|
95
|
+
<Box css={styles.usdcApyTitle}>
|
|
96
|
+
<Box>USDC yield</Box>
|
|
97
|
+
<Tooltip
|
|
98
|
+
title='Current monthly USDC APY for Classic mode.'
|
|
99
|
+
placement='top'
|
|
100
|
+
>
|
|
101
|
+
<InfoOutlineIcon css={styles.infoIcon} />
|
|
102
|
+
</Tooltip>
|
|
103
|
+
</Box>
|
|
104
|
+
<Box css={styles.usdcApyValue}>
|
|
105
|
+
<Box>{toPercentage(usdcApy, 1)}</Box>
|
|
106
|
+
<UsdcIcon />
|
|
107
|
+
</Box>
|
|
108
|
+
</Box>
|
|
109
|
+
<Box css={styles.humaRewardsApy}>
|
|
110
|
+
<Box css={styles.humaRewardsApyTitle}>
|
|
111
|
+
<Box>Huma rewards</Box>
|
|
112
|
+
<Tooltip
|
|
113
|
+
title='Returns are estimated based on the 7-day average price of $HUMA.'
|
|
114
|
+
placement='top'
|
|
115
|
+
>
|
|
116
|
+
<InfoOutlineIcon css={styles.infoIcon} />
|
|
117
|
+
</Tooltip>
|
|
118
|
+
</Box>
|
|
119
|
+
<Box css={styles.humaRewardsApyValue}>
|
|
120
|
+
<Box>{toPercentage(humaRewardsApy, 1)}</Box>
|
|
121
|
+
<HumaNoEmptySpaceIcon />
|
|
122
|
+
</Box>
|
|
123
|
+
</Box>
|
|
124
|
+
</Box>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Box, css, Link, useTheme } from '@mui/material'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
export function Benefit(): React.ReactElement {
|
|
5
|
+
const theme = useTheme()
|
|
6
|
+
|
|
7
|
+
const styles = {
|
|
8
|
+
container: css`
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
margin-top: ${theme.spacing(2)};
|
|
12
|
+
`,
|
|
13
|
+
title: css`
|
|
14
|
+
color: #b8b8b8;
|
|
15
|
+
font-size: 16px;
|
|
16
|
+
font-weight: 700;
|
|
17
|
+
line-height: 175%;
|
|
18
|
+
letter-spacing: 0.15px;
|
|
19
|
+
`,
|
|
20
|
+
list: css`
|
|
21
|
+
margin-top: ${theme.spacing(0)};
|
|
22
|
+
padding-left: ${theme.spacing(2)};
|
|
23
|
+
`,
|
|
24
|
+
listItem: css`
|
|
25
|
+
color: #686868;
|
|
26
|
+
font-size: 14px;
|
|
27
|
+
font-weight: 500;
|
|
28
|
+
line-height: 143%;
|
|
29
|
+
letter-spacing: 0.17px;
|
|
30
|
+
`,
|
|
31
|
+
link: css`
|
|
32
|
+
color: #686868;
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
font-weight: 500;
|
|
35
|
+
line-height: 143%;
|
|
36
|
+
letter-spacing: 0.17px;
|
|
37
|
+
`,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Box css={styles.container}>
|
|
42
|
+
<Box css={styles.title}>Permissionless benefits</Box>
|
|
43
|
+
<ul css={styles.list}>
|
|
44
|
+
<li css={styles.listItem}>
|
|
45
|
+
Keep your OG status and unlock boosted yield forever
|
|
46
|
+
</li>
|
|
47
|
+
<li css={styles.listItem}>Choose your own investment lockup periods</li>
|
|
48
|
+
<li css={styles.listItem}>Earn incentives for longer commitments</li>
|
|
49
|
+
<li css={styles.listItem}>
|
|
50
|
+
<Link
|
|
51
|
+
href='https://app.huma.finance/faqs'
|
|
52
|
+
target='_blank'
|
|
53
|
+
rel='noopener noreferrer'
|
|
54
|
+
css={styles.link}
|
|
55
|
+
>
|
|
56
|
+
Read more
|
|
57
|
+
</Link>{' '}
|
|
58
|
+
about the Permissionless benefits
|
|
59
|
+
</li>
|
|
60
|
+
</ul>
|
|
61
|
+
</Box>
|
|
62
|
+
)
|
|
63
|
+
}
|