Skip to content
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

Additional filter checks for UniV1/V2 & ParaswapPool trades via Paraswap #230

Merged
merged 13 commits into from
Apr 13, 2021

Conversation

olivdb
Copy link
Contributor

@olivdb olivdb commented Apr 1, 2021

This PR adds additional parameter checks for Paraswap trades using

  • UniV1
  • UniV2
  • Sushi
  • Linkswap
  • Defiswap
  • ZeroExV2-based Paraswappools
  • ZeroExV4-based Paraswappools

@olivdb olivdb changed the title Additional filter checks for Uniswap trades via Paraswap Additional filter checks for UniV1/V2 trades via Paraswap Apr 1, 2021
@olivdb olivdb self-assigned this Apr 1, 2021
@juniset
Copy link
Member

juniset commented Apr 8, 2021

Just a reminder to enable trades using a ParaswapPool. The addresses should be provided to the filter for verification.

@olivdb olivdb force-pushed the paraswapV4-safeuni branch 2 times, most recently from ed95164 to 80eb67a Compare April 12, 2021 12:06
@olivdb olivdb marked this pull request as ready for review April 12, 2021 13:17
@olivdb olivdb requested a review from juniset April 12, 2021 13:17
@@ -171,26 +205,24 @@ contract ParaswapFilter is BaseFilter {
return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we pass the address of uniswapProxy in the constructor to avoid this costly call. The point of having dedicated uniswap methods is to save gas and this call will cost between 5k and 10k gas (post Berlin). It will not change frequently, anw when it does we can just update the filter.

Copy link
Contributor Author

@olivdb olivdb Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uniswapProxy is already assigned in the constructor. This is a check that the Paraswap proxy used by the call is the same as the proxy recorded at the time the filter was created.

Given that changes of the uniswapProxy are now timelocked on Paraswap's side, we could skip the check, assuming Paraswap is willing to increase their timelock (currently 1 hour) to e.g. 7 days so that if they get compromised we have time to get notified and remove our filter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Their timelock cannot be changed without a redeployment of Augustus btw, so unless we can convince them to redeploy, we might want a cronjob on our end to kill our filter as soon as the the proxy gets changed. This could be via a method callable by anyone that lets you shutdown the filter whenever there is a pending change of the uniswapProxy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

Copy link
Contributor Author

@olivdb olivdb Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to checking a local storage variable

function isValidUniSwap(address _augustus, bytes calldata _data) internal view returns (bool) {
        if(!isValidUniswapProxy) {
            return false;
        }
        //...
    }

updated via

    function updateIsValidUniswapProxy() external {
        isValidUniswapProxy = (uniswapProxy == IParaswap(augustus).getUniswapProxy());
    }

But obviously we don't save a ton as there is still the storage read cost.

if(!hasValidUniV2Route(route.payload, uniForkFactory3, uniForkInitCode3)) {
return false;
}
} else if(route.exchange == uniV1Adapter) {
Copy link
Member

@juniset juniset Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed? Given the limited liquidity is there any route that will use Uniswap V1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my experience, 1inch still regularly routes trades via UniV1, especially for older tokens whose liquidity hasn't been fully migrated or simply when a temporary arbitrage makes a UniV1 trade more attractive. I assume the same is true for Paraswap. In any case, if this check is the last one to be done, it doesn't increase the gas cost of any trade.

return hasValidBeneficiary(_wallet, sell.beneficiary) &&
hasTradableToken(sell.path[sell.path.length - 1].to) &&
hasValidExchangeAdapters(sell.path);
return hasValidBeneficiary(_wallet, sell.beneficiary) && hasValidPath(sell.fromToken, sell.path);
}

function isValidSimpleSwap(address _wallet, address _augustus, bytes calldata _data) internal view returns (bool) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any scenario that will use simpleSwap if the accepeted DEX are restricted to Uniswap (fork) and Paraswap Pools?

Copy link
Contributor Author

@olivdb olivdb Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any single-path trade, e.g. a ETH->DAI trade that uses 30% sushi, 30% uniV2, 40% paraswappool.

Copy link
Member

@juniset juniset Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, but then I'm not convinced by the implementation of hasAuthorisedCallees. In particular the use of return authoriser.areAuthorised(_augustus, spenders, _callees, allData); since none of the DEXes has been added to the Registry.

If that's the case then we should have filters for e.g. Uniswap, SushiSwap and ParaswapPool.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but I thought we agreed that for our initial launch we would only support swapOnUniswap[Fork] and multiSwap and only add the callees necessary for simpleSwap later on. IMO isValidSimpleSwap can stay for now as it won't change, it will just return false until we add the filters for the callees.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I thought we would remove simpleSwap until we really support it but it makes sense to keep the filter and just add the callees to the Registry.

As a side note, could we replace _augustus by _wallet in return authoriser.areAuthorised(_augustus, spenders, _callees, allData); to make the code a bit more readable ? I understand that Augustus is calling but in the end the call is being authorised for the wallet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would find this a bit misleading as this variable is the AugustusSwapper contract, not the wallet address. Besides, we use both _wallet and _augustus in isValidSimpleSwap so what should we rename _augustus to in this function?

What about renaming it _authorised or just _target?

@olivdb olivdb changed the title Additional filter checks for UniV1/V2 trades via Paraswap Additional filter checks for UniV1/V2 & ParaswapPool trades via Paraswap Apr 12, 2021
@olivdb olivdb merged commit 9481333 into develop Apr 13, 2021
@juniset juniset deleted the paraswapV4-safeuni branch April 26, 2021 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants