Skip to content

Commit

Permalink
Merge pull request #45 from jediswaplabs/retroboy/revert-swap-logic
Browse files Browse the repository at this point in the history
reverted swap logic
  • Loading branch information
retroboydev authored Nov 2, 2023
2 parents 490b6ba + e74a5d1 commit 228d6bd
Show file tree
Hide file tree
Showing 2 changed files with 280 additions and 72 deletions.
177 changes: 138 additions & 39 deletions src/hooks/useUniswapXSwapCallback.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
import { BigNumber } from '@ethersproject/bignumber'
import * as Sentry from '@sentry/react'
import { CustomUserProperties, SwapEventName } from '@uniswap/analytics-events'
import { Percent } from '@uniswap/sdk-core'
import { DutchOrder, DutchOrderBuilder } from '@uniswap/uniswapx-sdk'
import { useWeb3React } from '@web3-react/core'
import { sendAnalyticsEvent, useTrace } from 'analytics'
import { useCachedPortfolioBalancesQuery } from 'components/PrefetchBalancesWrapper/PrefetchBalancesWrapper'
import { getConnection } from 'connection'
import { formatSwapSignedAnalyticsEventProperties } from 'lib/utils/analytics'
import { useCallback } from 'react'
import { DutchOrderTrade, TradeFillType } from 'state/routing/types'

import { SignatureExpiredError, UserRejectedRequestError } from 'utils/errors'
import { signTypedData } from 'utils/signing'
import { didUserReject, swapErrorToUserReadableMessage } from 'utils/swapErrorToUserReadableMessage'
import { getWalletMeta } from 'utils/walletMeta'
/* eslint-disable */
// @ts-nocheck
import { BigNumber } from '@ethersproject/bignumber';
import * as Sentry from '@sentry/react';
import { CustomUserProperties, SwapEventName } from '@uniswap/analytics-events';
import { Percent } from '@uniswap/sdk-core';
import { DutchOrder, DutchOrderBuilder } from '@uniswap/uniswapx-sdk';
import { useWeb3React } from '@web3-react/core';
import { useCallback } from 'react';

import { sendAnalyticsEvent, useTrace } from 'analytics';
import { useCachedPortfolioBalancesQuery } from 'components/PrefetchBalancesWrapper/PrefetchBalancesWrapper';
import { getConnection } from 'connection';
import { formatSwapSignedAnalyticsEventProperties } from 'lib/utils/analytics';
import { DutchOrderTrade, TradeFillType } from 'state/routing/types';
import { SignatureExpiredError, UserRejectedRequestError } from 'utils/errors';
import { signTypedData } from 'utils/signing';
import { didUserReject, swapErrorToUserReadableMessage } from 'utils/swapErrorToUserReadableMessage';
import { getWalletMeta } from 'utils/walletMeta';

type DutchAuctionOrderError = { errorCode?: number; detail?: string }
type DutchAuctionOrderSuccess = { hash: string }
type DutchAuctionOrderResponse = DutchAuctionOrderError | DutchAuctionOrderSuccess

const isErrorResponse = (res: Response, order: DutchAuctionOrderResponse): order is DutchAuctionOrderError =>
res.status < 200 || res.status > 202
const isErrorResponse = (res: Response, order: DutchAuctionOrderResponse): order is DutchAuctionOrderError => res.status < 200 || res.status > 202;

const UNISWAP_API_URL = process.env.REACT_APP_UNISWAP_API_URL
const UNISWAP_API_URL = process.env.REACT_APP_UNISWAP_API_URL;
if (UNISWAP_API_URL === undefined) {
throw new Error(`UNISWAP_API_URL must be a defined environment variable`)
throw new Error('UNISWAP_API_URL must be a defined environment variable');
}

