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

Add backend provided slippage #5649

Merged
merged 3 commits into from
Apr 23, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"@notifee/react-native": "5.6.0",
"@rainbow-me/provider": "0.0.11",
"@rainbow-me/react-native-animated-number": "0.0.2",
"@rainbow-me/swaps": "0.16.0",
"@rainbow-me/swaps": "0.17.0",
"@react-native-async-storage/async-storage": "1.18.2",
"@react-native-camera-roll/camera-roll": "5.7.1",
"@react-native-clipboard/clipboard": "1.13.2",
Expand Down
88 changes: 80 additions & 8 deletions src/__swaps__/screens/Swap/hooks/useSwapInputsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useDebouncedCallback } from 'use-debounce';
import { ETH_COLOR, ETH_COLOR_DARK, SCRUBBER_WIDTH, SLIDER_WIDTH, snappySpringConfig } from '@/__swaps__/screens/Swap/constants';
import { SWAP_FEE } from '@/__swaps__/screens/Swap/dummyValues';
import { inputKeys, inputMethods } from '@/__swaps__/types/swap';
import { logger } from '@/logger';
import { RainbowError, logger } from '@/logger';
import {
addCommasToNumber,
clamp,
Expand All @@ -32,10 +32,14 @@ import {
Quote,
QuoteError,
QuoteParams,
Slippage,
SlippageError,
SlippageParams,
Source,
SwapType,
getCrosschainQuote,
getQuote,
getSlippage,
} from '@rainbow-me/swaps';
import { useRemoteConfig } from '@/model/remoteConfig';
import { useAccountSettings } from '@/hooks';
Expand Down Expand Up @@ -410,8 +414,10 @@ export function useSwapInputsController({

const quoteParams: QuoteParams = {
source: source.value === 'auto' ? undefined : source.value,
chainId: assetToSell.value.chainId,
swapType: isCrosschainSwap ? SwapType.crossChain : SwapType.normal,
fromAddress: currentAddress,
chainId: assetToSell.value.chainId,
toChainId: isCrosschainSwap ? assetToBuy.value.chainId : assetToSell.value.chainId,
sellTokenAddress: assetToSell.value.isNativeAsset ? ETH_ADDRESS : assetToSell.value.address,
buyTokenAddress: assetToBuy.value.isNativeAsset ? ETH_ADDRESS : assetToBuy.value.address,
// TODO: Sometimes decimals are present here which messes with the quote
Expand All @@ -420,8 +426,6 @@ export function useSwapInputsController({
buyAmount: isInputAmount ? undefined : convertAmountToRawAmount(amount, assetToBuy.value.decimals),
slippage: Number(slippage.value),
refuel: false,
swapType: isCrosschainSwap ? SwapType.crossChain : SwapType.normal,
toChainId: isCrosschainSwap ? assetToBuy.value.chainId : assetToSell.value.chainId,
};

logger.debug(`[useSwapInputsController] quoteParams`, { quoteParams });
Expand Down Expand Up @@ -554,11 +558,79 @@ export function useSwapInputsController({
};

const onExecuteSwap = async () => {
if (!assetToSell.value || !assetToBuy.value || !quote.value) return;
const quoteData = quote.value as Quote | CrosschainQuote;
/**
* NOTE: Before executing a swap, we want to check several things:
* 1. assetToSell && assetToBuy addresses match the quote values
* 2. outputNative matches quote value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check makes sense but not sure if practical, like isnt there a case where the quote could update

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outputNative is updated when the quote updates

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not a necessary check, but is more of a sanity check that the user is displayed and can confirm what will actually get received.

* 3. buyAmount > 0 (should we check this? because we can have missing price data)
* 4. both chainId and toChain match the quote data
*/
const failedConditions: string[] = [];
// Ensure assetToSell and assetToBuy are not null or undefined before proceeding
if (!assetToBuy.value || !assetToSell.value) {
logger.debug('[onExecuteSwap]: Missing assetToSell or assetToBuy');
return;
}
if ((quote.value as QuoteError)?.error) failedConditions.push('quote error');
if (quoteData.buyAmountMinusFees.toString() === '0') failedConditions.push('buyAmountMinusFees is 0');
if (quoteData.buyTokenAddress !== assetToBuy.value.address) failedConditions.push('buyTokenAddress mismatch');
walmat marked this conversation as resolved.
Show resolved Hide resolved
if (quoteData.sellTokenAddress !== assetToSell.value.address) failedConditions.push('sellTokenAddress mismatch');
if (quoteData.swapType === SwapType.normal && quoteData.chainId !== assetToSell.value.chainId)
failedConditions.push('chainId mismatch for swapType normal');
if (quoteData.swapType === SwapType.crossChain && quoteData.chainId === assetToSell.value.chainId)
failedConditions.push('chainId mismatch for swapType crossChain');

if (failedConditions.length > 0) {
logger.debug(`[onExecuteSwap]: Not executing swap due to failed conditions: ${failedConditions.join(', ')}`);
return;
}

const isCrosschainSwap = assetToSell.value.chainId !== assetToBuy.value.chainId;
const slippageParams: SlippageParams = {
chainId: assetToSell.value.chainId,
toChainId: isCrosschainSwap ? assetToBuy.value.chainId : assetToSell.value.chainId,
sellTokenAddress: assetToSell.value.isNativeAsset ? ETH_ADDRESS : assetToSell.value.address,
buyTokenAddress: assetToBuy.value.isNativeAsset ? ETH_ADDRESS : assetToBuy.value.address,
sellAmount: quoteData.sellAmount,
buyAmount: quoteData.buyAmountMinusFees,
};

let slippageToUse = slippage.value;

const defaultSlippage = getDefaultSlippage(assetToSell.value?.chainId || ChainId.mainnet, config);
// NOTE: if slippage === default slippage, update the slippage because we can assume that the user wanted the default slippage if they haven't adjusted it.
if (slippage.value === defaultSlippage) {
try {
const backendSlippage = await getSlippage(slippageParams);
if (!backendSlippage) {
throw new RainbowError('[useSwapInputsController] Error fetching slippage', {
cause: 'Slippage not found',
});
}

if ((backendSlippage as SlippageError)?.error) {
throw new RainbowError('[useSwapInputsController] Error fetching slippage', {
cause: backendSlippage as SlippageError,
});
}

const percentage = (backendSlippage as Slippage).slippagePercent;
slippageToUse = `${percentage}`;
} catch (e) {
if (e instanceof RainbowError) {
logger.error(e);
} else {
logger.error(
new RainbowError('[useSwapInputsController] Error fetching slippage', {
cause: JSON.stringify(e),
})
);
}
}
}

// console.log('executing swap');
// const isCrosschainSwap =
// assetToSell.value.chainId !== assetToBuy.value.chainId;
logger.debug(`[onExecuteSwap] slippageToUse`, { slippageToUse });
// const flashbotsEnabled =
// assetToSell.value.chainId === ChainId.mainnet ? flashbots.value : false;
// const rapType = getSwapRapTypeByExchangeType(isCrosschainSwap);
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3320,10 +3320,10 @@
dependencies:
react-merge-refs "^1.0.0"

"@rainbow-me/swaps@0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@rainbow-me/swaps/-/swaps-0.16.0.tgz#3c90bcf162e11434348d839eeec75549bb7ba333"
integrity sha512-OfVBXfN55J/YKvj8tCnjP+d6t0N5jLtbTw51dpMMQKvrLo1AHrjrqAldf8v5lSsu0kQhPZWd5fJb6bLxy+Iq/A==
"@rainbow-me/swaps@0.17.0":
version "0.17.0"
resolved "https://registry.yarnpkg.com/@rainbow-me/swaps/-/swaps-0.17.0.tgz#4db1c3807b1dd040c863dbd34de5f73c0489891b"
integrity sha512-iXGSfbs7fopZyFI5nUe4e6LO6z1ZnSY3SPH8tJXYxRpHOUgl9b27r46rLvDTKBFgrng9MQMeXzJkm0EMgisvzA==
dependencies:
"@ethereumjs/util" "9.0.0"
"@ethersproject/abi" "5.7.0"
Expand Down