Skip to content

Commit

Permalink
feat: add bebop integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeday committed Mar 13, 2024
1 parent c60f4bf commit 7cb7698
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 3 deletions.
19 changes: 19 additions & 0 deletions assets/icons/bebop.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions config/matomoClickEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const enum MATOMO_CLICK_EVENTS_TYPES {
withdrawalOtherFactorsTooltipMode = 'withdrawalOtherFactorsTooltipMode',
withdrawalFAQtooltipEthAmount = 'withdrawalFAQtooltipEthAmount',
withdrawalGoTo1inch = 'withdrawalGoTo1inch',
withdrawalGoToBebop = 'withdrawalGoToBebop',
withdrawalGoToCowSwap = 'withdrawalGoToCowSwap',
withdrawalGoToParaswap = 'withdrawalGoToParaswap',
withdrawalGoToOpenOcean = 'withdrawalGoToOpenOcean',
Expand Down Expand Up @@ -279,6 +280,11 @@ export const MATOMO_CLICK_EVENTS: Record<
'Click on «Go to 1inch» in aggregators list on Request tab',
'eth_withdrawals_request_go_to_1inch',
],
[MATOMO_CLICK_EVENTS_TYPES.withdrawalGoToBebop]: [
'Ethereum_Withdrawals_Widget',
'Click on «Go to Bebop» in aggregators list on Request tab',
'eth_withdrawals_request_go_to_1inch',
],
[MATOMO_CLICK_EVENTS_TYPES.withdrawalGoToCowSwap]: [
'Ethereum_Withdrawals_Widget',
'Click on «Go to CowSwap» in aggregators list on Request tab',
Expand Down
8 changes: 8 additions & 0 deletions features/withdrawals/request/withdrawal-rates/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import styled from 'styled-components';
import OpenOcean from 'assets/icons/open-ocean.svg';
import Paraswap from 'assets/icons/paraswap-circle.svg';
import Oneinch from 'assets/icons/oneinch-circle.svg';
import Bebop from 'assets/icons/bebop.svg';

export const OpenOceanIcon = styled.img.attrs({
src: OpenOcean,
Expand All @@ -23,3 +24,10 @@ export const OneInchIcon = styled.img.attrs({
})`
display: block;
`;

export const BebopIcon = styled.img.attrs({
src: Bebop,
alt: 'Bebop',
})`
display: block;
`;
31 changes: 30 additions & 1 deletion features/withdrawals/request/withdrawal-rates/integrations.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { Zero } from '@ethersproject/constants';
import { getTokenAddress, CHAINS, TOKENS } from '@lido-sdk/constants';
import { BigNumber } from 'ethers';
import { getAddress } from 'ethers/lib/utils.js';
import { formatEther } from '@ethersproject/units';

import { getOneInchRate } from 'utils/get-one-inch-rate';
import { getBebopRate } from 'utils/get-bebop-rate';
import { getOpenOceanRate } from 'utils/get-open-ocean-rate';
import { standardFetcher } from 'utils/standardFetcher';
import { OPEN_OCEAN_REFERRAL_ADDRESS } from 'config/external-links';
import { MATOMO_CLICK_EVENTS_TYPES } from 'config/matomoClickEvents';

import { OneInchIcon, OpenOceanIcon, ParaSwapIcon } from './icons';
import { BebopIcon, OneInchIcon, OpenOceanIcon, ParaSwapIcon } from './icons';

import type {
DexWithdrawalApi,
Expand Down Expand Up @@ -124,6 +126,23 @@ const getOneInchWithdrawalRate: GetRateType = async (params) => {
};
};

const getBebopWithdrawalRate: GetRateType = async ({ amount, token }) => {
try {
if (amount.gt(Zero)) {
return await getBebopRate(amount, token, 'ETH');
}
} catch (e) {
console.warn(
'[getOneInchWithdrawalRate] Failed to receive withdraw rate',
e,
);
}
return {
rate: null,
toReceive: null,
};
};

const dexWithdrawalMap: DexWithdrawalIntegrationMap = {
'open-ocean': {
title: 'OpenOcean',
Expand Down Expand Up @@ -158,6 +177,16 @@ const dexWithdrawalMap: DexWithdrawalIntegrationMap = {
token == TOKENS.STETH ? 'stETH' : 'wstETH'
}/ETH?sourceTokenAmount=${formatEther(amount)}`,
},
bebop: {
title: 'Bebop',
icon: BebopIcon,
fetcher: getBebopWithdrawalRate,
matomoEvent: MATOMO_CLICK_EVENTS_TYPES.withdrawalGoToBebop,
link: (amount, token) =>
`https://bebop.xyz/trade?network=ethereum&buy=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&sell=${getAddress(
getTokenAddress(CHAINS.Mainnet, token),
)}&sellAmounts=${formatEther(amount)}`,
},
} as const;

export const getDexConfig = (dexKey: DexWithdrawalApi) =>
Expand Down
2 changes: 1 addition & 1 deletion features/withdrawals/request/withdrawal-rates/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export type SingleWithdrawalRateResult = {
toReceive: BigNumber | null;
};

export type DexWithdrawalApi = 'paraswap' | 'open-ocean' | 'one-inch';
export type DexWithdrawalApi = 'paraswap' | 'open-ocean' | 'one-inch' | 'bebop';

export type DexWithdrawalIntegration = {
title: string;
Expand Down
2 changes: 1 addition & 1 deletion features/withdrawals/withdrawals-constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ export const VALIDATION_CONTEXT_TIMEOUT = 4000;

export const ENABLED_WITHDRAWAL_DEXES: DexWithdrawalApi[] = [
'one-inch',
'open-ocean',
'bebop',
'paraswap',
];
81 changes: 81 additions & 0 deletions utils/get-bebop-rate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { CHAINS, TOKENS, getTokenAddress } from '@lido-sdk/constants';
import { BigNumber } from 'ethers';
import { standardFetcher } from './standardFetcher';
import { ESTIMATE_ACCOUNT } from 'config';
import { getAddress } from 'ethers/lib/utils.js';

type BebopGetQuotePartial = {
routes: {
quote: {
buyTokens: Record<
string,
{
amount: string;
amountBeforeFee: string;
}
>;
sellTokens: Record<
string,
{
amount: string;
priceBeforeFee: number;
}
>;
};
}[];
};

type RateToken = TOKENS.STETH | TOKENS.WSTETH | 'ETH';

type RateCalculationResult = { rate: number; toReceive: BigNumber };

const getRateTokenAddress = (token: RateToken) =>
token === 'ETH'
? '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'
: getTokenAddress(CHAINS.Mainnet, token);

export const getBebopRate = async (
amount: BigNumber,
fromToken: RateToken,
toToken: RateToken,
): Promise<RateCalculationResult> => {
const basePath = 'https://api.bebop.xyz/router/ethereum/v1/quote';

const sell_tokens = getAddress(getRateTokenAddress(fromToken));
const buy_tokens = getAddress(getRateTokenAddress(toToken));

const params = new URLSearchParams({
sell_tokens,
buy_tokens,
taker_address: ESTIMATE_ACCOUNT,
sell_amounts: amount.toString(),
approval_type: 'Standard',
});

const data = await standardFetcher<BebopGetQuotePartial>(
`${basePath}/?${params.toString()}`,
);

const bestRoute = data.routes.toSorted(
(r1, r2) =>
r2.quote.sellTokens[sell_tokens].priceBeforeFee -
r1.quote.sellTokens[sell_tokens].priceBeforeFee,
)[0];

if (
bestRoute &&
bestRoute.quote.sellTokens[sell_tokens] &&
bestRoute.quote.buyTokens[buy_tokens]
) {
const rate = data.routes[0].quote.sellTokens[sell_tokens].priceBeforeFee;

const toAmount = BigNumber.from(
data.routes[0].quote.buyTokens[buy_tokens].amountBeforeFee,
);
return {
rate,
toReceive: toAmount,
};
}
throw new Error('[getBebopRate] Could not get quote, invalid response body');
};

0 comments on commit 7cb7698

Please sign in to comment.