Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/gas estimation #235

Merged
merged 6 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions src/features/swap/hooks/useStaking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import logger from 'src/services/logger';
import { Mode } from 'src/types';
import { transactionEvent } from 'src/utils/ga';
import { Celo, CeloUSD, StCelo, Token } from 'src/utils/tokens';
import { useContractWrite, usePublicClient } from 'wagmi';
import { Address, useContractWrite, usePublicClient } from 'wagmi';
import { showErrorToast, showHashToast, showStakingToast } from '../utils/toast';

export function useStaking() {
Expand All @@ -28,6 +28,19 @@ export function useStaking() {

const client = usePublicClient();

const _estimateDepositGas = useCallback(
(address: Address, value: bigint) => {
return publicClient.estimateContractGas({
abi: managerContract.abi,
address: managerContract.address!,
account: address!,
functionName: 'deposit',
value,
});
},
[publicClient, managerContract]
);

const stake = useCallback(
async (callbacks?: TxCallbacks) => {
if (!address || !celoAmount || celoAmount.isEqualTo(0) || !stCeloBalance || !loadBalances) {
Expand All @@ -41,7 +54,9 @@ export function useStaking() {
value: celoAmount.displayAsBase(),
});
try {
const stakeHash = await _stake({ value: celoAmount?.toBigInt() });
const value = celoAmount?.toBigInt();
const gas = await _estimateDepositGas(address!, value);
const stakeHash = await _stake({ value, gas });
console.info('stakeHash', stakeHash);
transactionEvent({
action: Mode.stake,
Expand All @@ -67,7 +82,8 @@ export function useStaking() {
} catch (e: unknown) {
console.error(e);
showErrorToast(
(e as Error).message.includes('rejected')
(e as Error).message.includes('rejected') ||
(e as any).details?.toLowerCase().includes('cancelled')
? 'User rejected the request'
: (e as Error).message
);
Expand All @@ -81,7 +97,7 @@ export function useStaking() {
logger.error('afterDeposit error', e);
}
},
[_stake, address, api, celoAmount, client, loadBalances, stCeloBalance]
[_estimateDepositGas, _stake, address, api, celoAmount, client, loadBalances, stCeloBalance]
);

const estimateStakingGas = useCallback(async () => {
Expand All @@ -95,19 +111,19 @@ export function useStaking() {
return null;
}

const gasFee = new Token(
await publicClient.estimateContractGas({
abi: managerContract.abi,
address: managerContract.address!,
account: address!,
functionName: 'deposit',
value: celoAmount.toBigInt(),
})
);
const gasFee = new Token(await _estimateDepositGas(address!, celoAmount.toBigInt()));
const gasFeeInCelo = new Celo(gasFee.multipliedBy(suggestedGasPrice));
const gasFeeInUSD = new CeloUSD(gasFeeInCelo.multipliedBy(celoToUSDRate));
return gasFeeInUSD;
}, [celoAmount, celoBalance, managerContract, publicClient, suggestedGasPrice, celoToUSDRate]);
}, [
celoAmount,
celoBalance,
address,
managerContract.address,
_estimateDepositGas,
suggestedGasPrice,
celoToUSDRate,
]);

const receivedStCelo = useMemo(
() => (celoAmount ? new StCelo(celoAmount.multipliedBy(stakingRate).dp(0)) : null),
Expand Down
16 changes: 13 additions & 3 deletions src/features/swap/hooks/useSwap.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import BigNumber from 'bignumber.js';
import { useCallback, useEffect, useState } from 'react';
import { MAX_AMOUNT_THRESHOLD } from 'src/config/consts';
import { useAccountContext } from 'src/contexts/account/AccountContext';
import { TxCallbacks } from 'src/contexts/blockchain/useBlockchain';
import { useProtocolContext } from 'src/contexts/protocol/ProtocolContext';
import { Mode } from 'src/types';
import { Celo, CeloUSD, StCelo, Token } from 'src/utils/tokens';
import { useStaking } from './useStaking';
import { useUnstaking } from './useUnstaking';
import { MAX_AMOUNT_THRESHOLD } from 'src/config/consts';

export function useSwap(mode: Mode) {
const { stakingRate, unstakingRate } = useProtocolContext();
Expand Down Expand Up @@ -47,8 +47,18 @@ export function useSwap(mode: Mode) {
}

const setMaxAmount = useCallback(() => {
const maxAmount = new Token(BigNumber.max(0, balance.minus(MAX_AMOUNT_THRESHOLD.toString())));
setAmount(maxAmount);
let maxAmount: Token;
if (Mode.stake) {
// NOTE: we're doing this weird `minus` operation to make sure the
// account owner has enough currency leftover to pay for gasfees.

// NOTE2: this is a good use-case for alternative gas currencies
// (cUSD, cEUR, etc...)
maxAmount = new Token(BigNumber.max(0, balance.minus(MAX_AMOUNT_THRESHOLD.toString())));
} else if (Mode.unstake) {
maxAmount = new Token(BigNumber.max(0, balance));
}
setAmount(maxAmount!);
}, [setAmount, balance]);

// Don't override gasFee when estimateGas function is not the latest one
Expand Down
44 changes: 30 additions & 14 deletions src/features/swap/hooks/useUnstaking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useAPI } from 'src/hooks/useAPI';
import logger from 'src/services/logger';
import { Mode } from 'src/types';
import { Celo, CeloUSD, StCelo, Token } from 'src/utils/tokens';
import { useContractWrite, usePublicClient } from 'wagmi';
import { Address, useContractWrite, usePublicClient } from 'wagmi';
import { transactionEvent } from '../../../utils/ga';
import { showErrorToast, showUnstakingToast } from '../utils/toast';

Expand All @@ -26,6 +26,19 @@ export function useUnstaking() {
args: [stCeloAmount?.toBigInt() || 0n] as const,
});

const _estimateWithdrawGas = useCallback(
(address: Address, value: bigint) => {
return publicClient.estimateContractGas({
abi: managerContract.abi,
address: managerContract.address!,
account: address,
functionName: 'withdraw',
args: [value || 0n] as const,
});
},
[publicClient, managerContract]
);

const unstake = useCallback(
async (callbacks?: TxCallbacks) => {
if (
Expand All @@ -43,23 +56,34 @@ export function useUnstaking() {
value: stCeloAmount.displayAsBase(),
});
try {
await _unstake();
const gas = await _estimateWithdrawGas(address, stCeloAmount?.toBigInt());
await _unstake({ gas });
await api.withdraw(address);
showUnstakingToast();
await Promise.all([loadBalances(), loadPendingWithdrawals?.()]);
setStCeloAmount(null);
} catch (e: unknown) {
logger.error(e);
showErrorToast(
(e as Error).message.includes('rejected')
(e as Error).message.includes('rejected') ||
(e as any).details?.toLowerCase().includes('cancelled')
? 'User rejected the request'
: (e as Error).message
);
} finally {
callbacks?.onSent?.();
}
},
[_unstake, address, api, loadBalances, loadPendingWithdrawals, managerContract, stCeloAmount]
[
_estimateWithdrawGas,
_unstake,
address,
api,
loadBalances,
loadPendingWithdrawals,
managerContract,
stCeloAmount,
]
);

const estimateUnstakingGas = useCallback(async () => {
Expand All @@ -72,23 +96,15 @@ export function useUnstaking() {
return null;
}

const gasFee = new Token(
await publicClient.estimateContractGas({
abi: managerContract.abi,
address: managerContract.address!,
account: address!,
functionName: 'withdraw',
args: [stCeloAmount?.toBigInt() || 0n] as const,
})
);
const gasFee = new Token(await _estimateWithdrawGas(address!, stCeloAmount?.toBigInt()));
const gasFeeInCelo = new Celo(gasFee.multipliedBy(suggestedGasPrice));
const gasFeeInUSD = new CeloUSD(gasFeeInCelo.multipliedBy(celoToUSDRate));
return gasFeeInUSD;
}, [
stCeloAmount,
stCeloBalance,
managerContract,
publicClient,
_estimateWithdrawGas,
address,
suggestedGasPrice,
celoToUSDRate,
Expand Down
Loading