Skip to content

Commit

Permalink
feat: add auto slippage (#2461)
Browse files Browse the repository at this point in the history
* feat: add auto slippage

* fix: ui

* feat: dex fee display

* fix: slippage change

* fix: slippage change after swiching to auto

* fix: slippage input font size
  • Loading branch information
dmy147 authored Aug 9, 2024
1 parent 27acb39 commit 1e2b42d
Show file tree
Hide file tree
Showing 15 changed files with 225 additions and 53 deletions.
5 changes: 3 additions & 2 deletions _raw/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -903,10 +903,11 @@
"No-available-quote": "No available quote",
"price-impact": "Price Impact",
"loss-tips": "You're losing {{usd}}. Try a smaller amount in a small market.",
"Auto": "Auto",
"rabbyFee": {
"title": "Rabby fee",
"swapDesc": "Rabby Wallet will always find the best possible rate from top aggregators and check the reliability of their offer for you. A 0.25% fee (0% for wrap) is automatically factored into the quote.",
"bridgeDesc": "Rabby Wallet will always find the best possible rate from top aggregators and check the reliability of their offer for you. A 0.25% fee is automatically factored into the quote.",
"swapDesc": "Rabby Wallet will always find the best possible rate from top aggregators and verify the reliability of their offers. Rabby charges a 0.25% fee (0% for wrapping), which is automatically included in the quote.",
"bridgeDesc": "Rabby Wallet will always find the best possible rate from top aggregators and verify the reliability of their offers. Rabby charges a 0.25% fee, which is automatically included in the quote.",
"wallet": "Wallet",
"rate": "Fee rate",
"button": "Got it"
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@
"@rabby-wallet/eth-watch-keyring": "1.0.0",
"@rabby-wallet/gnosis-sdk": "1.3.8",
"@rabby-wallet/page-provider": "0.4.0",
"@rabby-wallet/rabby-api": "0.7.24",
"@rabby-wallet/rabby-api": "0.7.25",
"@rabby-wallet/rabby-security-engine": "2.0.5",
"@rabby-wallet/rabby-swap": "0.0.38",
"@rabby-wallet/rabby-swap": "0.0.39",
"@rabby-wallet/widgets": "1.0.9",
"@rematch/core": "2.2.0",
"@rematch/select": "3.1.2",
Expand Down
3 changes: 3 additions & 0 deletions src/background/controller/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,9 @@ export class WalletController extends BaseController {
setSwapSortIncludeGasFee = swapService.setSwapSortIncludeGasFee;
getSwapPreferMEVGuarded = swapService.getSwapPreferMEVGuarded;
setSwapPreferMEVGuarded = swapService.setSwapPreferMEVGuarded;
setAutoSlippage = swapService.setAutoSlippage;
setIsCustomSlippage = swapService.setIsCustomSlippage;
setSlippage = swapService.setSlippage;

setRedirect2Points = RabbyPointsService.setRedirect2Points;
setRabbyPointsSignature = RabbyPointsService.setSignature;
Expand Down
19 changes: 19 additions & 0 deletions src/background/service/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export type SwapServiceStore = {
selectedChain: CHAINS_ENUM | null;
selectedFromToken?: TokenItem;
selectedToToken?: TokenItem;
autoSlippage: boolean;
isCustomSlippage?: boolean;
slippage: string;

/**
* @deprecated
Expand Down Expand Up @@ -54,6 +57,8 @@ class SwapService {
tradeList: {} as SwapServiceStore['tradeList'],
sortIncludeGasFee: false,
preferMEVGuarded: false,
autoSlippage: true,
slippage: '0.1',
};

init = async () => {
Expand All @@ -68,6 +73,8 @@ class SwapService {
tradeList: {} as SwapServiceStore['tradeList'],
preferMEVGuarded: false,
sortIncludeGasFee: true,
autoSlippage: true,
slippage: '0.1',
},
});
if (storage) {
Expand Down Expand Up @@ -239,6 +246,18 @@ class SwapService {
setSwapPreferMEVGuarded = (bool: boolean) => {
this.store.preferMEVGuarded = bool;
};

setAutoSlippage = (auto: boolean) => {
this.store.autoSlippage = auto;
};

setIsCustomSlippage = (isCustomSlippage: boolean) => {
this.store.isCustomSlippage = isCustomSlippage;
};

setSlippage = (slippage: string) => {
this.store.slippage = slippage;
};
}

export default new SwapService();
4 changes: 3 additions & 1 deletion src/ui/component/TokenWithChain/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const TokenWithChain = ({
noRound = false,
hideChainIcon = false,
isShowChainTooltip = false,
className,
}: {
token: TokenItem;
width?: string;
Expand All @@ -24,14 +25,15 @@ const TokenWithChain = ({
noRound?: boolean;
hideChainIcon?: boolean;
isShowChainTooltip?: boolean;
className?: string;
}) => {
const chainServerId = token.chain;
const chain = findChain({
serverId: chainServerId,
});
return (
<div
className={clsx('token-with-chain', noRound && 'no-round')}
className={clsx('token-with-chain', noRound && 'no-round', className)}
style={{ width, height }}
>
<img
Expand Down
17 changes: 17 additions & 0 deletions src/ui/models/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const swap = createModel<RootModel>()({
name: 'swap',

state: {
slippage: '0.1',
autoSlippage: true,
supportedDEXList: Object.keys(DEX),
selectedDex: null,
selectedChain: null,
Expand Down Expand Up @@ -193,5 +195,20 @@ export const swap = createModel<RootModel>()({
});
}
},

async setAutoSlippage(autoSlippage: boolean, store) {
await store.app.wallet.setAutoSlippage(autoSlippage);
this.setField({ autoSlippage });
},

async setIsCustomSlippage(isCustomSlippage: boolean, store) {
await store.app.wallet.setIsCustomSlippage(isCustomSlippage);
this.setField({ isCustomSlippage });
},

async setSlippage(slippage: string, store) {
await store.app.wallet.setSlippage(slippage);
this.setField({ slippage });
},
}),
});
14 changes: 12 additions & 2 deletions src/ui/views/Bridge/Component/BridgeTokenPair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,12 @@ export const BridgeTokenPair = (props: {
) : (
<div className="pair">
<div className="token">
<TokenWithChain width="24px" height="24px" token={value?.from} />
<TokenWithChain
width="24px"
height="24px"
token={value?.from}
className="flex items-center"
/>
<span
className="token-symbol"
title={getTokenSymbol(value?.from)}
Expand All @@ -234,7 +239,12 @@ export const BridgeTokenPair = (props: {
<span className="text-r-neutral-foot"></span>

<div className="token">
<TokenWithChain width="24px" height="24px" token={value?.to} />
<TokenWithChain
width="24px"
height="24px"
token={value?.to}
className="flex items-center"
/>
<span className="token-symbol" title={getTokenSymbol(value?.to)}>
{getTokenSymbol(value?.to)}
</span>
Expand Down
14 changes: 8 additions & 6 deletions src/ui/views/Swap/Component/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { PageHeader } from '@/ui/component';
import React, { useCallback, useState } from 'react';
import {
usePollSwapPendingNumber,
useRabbyFeeVisible,
useSetRabbyFeeVisible,
useRabbyFee,
useSetRabbyFee,
} from '../hooks';
import { SwapTxHistory } from './History';
import { useTranslation } from 'react-i18next';
Expand All @@ -19,8 +19,8 @@ export const Header = () => {

const loadingNumber = usePollSwapPendingNumber(5000);

const rabbyFeeVisible = useRabbyFeeVisible();
const setRabbyFeeVisible = useSetRabbyFeeVisible();
const { visible, feeDexDesc, dexName } = useRabbyFee();
const setRabbyFeeVisible = useSetRabbyFee();

const openHistory = useCallback(() => {
setHistoryVisible(true);
Expand Down Expand Up @@ -59,8 +59,10 @@ export const Header = () => {
}, [])}
/>
<RabbyFeePopup
visible={rabbyFeeVisible}
onClose={() => setRabbyFeeVisible(false)}
visible={visible}
dexName={dexName}
feeDexDesc={feeDexDesc}
onClose={() => setRabbyFeeVisible({ visible: false })}
/>
</>
);
Expand Down
11 changes: 8 additions & 3 deletions src/ui/views/Swap/Component/QuoteItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import {
QuoteProvider,
isSwapWrapToken,
} from '../hooks/quote';
import { useSetQuoteVisible, useSetRabbyFeeVisible, verifySdk } from '../hooks';
import { useSetQuoteVisible, useSetRabbyFee, verifySdk } from '../hooks';
import { getTokenSymbol } from '@/ui/utils/token';
import { TooltipWithMagnetArrow } from '@/ui/component/Tooltip/TooltipWithMagnetArrow';
import { useTranslation } from 'react-i18next';
import { TokenWithChain } from '@/ui/component';
import { Tooltip } from 'antd';
import { DEX_ENUM } from '@rabby-wallet/rabby-swap';

const GAS_USE_AMOUNT_LIMIT = 2_000_000;

Expand Down Expand Up @@ -158,7 +159,7 @@ export const DexQuoteItem = (

const openSwapQuote = useSetQuoteVisible();

const setRabbyFeeVisible = useSetRabbyFeeVisible();
const setRabbyFeeVisible = useSetRabbyFee();

const isSdkDataPass = !!preExecResult?.isSdkPass;

Expand Down Expand Up @@ -502,7 +503,11 @@ export const DexQuoteItem = (
? undefined
: (e) => {
e.stopPropagation();
setRabbyFeeVisible(true);
setRabbyFeeVisible({
visible: true,
dexName: dexId,
feeDexDesc: quote?.dexFeeDesc || undefined,
});
}
}
>
Expand Down
62 changes: 54 additions & 8 deletions src/ui/views/Swap/Component/RabbyFeePopup.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useMemo } from 'react';
import { Popup } from '@/ui/component';
import { ReactComponent as RCIconRabbyWhite } from '@/ui/assets/swap/rabby.svg';
import { useTranslation } from 'react-i18next';
Expand All @@ -7,6 +7,7 @@ import ImgPhantom from '@/ui/assets/swap/phantom.png';
import ImgRabbyWallet from '@/ui/assets/swap/rabby-wallet.png';
import clsx from 'clsx';
import { Button } from 'antd';
import { DEX } from '@/constant';

const swapFee = [
{
Expand Down Expand Up @@ -48,23 +49,43 @@ export const RabbyFeePopup = ({
visible,
onClose,
type = 'swap',
feeDexDesc,
dexName,
}: {
visible: boolean;
onClose: () => void;
type?: keyof typeof fee;
dexName?: string;
feeDexDesc?: string;
}) => {
const { t } = useTranslation();

const hasSwapDexFee = useMemo(() => {
return type === 'swap' && dexName && feeDexDesc && DEX?.[dexName]?.logo;
}, [type, dexName, feeDexDesc]);

const height = useMemo(() => {
if (type === 'swap') {
if (dexName && feeDexDesc && DEX?.[dexName]?.logo) {
return 500;
}
return 493;
}
return 428;
}, [type, dexName, feeDexDesc]);
return (
<Popup
visible={visible}
title={null}
height={type === 'swap' ? 478 : 428}
height={height}
isSupportDarkMode
isNew
onCancel={onClose}
bodyStyle={{
paddingTop: 24,
paddingTop: hasSwapDexFee ? 20 : 32,
paddingBottom: 20,
display: 'flex',
flexDirection: 'column',
}}
>
<div className="w-[52px] h-[52px] flex items-center justify-center rounded-full bg-r-blue-default mx-auto">
Expand All @@ -84,8 +105,9 @@ export const RabbyFeePopup = ({
<div
className={clsx(
'flex justify-between items-center',
'px-16 mt-20 mb-8',
'text-12 text-r-neutral-foot'
'px-16 mb-6',
'text-12 text-r-neutral-foot',
type === 'bridge' ? 'mt-20' : hasSwapDexFee ? 'mt-20' : 'mt-[26px]'
)}
>
<span>{t('page.swap.rabbyFee.wallet')}</span>
Expand All @@ -97,13 +119,13 @@ export const RabbyFeePopup = ({
key={item.name}
className={clsx(
'flex justify-between items-center',
'px-16 py-12',
'px-16 h-[44px]',
'border-b-[1px] border-solid border-rabby-neutral-line',
idx === list.length - 1 ? 'border-b-0' : ''
)}
>
<div className="flex items-center">
<img src={item.logo} className="w-[20px] h-[20px] mr-8" />
<img src={item.logo} className="w-[18px] h-[18px] mr-8" />
<span className="text-13 leading-normal font-medium text-rabby-neutral-title1">
{item.name}
</span>
Expand All @@ -114,15 +136,39 @@ export const RabbyFeePopup = ({
</div>
))}
</div>

<SwapAggregatorFee dexName={dexName} feeDexDesc={feeDexDesc} />

<Button
type="primary"
block
size="large"
className="mt-[20px] h-[48px] text-16 font-medium text-r-neutral-title2"
className="mt-[auto] h-[48px] text-16 font-medium text-r-neutral-title2"
onClick={onClose}
>
{t('page.swap.rabbyFee.button')}
</Button>
</Popup>
);
};

function SwapAggregatorFee({
dexName,
feeDexDesc,
}: {
dexName?: string;
feeDexDesc?: string;
}) {
if (dexName && feeDexDesc && DEX?.[dexName]?.logo) {
return (
<div className="flex justify-center items-center mt-16 gap-[3px] text-12 text-r-neutral-foot">
<img
src={DEX[dexName].logo}
className="w-[14px] h-[14px] rounded-full"
/>
<span>{feeDexDesc}</span>
</div>
);
}
return null;
}
Loading

0 comments on commit 1e2b42d

Please sign in to comment.