Skip to content

Commit

Permalink
Fix rewards calculation and check getWithdrawableBalance before initi…
Browse files Browse the repository at this point in the history
…ating withdraw
  • Loading branch information
ccali11 committed Oct 25, 2023
1 parent f8bd5c7 commit 3a7899b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 38 deletions.
25 changes: 17 additions & 8 deletions apps/web/src/composables/breakdownMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,25 @@ export default function useBreakdownMetrics() {
addresses.forEach(address => {userEventTotalsPromises.push(getContractEventsTotalsByAddress(address, eigenManager))})
const userEventTotals = await Promise.all(userEventTotalsPromises) as Array<ContractEventsByAddress>
const userEventTotalsSum = userEventTotals.reduce((acc, curr) => {
const { StakeDeposited, WithdrawalInitiated } = curr
const { StakeDeposited, WithdrawalInitiated, WithdrawalRequested, WithdrawalFulfilled } = curr
return {
StakeDeposited: acc.StakeDeposited + (StakeDeposited || 0),
WithdrawalInitiated: acc.WithdrawalInitiated + (WithdrawalInitiated || 0),
WithdrawalRequested: acc.WithdrawalRequested + (WithdrawalRequested || 0),
WithdrawalFulfilled: acc.WithdrawalFulfilled + (WithdrawalFulfilled || 0)
}
}, { StakeDeposited: 0, WithdrawalInitiated: 0 } as { StakeDeposited: number; WithdrawalInitiated: number })
}, { StakeDeposited: 0, WithdrawalInitiated: 0, WithdrawalRequested: 0, WithdrawalFulfilled: 0 } as { StakeDeposited: number; WithdrawalInitiated: number, WithdrawalRequested: number, WithdrawalFulfilled: number })


const stakedDepositedETH = userEventTotalsSum.StakeDeposited
const withdrawalInitiatedETH = userEventTotalsSum.WithdrawalInitiated
const withdrawalRequestedETH = userEventTotalsSum.WithdrawalRequested
const withdrawalFulfilledETH = userEventTotalsSum.WithdrawalFulfilled


/* Get User's All Time Rewards */
const currentUserStakeMinusEvents = currentUserStakeETH - stakedDepositedETH + ((withdrawalInitiatedETH) + (withdrawalRequestedETH) + (withdrawalFulfilledETH))

/* Get User's All Time Rewards by Subtracting (StakeDeposited + WithdrawalInitiated) from CurrentStake */
const currentUserStakeMinusEvents = currentUserStakeETH - (stakedDepositedETH as number) - (withdrawalInitiatedETH as number)
return {
eth: `${formatNumber(currentUserStakeMinusEvents)} ETH`,
usd: `$${formatNumber(currentUserStakeMinusEvents * (await getCurrentPrice({ coin: 'ETH', currency: 'USD' })))}`
Expand All @@ -96,7 +102,9 @@ export default function useBreakdownMetrics() {
const eventList = [
'StakeDeposited',
'StakeRebalanced',
'WithdrawalInitiated'
'WithdrawalInitiated',
'WithdrawalRequested',
'WithdrawalFulfilled'
]
const eventFilters = eventList.map(event => {
if (event === 'StakeRebalanced') return (manager as CasimirManager).filters[event]()
Expand All @@ -120,14 +128,15 @@ export default function useBreakdownMetrics() {
userEventTotals[event as string] += amountInEth
}
}

return userEventTotals
return userEventTotals as ContractEventsByAddress
} catch (err) {
console.error(`There was an error in getContractEventsTotalsByAddress: ${err}`)
return {
StakeDeposited: 0,
StakeRebalanced: 0,
WithdrawalInitiated: 0
WithdrawalInitiated: 0,
WithdrawalRequested: 0,
WithdrawalFulfilled: 0
}
}
}
Expand Down
30 changes: 22 additions & 8 deletions apps/web/src/composables/staking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ export default function useStaking() {
}
}

async function getWithdrawableBalance({walletProvider, type}: {walletProvider: ProviderString, type: 'default' | 'eigen'}) {
let signer
if (ethersProviderList.includes(walletProvider)) {
signer = getEthersBrowserSigner(walletProvider)
} else if (walletProvider === 'WalletConnect') {
await getWalletConnectSignerV2()
} else if (walletProvider === 'Ledger') {
getEthersLedgerSigner()
} else if (walletProvider === 'Trezor') {
getEthersTrezorSigner()
} else {
throw new Error(`Invalid wallet provider: ${walletProvider}`)
}
const manager = type === 'default' ? defaultManager : eigenManager
const managerSigner = (manager as CasimirManager).connect(signer as ethers.Signer)
const withdrawableBalance = await managerSigner.getWithdrawableBalance()
const withdrawableBalanceEther = ethers.utils.formatEther(withdrawableBalance)
return withdrawableBalanceEther
}

