From 41eae0760b73f3ac7b5072907bf852813e7ba3e8 Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Tue, 7 Nov 2023 19:40:37 +0100 Subject: [PATCH] fix(prepare-transactions): add `throwOnSpendTokenAmountExceedsBalance` option (#4442) ### Description I realized a bit too late that the changes in https://github.com/valora-inc/wallet/pull/4432 broke the swap flow where we want to prepare transactions when the spend amount is greater than the balance. This is because we want users to be able to try any amount to see the quote (and associated fee). ### Test plan - Updated tests ### Related issues - N/A ### Backwards compatibility Yes --- src/swap/useSwapQuote.ts | 2 ++ src/viem/prepareTransactions.test.ts | 25 +++++++++++++++++++++++++ src/viem/prepareTransactions.ts | 10 ++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/swap/useSwapQuote.ts b/src/swap/useSwapQuote.ts index 7bf1be326dc..5a0c81846d6 100644 --- a/src/swap/useSwapQuote.ts +++ b/src/swap/useSwapQuote.ts @@ -103,6 +103,8 @@ export async function prepareSwapTransactions( spendTokenAmount: new BigNumber(amountToApprove.toString()), decreasedAmountGasFeeMultiplier: DECREASED_SWAP_AMOUNT_GAS_FEE_MULTIPLIER, baseTransactions, + // We still want to prepare the transactions even if the user doesn't have enough balance + throwOnSpendTokenAmountExceedsBalance: false, }) } diff --git a/src/viem/prepareTransactions.test.ts b/src/viem/prepareTransactions.test.ts index 2ef8204cdae..bba19cd3778 100644 --- a/src/viem/prepareTransactions.test.ts +++ b/src/viem/prepareTransactions.test.ts @@ -116,6 +116,31 @@ describe('prepareTransactions module', () => { }) ).rejects.toThrowError(/Cannot prepareTransactions for amount greater than balance./) }) + it('does not throw if trying to sendAmount > sendToken balance when throwOnSpendTokenAmountExceedsBalance is false', async () => { + mocked(estimateFeesPerGas).mockResolvedValue({ + maxFeePerGas: BigInt(100), + maxPriorityFeePerGas: BigInt(2), + }) + mockPublicClient.estimateGas.mockResolvedValue(BigInt(1_000)) + + await expect( + prepareTransactions({ + feeCurrencies: mockFeeCurrencies, + spendToken: mockSpendToken, + spendTokenAmount: new BigNumber(51_000), + decreasedAmountGasFeeMultiplier: 1, + baseTransactions: [ + { + from: '0xfrom' as Address, + to: '0xto' as Address, + data: '0xdata', + type: 'cip42', + }, + ], + throwOnSpendTokenAmountExceedsBalance: false, + }) + ).resolves.toEqual(expect.anything()) + }) it("returns a 'not-enough-balance-for-gas' result when the balances for feeCurrencies are too low to cover the fee", async () => { mocked(estimateFeesPerGas).mockResolvedValue({ maxFeePerGas: BigInt(100), diff --git a/src/viem/prepareTransactions.ts b/src/viem/prepareTransactions.ts index c9763be8032..c9d6c81374b 100644 --- a/src/viem/prepareTransactions.ts +++ b/src/viem/prepareTransactions.ts @@ -172,13 +172,14 @@ export async function tryEstimateTransactions( * Adds "maxFeePerGas" and "maxPriorityFeePerGas" fields to base transactions. Adds "gas" field to base * transactions if they do not already include them. * - * NOTE: throws if spendTokenAmount exceeds the user's balance of that token. + * NOTE: throws if spendTokenAmount exceeds the user's balance of that token, unless throwOnSpendTokenAmountExceedsBalance is false * * @param feeCurrencies * @param spendToken * @param spendTokenAmount * @param decreasedAmountGasFeeMultiplier * @param baseTransactions + * @param throwOnSpendTokenAmountExceedsBalance */ export async function prepareTransactions({ feeCurrencies, @@ -186,14 +187,19 @@ export async function prepareTransactions({ spendTokenAmount, decreasedAmountGasFeeMultiplier, baseTransactions, + throwOnSpendTokenAmountExceedsBalance = true, }: { feeCurrencies: TokenBalance[] spendToken: TokenBalanceWithAddress spendTokenAmount: BigNumber decreasedAmountGasFeeMultiplier: number baseTransactions: (TransactionRequestCIP42 & { gas?: bigint })[] + throwOnSpendTokenAmountExceedsBalance?: boolean }): Promise { - if (spendTokenAmount.isGreaterThan(spendToken.balance.shiftedBy(spendToken.decimals))) { + if ( + throwOnSpendTokenAmountExceedsBalance && + spendTokenAmount.isGreaterThan(spendToken.balance.shiftedBy(spendToken.decimals)) + ) { throw new Error( `Cannot prepareTransactions for amount greater than balance. Amount: ${spendTokenAmount}, Balance: ${spendToken.balance}, Decimals: ${spendToken.decimals}` )