-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #244 from lidofinance/develop
Develop to main
- Loading branch information
Showing
31 changed files
with
759 additions
and
463 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export { SwapDiscountBanner } from './swap-discount-banner'; | ||
export type { StakeSwapDiscountIntegrationKey } from './types'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { TOKENS } from '@lido-sdk/constants'; | ||
import { getOpenOceanRate } from 'utils/get-open-ocean-rate'; | ||
import { | ||
StakeSwapDiscountIntegrationKey, | ||
StakeSwapDiscountIntegrationMap, | ||
} from './types'; | ||
import { OpenOceanIcon, OneInchIcon, OverlayLink } from './styles'; | ||
import { parseEther } from '@ethersproject/units'; | ||
import { OPEN_OCEAN_REFERRAL_ADDRESS } from 'config/external-links'; | ||
import { MATOMO_CLICK_EVENTS } from 'config/matomoClickEvents'; | ||
import { getOneInchRate } from 'utils/get-one-inch-rate'; | ||
import { use1inchDeepLinkProps } from 'features/stake/hooks'; | ||
|
||
const DEFAULT_AMOUNT = parseEther('1'); | ||
|
||
const STAKE_SWAP_INTEGRATION_CONFIG: StakeSwapDiscountIntegrationMap = { | ||
'open-ocean': { | ||
title: 'OpenOcean', | ||
async getRate() { | ||
const { rate } = await getOpenOceanRate( | ||
DEFAULT_AMOUNT, | ||
'ETH', | ||
TOKENS.STETH, | ||
); | ||
return rate; | ||
}, | ||
BannerText({ discountPercent }) { | ||
return ( | ||
<> | ||
Get a <b>{discountPercent.toFixed(2)}% discount</b> by swapping to | ||
stETH on the OpenOcean platform | ||
</> | ||
); | ||
}, | ||
Icon: OpenOceanIcon, | ||
linkHref: `https://app.openocean.finance/classic?referrer=${OPEN_OCEAN_REFERRAL_ADDRESS}#/ETH/ETH/STETH`, | ||
matomoEvent: MATOMO_CLICK_EVENTS.openOceanDiscount, | ||
}, | ||
'one-inch': { | ||
title: '1inch', | ||
async getRate() { | ||
const { rate } = await getOneInchRate({ token: 'ETH' }); | ||
return rate; | ||
}, | ||
BannerText({ discountPercent }) { | ||
return ( | ||
<> | ||
Get a <b>{discountPercent.toFixed(2)}% discount</b> by swapping to | ||
stETH on the 1inch platform | ||
</> | ||
); | ||
}, | ||
Icon: OneInchIcon, | ||
linkHref: `https://app.1inch.io/#/1/simple/swap/ETH/stETH`, | ||
matomoEvent: MATOMO_CLICK_EVENTS.oneInchDiscount, | ||
CustomLink({ children, ...props }) { | ||
const customProps = use1inchDeepLinkProps(); | ||
return ( | ||
<OverlayLink {...props} {...customProps}> | ||
{children} | ||
</OverlayLink> | ||
); | ||
}, | ||
}, | ||
}; | ||
|
||
export const getSwapIntegration = (key: StakeSwapDiscountIntegrationKey) => | ||
STAKE_SWAP_INTEGRATION_CONFIG[key]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 22 additions & 69 deletions
91
features/stake/swap-discount-banner/swap-discount-banner.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,43 @@ | ||
import { Button } from '@lidofinance/lido-ui'; | ||
import { trackEvent } from '@lidofinance/analytics-matomo'; | ||
|
||
import { MATOMO_CLICK_EVENTS } from 'config'; | ||
import { OPEN_OCEAN_REFERRAL_ADDRESS } from 'config/external-links'; | ||
import { STRATEGY_LAZY } from 'utils/swrStrategies'; | ||
import { getOpenOceanRate } from 'utils/get-open-ocean-rate'; | ||
import { parseEther } from '@ethersproject/units'; | ||
import { TOKENS } from '@lido-sdk/constants'; | ||
import { useLidoSWR } from '@lido-sdk/react'; | ||
import { enableQaHelpers } from 'utils'; | ||
|
||
import { Wrap, TextWrap, OpenOceanIcon, OverlayLink } from './styles'; | ||
|
||
const SWAP_URL = `https://app.openocean.finance/classic?referrer=${OPEN_OCEAN_REFERRAL_ADDRESS}#/ETH/ETH/STETH`; | ||
const DISCOUNT_THRESHOLD = 1.004; | ||
const DEFAULT_AMOUNT = parseEther('1'); | ||
const MOCK_LS_KEY = 'mock-qa-helpers-discount-rate'; | ||
|
||
type FetchRateResult = { | ||
rate: number; | ||
shouldShowDiscount: boolean; | ||
discountPercent: number; | ||
}; | ||
|
||
const calculateDiscountState = (rate: number): FetchRateResult => ({ | ||
rate, | ||
shouldShowDiscount: rate > DISCOUNT_THRESHOLD, | ||
discountPercent: (1 - 1 / rate) * 100, | ||
}); | ||
|
||
// we show banner if STETH is considerably cheaper to get on dex than staking | ||
// ETH -> stETH rate > THRESHOLD | ||
const fetchRate = async (): Promise<FetchRateResult> => { | ||
const { rate } = await getOpenOceanRate(DEFAULT_AMOUNT, 'ETH', TOKENS.STETH); | ||
return calculateDiscountState(rate); | ||
}; | ||
|
||
const linkClickHandler = () => | ||
trackEvent(...MATOMO_CLICK_EVENTS.openOceanDiscount); | ||
|
||
if (enableQaHelpers && typeof window !== 'undefined') { | ||
(window as any).setMockDiscountRate = (rate?: number) => | ||
rate === undefined | ||
? localStorage.removeItem(MOCK_LS_KEY) | ||
: localStorage.setItem(MOCK_LS_KEY, rate.toString()); | ||
} | ||
|
||
const getData = (data: FetchRateResult | undefined) => { | ||
if (!enableQaHelpers || typeof window == 'undefined') return data; | ||
const mock = localStorage.getItem(MOCK_LS_KEY); | ||
if (mock) { | ||
return calculateDiscountState(parseFloat(mock)); | ||
} | ||
return data; | ||
}; | ||
import { useSwapDiscount } from './use-swap-discount'; | ||
import { Wrap, TextWrap, OverlayLink } from './styles'; | ||
|
||
export const SwapDiscountBanner = ({ children }: React.PropsWithChildren) => { | ||
const swr = useLidoSWR<FetchRateResult>( | ||
['swr:open-ocean-rate'], | ||
fetchRate, | ||
STRATEGY_LAZY, | ||
); | ||
|
||
const data = getData(swr.data); | ||
const { data, initialLoading } = useSwapDiscount(); | ||
|
||
if (swr.initialLoading) return null; | ||
if (initialLoading) return null; | ||
|
||
if (!data?.shouldShowDiscount) return <>{children}</>; | ||
if (!data || !data.shouldShowDiscount) return <>{children}</>; | ||
|
||
const { | ||
BannerText, | ||
Icon, | ||
discountPercent, | ||
matomoEvent, | ||
linkHref, | ||
CustomLink, | ||
} = data; | ||
const Link = CustomLink ?? OverlayLink; | ||
return ( | ||
<Wrap> | ||
<OpenOceanIcon /> | ||
<Icon /> | ||
<TextWrap> | ||
Get a <b>{data?.discountPercent.toFixed(2)}% discount</b> by swapping to | ||
stETH on the OpenOcean platform | ||
<BannerText discountPercent={discountPercent} /> | ||
</TextWrap> | ||
<OverlayLink | ||
<Link | ||
target="_blank" | ||
rel="noreferrer" | ||
href={SWAP_URL} | ||
onClick={linkClickHandler} | ||
href={linkHref} | ||
onClick={() => { | ||
trackEvent(...matomoEvent); | ||
}} | ||
> | ||
<Button fullwidth size="xs"> | ||
Get discount | ||
</Button> | ||
</OverlayLink> | ||
</Link> | ||
</Wrap> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { MatomoEventType } from '@lidofinance/analytics-matomo'; | ||
|
||
export type StakeSwapDiscountIntegrationKey = 'open-ocean' | 'one-inch'; | ||
|
||
export type StakeSwapDiscountIntegrationValue = { | ||
title: string; | ||
getRate: () => Promise<number>; | ||
linkHref: string; | ||
CustomLink?: React.FC<React.PropsWithoutRef<React.ComponentProps<'a'>>>; | ||
matomoEvent: MatomoEventType; | ||
BannerText: React.FC<{ discountPercent: number }>; | ||
Icon: React.FC; | ||
}; | ||
|
||
export type StakeSwapDiscountIntegrationMap = Record< | ||
StakeSwapDiscountIntegrationKey, | ||
StakeSwapDiscountIntegrationValue | ||
>; | ||
|
||
export type FetchRateResult = { | ||
rate: number; | ||
shouldShowDiscount: boolean; | ||
discountPercent: number; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { STRATEGY_LAZY } from 'utils/swrStrategies'; | ||
import { useLidoSWR } from '@lido-sdk/react'; | ||
import { enableQaHelpers } from 'utils'; | ||
import type { | ||
FetchRateResult, | ||
StakeSwapDiscountIntegrationKey, | ||
StakeSwapDiscountIntegrationValue, | ||
} from './types'; | ||
import { STAKE_SWAP_INTEGRATION } from 'config'; | ||
import { getSwapIntegration } from './integrations'; | ||
|
||
const DISCOUNT_THRESHOLD = 1.004; | ||
const MOCK_LS_KEY = 'mock-qa-helpers-discount-rate'; | ||
|
||
if (enableQaHelpers && typeof window !== 'undefined') { | ||
(window as any).setMockDiscountRate = (rate?: number) => | ||
rate === undefined | ||
? localStorage.removeItem(MOCK_LS_KEY) | ||
: localStorage.setItem(MOCK_LS_KEY, rate.toString()); | ||
} | ||
|
||
// we show banner if STETH is considerably cheaper to get on dex than staking | ||
// ETH -> stETH rate > THRESHOLD | ||
const fetchRate = async ( | ||
_: string, | ||
integrationKey: StakeSwapDiscountIntegrationKey, | ||
): Promise<FetchRateResult & StakeSwapDiscountIntegrationValue> => { | ||
const integration = getSwapIntegration(integrationKey); | ||
let rate: number; | ||
const mock = localStorage.getItem(MOCK_LS_KEY); | ||
if (enableQaHelpers && mock) { | ||
rate = parseFloat(mock); | ||
} else { | ||
rate = await integration.getRate(); | ||
} | ||
return { | ||
...integration, | ||
rate, | ||
shouldShowDiscount: rate > DISCOUNT_THRESHOLD, | ||
discountPercent: (1 - 1 / rate) * 100, | ||
}; | ||
}; | ||
|
||
export const useSwapDiscount = () => { | ||
return useLidoSWR( | ||
['swr:swap-discount-rate', STAKE_SWAP_INTEGRATION], | ||
// @ts-expect-error useLidoSWR has broken fetcher-key type signature | ||
fetchRate, | ||
{ | ||
...STRATEGY_LAZY, | ||
onError(error, key) { | ||
console.warn( | ||
`[useSwapDiscount] Error fetching ETH->Steth:`, | ||
key, | ||
error, | ||
); | ||
}, | ||
}, | ||
); | ||
}; |
File renamed without changes.
Oops, something went wrong.