async function withdraw({ amount, walletProvider, type }: { amount: string, walletProvider: ProviderString, type: 'default' | 'eigen' }) {
let signer
if (ethersProviderList.includes(walletProvider)) {
Expand All @@ -106,14 +126,7 @@ export default function useStaking() {
const manager = type === 'default' ? defaultManager : eigenManager
const managerSigner = (manager as CasimirManager).connect(signer as ethers.Signer)
const value = ethers.utils.parseEther(amount)
// const withdrawableBalance = await (manager as CasimirManager).getWithdrawableBalance()
const bufferedBalance = await managerSigner.getBufferedBalance()
const bufferedBalanceNumber = parseFloat(ethers.utils.formatEther(bufferedBalance))
const result = await managerSigner.requestWithdrawal(value)
return {
result,
bufferedBalance: bufferedBalanceNumber
}
return await managerSigner.requestWithdrawal(value)
}

return {
Expand All @@ -122,6 +135,7 @@ export default function useStaking() {
deposit,
getDepositFees,
getUserStake,
getWithdrawableBalance,
withdraw
}
}
53 changes: 31 additions & 22 deletions apps/web/src/pages/overview/components/Staking.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import confetti from 'canvas-confetti'
import TermsOfService from '@/components/TermsOfService.vue'
const { stakingComposableInitialized, deposit, initializeStakingComposable, withdraw } = useStaking()
const { stakingComposableInitialized, deposit, initializeStakingComposable, withdraw, getWithdrawableBalance } = useStaking()
const { getEthersBalance } = useEthers()
const { convertString } = useFormat()
const { getCurrentPrice } = usePrice()
Expand All @@ -24,7 +24,7 @@ const stakeType = ref<'default' | 'eigen'>('default')
const currentUserStake = ref(0)
const estimatedFees = ref<number | string>('-')
const estimatedAPY = ref<string>('4.00')
const formattedAmountToStake = ref('')
const formattedAmountToStakeOrWithdraw = ref('')
const formattedWalletOptions = ref<Array<FormattedWalletOption>>([])
const selectedStakingProvider = ref<ProviderString>('')
const selectedWalletAddress = ref(null as null | string)
Expand Down Expand Up @@ -97,7 +97,7 @@ const handleInputOnAmountToStake = (event: any) => {
}
// Update the model value
formattedAmountToStake.value = parts.join('.')
formattedAmountToStakeOrWithdraw.value = parts.join('.')
}
const selectAmountInput = () => {
Expand Down Expand Up @@ -131,15 +131,15 @@ const aggregateAddressesByProvider = () => {
// empty out staking comp
selectedStakingProvider.value = ''
selectedWalletAddress.value = null
formattedAmountToStake.value = ''
formattedAmountToStakeOrWithdraw.value = ''
addressBalance.value = null
currentUserStake.value = 0
}
}
watch(formattedAmountToStake, async () => {
if (formattedAmountToStake.value) {
const floatAmount = parseFloat(formattedAmountToStake.value?.replace(/,/g, ''))
watch(formattedAmountToStakeOrWithdraw, async () => {
if (formattedAmountToStakeOrWithdraw.value) {
const floatAmount = parseFloat(formattedAmountToStakeOrWithdraw.value?.replace(/,/g, ''))
let maxAmount
// minAmount is 0.0001 ETH
let minAmount = 0.0001
Expand Down Expand Up @@ -186,7 +186,7 @@ watch(user, async () => {
} else {
selectedStakingProvider.value = ''
selectedWalletAddress.value = null
formattedAmountToStake.value = ''
formattedAmountToStakeOrWithdraw.value = ''
addressBalance.value = null
// currentUserStake.value = 0
}
Expand Down Expand Up @@ -248,12 +248,12 @@ const handleDeposit = async () => {
// const activeAddress = await detectActiveWalletAddress(selectedStakingProvider.value)
// if (activeAddress !== selectedWalletAddress.value) {
// formattedAmountToStake.value = ''
// formattedAmountToStakeOrWithdraw.value = ''
// return alert(`The account you selected is not the same as the one that is active in your ${selectedStakingProvider.value} wallet. Please open your browser extension and select the account that you want to log in with.`)
// }
const result = await deposit({
amount: formattedAmountToStake.value,
amount: formattedAmountToStakeOrWithdraw.value,
walletProvider: selectedStakingProvider.value,
type: stakeType.value
})
Expand All @@ -263,7 +263,7 @@ const handleDeposit = async () => {
setTimeout(() =>{
stakeButtonText.value = 'Stake'
formattedAmountToStake.value = ''
formattedAmountToStakeOrWithdraw.value = ''
}, 1000)
if (result) {
Expand All @@ -286,24 +286,33 @@ const handleWithdraw = async () => {
// const activeAddress = await detectActiveWalletAddress(selectedStakingProvider.value)
// if (activeAddress !== selectedWalletAddress.value) {
// formattedAmountToStake.value = ''
// formattedAmountToStakeOrWithdraw.value = ''
// return alert(`The account you selected is not the same as the one that is active in your ${selectedStakingProvider.value} wallet. Please open your browser extension and select the account that you want to log in with.`)
// }
const { result, bufferedBalance } = await withdraw({
amount: formattedAmountToStake.value,
const withdrawableBalance = await getWithdrawableBalance({
walletProvider: selectedStakingProvider.value,
type: stakeType.value
})
if (withdrawableBalance < formattedAmountToStakeOrWithdraw.value) {
stakeButtonText.value = 'Withdraw'
formattedAmountToStakeOrWithdraw.value = ''
return alert(`You can currently withdraw up to ${withdrawableBalance} ETH. Please try again with a smaller amount.`)
}
const result = await withdraw({
amount: formattedAmountToStakeOrWithdraw.value,
walletProvider: selectedStakingProvider.value,
type: stakeType.value
})
console.log('result :>> ', result)
console.log('bufferedBalance :>> ', bufferedBalance)
if (!result) stakeButtonText.value = 'Failed!'
stakeButtonText.value = 'Withdrawn!'
setTimeout(() =>{
stakeButtonText.value = 'Withdraw'
formattedAmountToStake.value = ''
formattedAmountToStakeOrWithdraw.value = ''
}, 1000)
if (result) {
Expand All @@ -322,7 +331,7 @@ const handleWithdraw = async () => {
function setStakeOrWithdraw(option: 'stake' | 'withdraw') {
stakeOrWithdraw.value = option
formattedAmountToStake.value = ''
formattedAmountToStakeOrWithdraw.value = ''
stakeButtonText.value = option === 'stake' ? 'Stake' : 'Withdraw'
}
</script>
Expand Down Expand Up @@ -438,7 +447,7 @@ function setStakeOrWithdraw(option: 'stake' | 'withdraw') {
<div class="flex items-center gap-[8px]">
<input
id="amount_input"
v-model="formattedAmountToStake"
v-model="formattedAmountToStakeOrWithdraw"
type="text"
pattern="^\d{1,3}(,\d{3})*(\.\d+)?$"
placeholder="0.00"
Expand Down Expand Up @@ -507,7 +516,7 @@ function setStakeOrWithdraw(option: 'stake' | 'withdraw') {
<button
ref="confettiButton"
class="eigen-toggle-container mb-[12px]"
:disabled="!(termsOfServiceCheckbox && selectedWalletAddress && formattedAmountToStake && !errorMessage && !eigenDisabled)"
:disabled="!(termsOfServiceCheckbox && selectedWalletAddress && formattedAmountToStakeOrWithdraw && !errorMessage && !eigenDisabled)"
@click="toggleShineEffect"
>
<div class="tooltip_container">
Expand All @@ -528,7 +537,7 @@ function setStakeOrWithdraw(option: 'stake' | 'withdraw') {
class="toggle_button"
:style="{ 'background-color': toggleBackgroundColor }"
:class="{ 'toggle-on': eigenIsToggled }"
:disabled="!(termsOfServiceCheckbox && selectedWalletAddress && formattedAmountToStake && !errorMessage)"
:disabled="!(termsOfServiceCheckbox && selectedWalletAddress && formattedAmountToStakeOrWithdraw && !errorMessage)"
>
<div class="toggle_circle" />
</div>
Expand All @@ -538,7 +547,7 @@ function setStakeOrWithdraw(option: 'stake' | 'withdraw') {
<button
class="submit-button h-[37px] w-full "
:class="success ? 'bg-approve' : failure ? 'bg-decline' : 'bg-primary'"
:disabled="!(termsOfServiceCheckbox && selectedWalletAddress && formattedAmountToStake && !errorMessage) || (stakeButtonText !== 'Stake' && stakeButtonText !== 'Withdraw')"
:disabled="!(termsOfServiceCheckbox && selectedWalletAddress && formattedAmountToStakeOrWithdraw && !errorMessage) || (stakeButtonText !== 'Stake' && stakeButtonText !== 'Withdraw')"
@click="stakeOrWithdraw === 'stake' ? handleDeposit() : handleWithdraw()"
>
<div
Expand Down
1 change: 1 addition & 0 deletions common/types/src/interfaces/ContractEventsByAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export interface ContractEventsByAddress {
TipsDeposited?: number;
WithdrawalInitiated?: number;
WithdrawalRequested?: number;
WithdrawalFulfilled?: number;
}

0 comments on commit 3a7899b

Please sign in to comment.