// getUpdatedNonce queries the UniswapX service for the most up-to-date nonce for a user.
Expand All @@ -34,33 +35,131 @@ if (UNISWAP_API_URL === undefined) {
//
async function getUpdatedNonce(swapper: string, chainId: number): Promise<BigNumber | null> {
try {
const res = await fetch(`${UNISWAP_API_URL}/nonce?address=${swapper}&chainId=${chainId}`)
const { nonce } = await res.json()
return BigNumber.from(nonce)
const res = await fetch(`${UNISWAP_API_URL}/nonce?address=${swapper}&chainId=${chainId}`);
const { nonce } = await res.json();
return BigNumber.from(nonce);
} catch (e) {
Sentry.withScope(function (scope) {
scope.setTag('method', 'getUpdatedNonce')
scope.setLevel('warning')
Sentry.captureException(e)
})
return null
Sentry.withScope((scope) => {
scope.setTag('method', 'getUpdatedNonce');
scope.setLevel('warning');
Sentry.captureException(e);
});
return null;
}
}

export function useUniswapXSwapCallback({
trade,
export function useUniswapXSwapCallback({ trade,
allowedSlippage,
fiatValues,
}: {
fiatValues }: {
trade?: DutchOrderTrade
fiatValues: { amountIn?: number; amountOut?: number; feeUsd?: number }
allowedSlippage: Percent
}) {
const { account, provider, connector } = useWeb3React()
const analyticsContext = useTrace()
const { account, provider, connector } = useWeb3React();
const analyticsContext = useTrace();

const { data } = useCachedPortfolioBalancesQuery({ account });
const portfolioBalanceUsd = data?.portfolios?.[0]?.tokensTotalDenominatedValue?.value;

return useCallback(
async () => {
if (!account) { throw new Error('missing account'); }
if (!provider) { throw new Error('missing provider'); }
if (!trade) { throw new Error('missing trade'); }

const signDutchOrder = async (): Promise<{ signature: string; updatedOrder: DutchOrder }> => {
try {
const updatedNonce = await getUpdatedNonce(account, trade.order.chainId);

const startTime = Math.floor(Date.now() / 1000) + trade.startTimeBufferSecs;

const endTime = startTime + trade.auctionPeriodSecs;

const deadline = endTime + trade.deadlineBufferSecs;

// Set timestamp and account based values when the user clicks 'swap' to make them as recent as possible
const updatedOrder = DutchOrderBuilder.fromOrder(trade.order)
.decayStartTime(startTime)
.decayEndTime(endTime)
.deadline(deadline)
.swapper(account)
.nonFeeRecipient(account, trade.swapFee?.recipient)
// if fetching the nonce fails for any reason, default to existing nonce from the Swap quote.
.nonce(updatedNonce ?? trade.order.info.nonce)
.build();

const { domain, types, values } = updatedOrder.permitData();

const signature = await signTypedData(provider.getSigner(account), domain, types, values);
if (deadline < Math.floor(Date.now() / 1000)) {
throw new SignatureExpiredError();
}
return { signature, updatedOrder };
} catch (swapError) {
if (swapError instanceof SignatureExpiredError) {
throw swapError;
}
if (didUserReject(swapError)) {
throw new UserRejectedRequestError(swapErrorToUserReadableMessage(swapError));
}
throw new Error(swapErrorToUserReadableMessage(swapError));
}
};

const beforeSign = Date.now();
const { signature, updatedOrder } = await signDutchOrder();

sendAnalyticsEvent(SwapEventName.SWAP_SIGNED, {
...formatSwapSignedAnalyticsEventProperties({
trade,
allowedSlippage,
fiatValues,
timeToSignSinceRequestMs: Date.now() - beforeSign,
portfolioBalanceUsd,
}),
...analyticsContext,
// TODO (WEB-2993): remove these after debugging missing user properties.
[CustomUserProperties.WALLET_ADDRESS]: account,
[CustomUserProperties.WALLET_TYPE]: getConnection(connector).getName(),
[CustomUserProperties.PEER_WALLET_AGENT]: provider ? getWalletMeta(provider)?.agent : undefined,
});

const res = await fetch(`${UNISWAP_API_URL}/order`, {
method: 'POST',
body: JSON.stringify({
encodedOrder: updatedOrder.serialize(),
signature,
chainId: updatedOrder.chainId,
quoteId: trade.quoteId,
}),
});

const body = (await res.json()) as DutchAuctionOrderResponse;

const { data } = useCachedPortfolioBalancesQuery({ account })
const portfolioBalanceUsd = data?.portfolios?.[0]?.tokensTotalDenominatedValue?.value
// TODO(UniswapX): For now, `errorCode` is not always present in the response, so we have to fallback
// check for status code and perform this type narrowing.
if (isErrorResponse(res, body)) {
sendAnalyticsEvent('UniswapX Order Post Error', {
...formatSwapSignedAnalyticsEventProperties({
trade,
allowedSlippage,
fiatValues,
portfolioBalanceUsd,
}),
...analyticsContext,
errorCode: body.errorCode,
detail: body.detail,
});
// TODO(UniswapX): Provide a similar utility to `swapErrorToUserReadableMessage` once
// backend team provides a list of error codes and potential messages
throw new Error(`${body.errorCode ?? body.detail ?? 'Unknown error'}`);
}

return () => {};
return {
type: TradeFillType.UniswapX as const,
response: { orderHash: body.hash, deadline: updatedOrder.info.deadline },
};
},
[account, provider, trade, allowedSlippage, fiatValues, portfolioBalanceUsd, analyticsContext, connector],
);
}
Loading

0 comments on commit 228d6bd

Please sign in to comment.