Skip to content

[draft] DEX aggregator liquidation bot#632

Draft
scott-silver wants to merge 56 commits intomainfrom
silver/dex-liquidation-bot
Draft

[draft] DEX aggregator liquidation bot#632
scott-silver wants to merge 56 commits intomainfrom
silver/dex-liquidation-bot

Conversation

@scott-silver
Copy link
Copy Markdown
Contributor

@scott-silver scott-silver commented Dec 7, 2022

Extremely rough version of a 1inch-enabled liquidation bot. Lots of changes to make still, but want to get some visibility on the decisions I'm making and thoughts on the remaining issues.

Some outstanding issues:

  1. We use a Uniswap flash loan (currently using the DAI/USDC pool). Uniswap pools have a reentrancy guard, so they will throw an error if you interact with the pool again in the flash loan transaction.

Sometimes, the 1inch router will use a route that involves swapping via the DAI/USDC pool, and the transaction will fail with "LOK".

  • figure out how to specify the reasonable max you should attempt for any asset
  • figure out how to always absorb (even when the protocol is not selling assets)
  • add a sweep function to clear out any dust that the contract collects?

assertGt(CometInterface(comet).getReserves(), initialReserves);
}

// XXX test actually liquidating an underwater account
Copy link
Copy Markdown
Contributor Author

@scott-silver scott-silver Dec 7, 2022

Choose a reason for hiding this comment

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

I have not yet figured out the best way to mimic an underwater account. If you take out a borrow position and then fast-forward until the interest put the position underwater, then the forked chain's block timestamp is set significantly higher than the current head of the chain in reality.

this causes issues when you request routes from 1inch: the rates returned are for the current block timestamp. if your forked chain is too far ahead of reality, some of the swap contracts will revert saying that your rates are stale (this happens with Curve most often, "src rate stale or flagged").

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not an answer to your original question, but I Googled that error and it seems to be coming from Synthetix. Is Curve routing through Synthetix (or maybe the other way around)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My bad, I meant Synthetix not Curve. It comes from this contract:

https://github.com/Synthetixio/synthetix/blob/v2.80.0-alpha/contracts/Exchanger.sol#L527

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How about prank as chainlink and decrease the price of the assets in it's price feed contract?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

oh that's an interesting idea

Comment on lines +139 to +140
address[] calldata swapTargets,
bytes[] calldata swapTransactions,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we validate that these lengths match?

function swap(address asset) public {
address[] memory liquidatableAccounts;

// XXX not a static call; will actually absorb the liquidatableAccounts
Copy link
Copy Markdown
Contributor

@kevincheng96 kevincheng96 Dec 9, 2022

Choose a reason for hiding this comment

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

If you want to do a static call, you can wrap this around a snapshot() and revertTo(): foundry-rs/foundry#2463 (comment)

// expect the protocol reserves to have increased
assertGt(CometInterface(comet).getReserves(), initialReserves);

// XXX make sure that you're making > 1% of the value of the swap
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why >1%? Is that a threshold we set somewhere?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

no, it's just an approximation of how much you should be making. if the protocol is selling at a 2.5% discount, and you have to pay some fee for the flash loan and there is some slippage in the swap, you should end up receiving ~1-2% of the value of the collateral

FlashCallbackData memory flashCallbackData = abi.decode(data, (FlashCallbackData));
CallbackValidation.verifyCallback(factory, flashCallbackData.poolKey);

TransferHelper.safeApprove(CometInterface(flashCallbackData.comet).baseToken(), address(flashCallbackData.comet), flashCallbackData.flashLoanAmount);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

use baseToken from line 220

@scott-silver scott-silver mentioned this pull request Dec 29, 2022
5 tasks
@jflatow jflatow added potential enhancement Potential features revisit This PR is worth keeping open but approach needs to be revisited labels Jan 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

potential enhancement Potential features revisit This PR is worth keeping open but approach needs to be revisited

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants