Degen Code

Degen Code

Share this post

Degen Code
Degen Code
UniswapV3 — Flash Borrowing
Copy link
Facebook
Email
Notes
More

UniswapV3 — Flash Borrowing

Bro I'll Pay This Back You Know I'm Good For It Bro

Jan 10, 2023
∙ Paid
5

Share this post

Degen Code
Degen Code
UniswapV3 — Flash Borrowing
Copy link
Facebook
Email
Notes
More
3
Share

Continuing our exploration of the Uniswap V3 callback series, this lesson will demonstrate how to execute and repay flash borrows from V3 pools.

You should already know how V2 flash borrowing works. If you don’t, please go back and work through the entire “Smart Contract Arbitrage” series.

The execution for a V3 flash borrow is similar, but there are some important differences.

Unchanged

  • V3 flash borrows must be completed inside the callback function.

  • V3 flash borrows allow calldata to be passed through for evaluation inside the callback.

Changed

  • V3 flash borrows may not be repaid with an arbitrary mix of tokens. The pool sets the fee (or fees, if both tokens are borrowed).

  • V3 flash borrows are performed via a dedicated flash function, instead of a special mode internal to the swap function.

Flash Callback

Reviewing the source of the V3 pool contract, we find that the flash function performs the following action:

/// @inheritdoc IUniswapV3PoolActions
function flash(
    address recipient,
    uint256 amount0,
    uint256 amount1,
    bytes calldata data
) external override lock noDelegateCall {
    uint128 _liquidity = liquidity;
    require(_liquidity > 0, 'L');

    uint256 fee0 = FullMath.mulDivRoundingUp(amount0, fee, 1e6);
    uint256 fee1 = FullMath.mulDivRoundingUp(amount1, fee, 1e6);
    uint256 balance0Before = balance0();
    uint256 balance1Before = balance1();

    if (amount0 > 0) TransferHelper.safeTransfer(token0, recipient, amount0);
    if (amount1 > 0) TransferHelper.safeTransfer(token1, recipient, amount1);

    IUniswapV3FlashCallback(msg.sender).uniswapV3FlashCallback(fee0, fee1, data);

    uint256 balance0After = balance0();
    uint256 balance1After = balance1();

    require(balance0Before.add(fee0) <= balance0After, 'F0');
    require(balance1Before.add(fee1) <= balance1After, 'F1');

[...]

The key line is IUniswapV3FlashCallback(msg.sender).uniswapV3FlashCallback(fee0, fee1, data); which calls the uniswapV3FlashCallback function at msg.sender and then checks that the contract balance has increased by the appropriate amount. If not, it will revert.

What does uniswapV3FlashCallback look like? That interface is defined in IUniswapV3FlashCallback.sol:

interface IUniswapV3FlashCallback {
/// @notice Called to `msg.sender` after transferring to the recipient from IUniswapV3Pool#flash.
/// @dev In the implementation you must repay the pool the tokens sent by flash plus the computed fee amounts.
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
/// @param fee0 The fee amount in token0 due to the pool by the end of the flash
/// @param fee1 The fee amount in token1 due to the pool by the end of the flash
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#flash call
function uniswapV3FlashCallback(
    uint256 fee0,
    uint256 fee1,
    bytes calldata data
) external;
}

It’s a simple enough interface. The V3 pool contract will provide the fees owed for both tokens, plus pass through any calldata that was sent to flash.

The uniswapV3FlashCallback function in our smart contract must take care of all the necessary logic to repay the pool.

Contract Implementation

To test and demonstrate, let’s implement a simple flash callback in Vyper that simply repays the pool and returns.

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2025 BowTiedDevil
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share

Copy link
Facebook
Email
Notes
More