Skip to content

Cowswap deadline #218

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/components/Aggregator/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { InfoOutlineIcon } from '@chakra-ui/icons';
import {
Button,
Checkbox,
Expand All @@ -12,11 +13,16 @@ import {
ModalFooter,
ModalHeader,
ModalOverlay,
Switch,
Tooltip,
useDisclosure
} from '@chakra-ui/react';
import { chunk } from 'lodash';
import { useLocalStorage } from '~/hooks/useLocalStorage';

export const Settings = ({ adapters, disabledAdapters, setDisabledAdapters, onClose: onExternalClose }) => {
const [isDegenModeEnabled, setIsDegenModeEnabled] = useLocalStorage('llamaswap-degenmode', false);
const [cowswapDeadline, setCowswapDeadline] = useLocalStorage('llamaswap-cowswapDeadline', 30);
const { isOpen, onClose } = useDisclosure({ defaultIsOpen: true });
const onCloseClick = () => {
onExternalClose();
Expand All @@ -38,6 +44,40 @@ export const Settings = ({ adapters, disabledAdapters, setDisabledAdapters, onCl
<ModalHeader>Settings</ModalHeader>
<ModalCloseButton />
<ModalBody>
<HStack mt={1} mb={4}>
<Heading size={'xs'}>Degen Mode</Heading>{' '}
<Tooltip label="Disable price impact warnings.">
<InfoOutlineIcon />
</Tooltip>
<Switch onChange={() => setIsDegenModeEnabled((mode) => !mode)} isChecked={isDegenModeEnabled} />
</HStack>
<HStack mt={1} mb={4}>
<Heading size={'xs'}>CowSwap Deadline</Heading>{' '}
<Tooltip label="Your swap will expire if not executed for longer than the duration set here">
<InfoOutlineIcon />
</Tooltip>
<input
onChange={(d) => {
const num = Number(d.target.value);
if (num <= 180 && num >= 2 && Number.isInteger(num)) {
setCowswapDeadline(num);
} else {
setCowswapDeadline(30);
}
}}
min={2}
step={1}
type="number"
max="180"
value={cowswapDeadline}
style={{
width: '3em',
borderRadius: '0.4em',
textAlign: 'end'
}}
/>{' '}
<span>minutes</span>
</HStack>
<Heading size={'xs'}>Enabled Aggregators</Heading>

<HStack mt={4}>
Expand Down
32 changes: 23 additions & 9 deletions src/components/Aggregator/SwapConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import {
} from '@chakra-ui/react';
import React, { useState } from 'react';

const SwapConfiramtion = ({ handleSwap, isUnknownPrice = false, isMaxPriceImpact = false }) => {
const SwapConfiramtion = ({
handleSwap,
isUnknownPrice = false,
isMaxPriceImpact = false,
isDegenModeEnabled = false
}) => {
const { isOpen, onToggle, onClose } = useDisclosure();
const requiredText = isMaxPriceImpact ? 'trade' : 'confirm';
const [value, setValue] = useState('');
Expand Down Expand Up @@ -50,14 +55,23 @@ const SwapConfiramtion = ({ handleSwap, isUnknownPrice = false, isMaxPriceImpact
<br />
You'll likely lose money.
<br />
Type "{requiredText}" to make a swap.
<Input
placeholder="Type here..."
mt={'4px'}
onChange={(e) => setValue(e.target.value)}
value={value}
></Input>
<Button colorScheme={'red'} onClick={handleSwap} mt={4} isDisabled={isSwapDisabled}>
{!isDegenModeEnabled ? (
<>
Type "{requiredText}" to make a swap.
<Input
placeholder="Type here..."
mt={'4px'}
onChange={(e) => setValue(e.target.value)}
value={value}
></Input>
</>
) : null}
<Button
colorScheme={'red'}
onClick={handleSwap}
mt={4}
isDisabled={isSwapDisabled && !isDegenModeEnabled}
>
Swap with high slippage
</Button>
</PopoverBody>
Expand Down
6 changes: 4 additions & 2 deletions src/components/Aggregator/adapters/cowswap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,14 @@ export async function getQuote(chain: string, from: string, to: string, amount:
const tokenTo = to === ethers.constants.AddressZero ? nativeToken : to;
const tokenFrom = isEthflowOrder ? wrappedTokens[chain] : from;
const isBuyOrder = extra.amountOut && extra.amountOut !== '0';

const validTo = Math.floor(Date.now() / 1e3) + (extra.deadline ?? 30) * 60;

// Ethflow orders are always sell orders.
// Source: https://github.com/cowprotocol/ethflowcontract/blob/v1.0.0/src/libraries/EthFlowOrder.sol#L93-L95
if (isEthflowOrder && isBuyOrder) {
throw new Error('buy orders from Ether are not allowed');
}

// amount should include decimals
const data = await fetch(`${chainToId[chain]}/api/v1/quote`, {
method: 'POST',
Expand All @@ -74,6 +75,7 @@ export async function getQuote(chain: string, from: string, to: string, amount:
sellTokenBalance: 'erc20',
buyTokenBalance: 'erc20',
from: extra.userAddress,
validTo,
//"priceQuality": "fast",
signingScheme: isEthflowOrder ? 'eip1271' : 'eip712', // for selling directly ether, another signature type is required
onchainOrder: isEthflowOrder ? true : false, // for selling directly ether, we have to quote for onchain orders
Expand Down
10 changes: 7 additions & 3 deletions src/components/Aggregator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,9 @@ export function AggregatorContainer({ tokenList, sandwichList }) {
const [slippage, setSlippage] = useLocalStorage('llamaswap-slippage', '0.5');
const [lastOutputValue, setLastOutputValue] = useState(null);
const [disabledAdapters, setDisabledAdapters] = useLocalStorage('llamaswap-disabledadapters', []);
const [isDegenModeEnabled, _] = useLocalStorage('llamaswap-degenmode', false);
const [isSettingsModalOpen, setSettingsModalOpen] = useState(false);
const [cowswapDeadline, _] = useLocalStorage('llamaswap-cowswapDeadline', 30);

// mobile states
const [uiState, setUiState] = useState(STATES.INPUT);
Expand Down Expand Up @@ -470,7 +472,8 @@ export function AggregatorContainer({ tokenList, sandwichList }) {
toToken: finalSelectedToToken,
slippage,
isPrivacyEnabled,
amountOut: amountOutWithDecimals
amountOut: amountOutWithDecimals,
deadline: cowswapDeadline
}
});

Expand Down Expand Up @@ -845,7 +848,7 @@ export function AggregatorContainer({ tokenList, sandwichList }) {

const handleSwap = () => {
if (selectedRoute && selectedRoute.price && !slippageIsWorng) {
if (hasMaxPriceImpact) {
if (hasMaxPriceImpact && !isDegenModeEnabled) {
toast({
title: 'Price impact is too high!',
description: 'Swap is blocked, please try another route.',
Expand Down Expand Up @@ -1088,7 +1091,7 @@ export function AggregatorContainer({ tokenList, sandwichList }) {
<Button colorScheme={'messenger'} onClick={() => setUiState(STATES.ROUTES)}>
Select Aggregator
</Button>
) : hasMaxPriceImpact ? (
) : hasMaxPriceImpact && !isDegenModeEnabled ? (
<Button colorScheme={'messenger'} disabled>
Price impact is too large
</Button>
Expand Down Expand Up @@ -1128,6 +1131,7 @@ export function AggregatorContainer({ tokenList, sandwichList }) {
isUnknownPrice={isUnknownPrice}
isMaxPriceImpact={hasMaxPriceImpact}
handleSwap={handleSwap}
isDegenModeEnabled={isDegenModeEnabled}
/>
) : (
<Button
Expand Down
1 change: 1 addition & 0 deletions src/components/Aggregator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export interface ExtraData {
userAddress: string;
slippage: string;
amountOut: string;
deadline?: number;
}