Algebra Integral
HomepageSocialsIntegrate
  • Overview / FAQ
    • 💡What is Algebra?
    • 🫂The Algebra Ecosystem
    • 🧑‍🔬Algebra Integral
    • 📚Glossary
    • 🪙Tokenomics
    • 📱Social Media & Links
    • 👨‍🎨Brand Assets
    • Partners
      • Algebra V1.0
        • QuickSwap Polygon
        • ZyberSwap
        • Thena
        • StellaSwap
        • QuickSwap Dogechain
        • SkullSwap
        • UbeSwap
        • Litx
      • Algebra V1.9
        • Camelot
        • Lynex
        • Swapbased
        • Synthswap
        • Zyberswap Optimism
        • Hercules
      • Integral 1.0
        • Swapsicle Telos
        • Swapsicle Mantle
        • Kim
        • Fenix
        • Blade
        • SilverSwap Fantom
        • Horizon
        • Glyph Exchange
        • SilverSwap Sonic
        • SwapX
        • Bulla
      • Integral 1.1
        • Scribe
      • Integral 1.2
        • Fibonacci
        • Voltage
        • Henjin
        • Wasabee
        • Holiverse
        • MorFi
        • StellaSwap
        • QuickSwap Soneium
  • Algebra Integral / Technical Reference
    • ℹ️Intro
    • 🔍Audits
    • 🏗️Integration Process
      • Specification and API of contracts
        • Algebra Pool
        • Algebra Factory
        • Swap Router
        • Nonfungible Position Manager
        • Quoter
        • QuoterV2
        • TickLens
      • Interaction with pools
        • Getting data from pools
      • Subgraphs and analytics
        • Examples of queries
      • Technical Guides
        • Intro
        • Swaps
          • Single swaps
          • Multihop swaps
        • Providing liquidity
          • Setting up your contract
          • Mint a new position
          • Collect fees
          • Decrease liquidity
          • Increase liquidity
          • Final Contract
        • Flashloans
          • Setting up your contract
          • Calling flash
          • Flash callback
          • Final contract
      • Migration from UniswapV3
    • 🖲️Core Logic
      • Pool overview
      • Swap calculation
      • Liquidity and positions
      • Ticks
        • Ticks search tree
      • Reserves
      • Flash
      • Plugins
      • AlgebraFactory and roles
    • 🧩Plugins
      • Overview
      • Adaptive Fee
      • Sliding Fee
      • Whitelist Discount Fee
      • Safety Switch
      • Position Limit Orders
      • Managed Swap Fee
      • FAQ
    • 📖Guides
      • 🔨Plugin Development
      • 🔬Plugin Testing
      • ☄️Plugin Deployment
    • ⬆️Changes V1
    • ⬆️Changes V1.1
    • ⬆️Changes v1.2
  • ⬆️Changes v1.2.1
  • Algebra V1 / Technical Reference
    • 🔏Contracts
      • API Reference v1.0
        • V1.0 - Core
          • AlgebraFactory
          • AlgebraPool
          • AlgebraPoolDeployer
          • DataStorage
          • DataStorageOperator
          • IAlgebraFactory
          • IAlgebraFlashCallback
          • IAlgebraMintCallback
          • IAlgebraPoolActions
          • IAlgebraPoolDeployer
          • IAlgebraPoolDerivedState
          • IAlgebraPoolEvents
          • IAlgebraPoolImmutables
          • IAlgebraPoolPermissionedActions
          • IAlgebraPoolState
          • IAlgebraSwapCallback
          • IAlgebraVirtualPool
          • IDataStorageOperator
          • IERC20Minimal
          • PoolImmutables
          • PoolState
        • V1.0 - Periphery
          • AlgebraInterfaceMulticall
          • ERC20
          • ERC20Permit
          • ERC165
          • ERC721
          • ERC721Permit
          • IAlgebraMintCallback
          • IAlgebraFactory
          • IAlgebraPoolDerivedState
          • IAlgebraPoolActions
          • IAlgebraPoolEvents
          • IAlgebraPoolImmutables
          • IAlgebraPoolPermissionedActions
          • IAlgebraPoolState
          • IAlgebraSwapCallback
          • IERC20
          • IDataStorageOperator
          • IERC20Metadata
          • IERC20Permit
          • IERC20PermitAllowed
          • IERC165
          • IERC721
          • IERC721Enumerable
          • IERC721Metadata
          • IERC721Permit
          • IERC721Receiver
          • IERC1271
          • IMulticall
          • INonfungiblePositionManager
          • INonfungibleTokenPositionDescriptor
          • IPeripheryImmutableState
          • IPeripheryPayments
          • IPeripheryPaymentsWithFee
          • IPoolInitializer
          • IQuoter
          • IQuoterV2
          • ISelfPermit
          • ISwapRouter
          • ITickLens
          • IUniswapV2Pair
          • IV3Migrator
          • IWNativeToken
          • LiquidityManagement
          • Multicall
          • NFTDescriptor
          • NonfungiblePositionManager
          • NonfungibleTokenPositionDescriptor
          • PeripheryImmutableState
          • PeripheryPayments
          • PeripheryPaymentsWithFee
          • PoolInitializer
          • Quoter
          • QuoterV2
          • SwapRouter
          • SelfPermit
          • TickLens
          • V3Migrator
        • V1.0 - Tokenomics
          • AlgebraEternalFarming
          • AlgebraFarming
          • AlgebraIncentiveFarming
          • AlgebraLimitFarming
          • AlgebraTokenStaking
          • AlgebraVault
          • AlgebraVirtualPoolBase
          • ERC20
          • ERC165
          • ERC721
          • ERC721Permit
          • EternalVirtualPool
          • FarmingCenter
          • FarmingCenterVault
          • FreezableToken
          • IAlgebraEternalFarming
          • IAlgebraEternalVirtualPool
          • IAlgebraFactory
          • IAlgebraFarming
          • IAlgebraIncentiveFarming
          • IAlgebraIncentiveVirtualPool
          • IAlgebraLimitFarming
          • IAlgebraLimitVirtualPool
          • IAlgebraPoolActions
          • IAlgebraPoolDeployer
          • IAlgebraPoolDerivedState
          • IAlgebraPoolEvents
          • IAlgebraPoolImmutables
          • IAlgebraPoolPermissionedActions
          • IAlgebraPoolState
          • IAlgebraSwapCallback
          • IAlgebraVirtualPool
          • IAlgebraVirtualPoolBase
          • IDataStorageOperator
          • IERC20
          • IERC20Minimal
          • IERC165
          • IERC721
          • IERC721Enumerable
          • IERC721Metadata
          • IERC721Permit
          • IERC721Receiver
          • IERC1271
          • IFarmingCenter
          • IFarmingCenterVault
          • IMulticall
          • IncentiveVirtualPool
          • INonfungiblePositionManager
          • IPeripheryPayments
          • IPeripheryImmutableState
          • IPoolInitializer
          • ISwapRouter
          • IWNativeToken
          • LimitVirtualPool
          • Multicall
          • PeripheryPayments
      • API Reference v1.9
        • V1.9 - Core
          • AlgebraFactory
          • AlgebraPool
          • AlgebraPoolDeployer
          • DataStorage
          • DataStorageOperator
          • IAlgebraFactory
          • IAlgebraFlashCallback
          • IAlgebraMintCallback
          • IAlgebraPoolActions
          • IAlgebraPoolDeployer
          • IAlgebraPoolDerivedState
          • IAlgebraPoolEvents
          • IAlgebraPoolImmutables
          • IAlgebraPoolPermissionedActions
          • IAlgebraPoolState
          • IAlgebraSwapCallback
          • IAlgebraVirtualPool
          • IDataStorageOperator
          • IERC20Minimal
          • PoolImmutables
          • PoolState
        • V1.9 - Periphery
          • ERC721Permit
          • AlgebraInterfaceMulticall
          • IERC20Metadata
          • IERC20PermitAllowed
          • IERC721Permit
          • IERC1271
          • IMulticall
          • INonfungiblePositionManager
          • INonfungibleTokenPositionDescriptor
          • IPeripheryImmutableState
          • IPeripheryPayments
          • IPeripheryPaymentsWithFee
          • IPoolInitializer
          • IQuoter
          • IQuoterV2
          • ISelfPermit
          • ISwapRouter
          • ITickLens
          • IV3Migrator
          • IWNativeToken
          • LiquidityManagement
          • Multicall
          • NFTDescriptor
          • NonfungiblePositionManager
          • NonfungibleTokenPositionDescriptor
          • PeripheryImmutableState
          • PeripheryPayments
          • PoolInitializer
          • PeripheryPaymentsWithFee
          • Quoter
          • QuoterV2
          • SelfPermit
          • SwapRouter
          • TickLens
          • V3Migrator
        • V1.9 - Tokenomics
          • AlgebraFarming
          • AlgebraEternalFarming
          • AlgebraLimitFarming
          • AlgebraTokenStaking
          • AlgebraVault
          • AlgebraVirtualPoolBase
          • ERC20
          • EternalVirtualPool
          • FarmingCenter
          • FarmingCenterVault
          • FreezableToken
          • IAlgebraEternalFarming
          • IAlgebraEternalVirtualPool
          • IAlgebraFarming
          • IAlgebraLimitFarming
          • IAlgebraLimitVirtualPool
          • IAlgebraVirtualPoolBase
          • IERC20Minimal
          • IFarmingCenter
          • IFarmingCenterVault
          • LimitVirtualPool
          • PeripheryPayments
      • API Reference v1.9 - Directional Fees
        • V1.9 (Directional Fees) - Core
          • AlgebraFactory
          • AlgebraPool
          • AlgebraPoolDeployer
          • DataStorage
          • DataStorageOperator
          • IAlgebraFactory
          • IAlgebraFlashCallback
          • IAlgebraMintCallback
          • IAlgebraPoolActions
          • IAlgebraPoolDeployer
          • IAlgebraPoolDerivedState
          • IAlgebraPoolEvents
          • IAlgebraPoolImmutables
          • IAlgebraPoolPermissionedActions
          • IAlgebraSwapCallback
          • IAlgebraPoolState
          • IAlgebraVirtualPool
          • IDataStorageOperator
          • IERC20Minimal
          • PoolImmutables
          • PoolState
        • V1.9 (Directional Fees) - Periphery
          • AlgebraInterfaceMulticall
          • ERC721Permit
          • IERC20Metadata
          • IERC20PermitAllowed
          • IERC721Permit
          • IERC1271
          • IMulticall
          • INonfungiblePositionManager
          • INonfungibleTokenPositionDescriptor
          • IPeripheryImmutableState
          • IPeripheryPayments
          • IPeripheryPaymentsWithFee
          • IPoolInitializer
          • IQuoter
          • IQuoterV2
          • ISelfPermit
          • ISwapRouter
          • ITickLens
          • IV3Migrator
          • IWNativeToken
          • LiquidityManagement
          • Multicall
          • NFTDescriptor
          • NonfungiblePositionManager
          • NonfungibleTokenPositionDescriptor
          • PeripheryImmutableState
          • PeripheryPayments
          • PeripheryPaymentsWithFee
          • PoolInitializer
          • Quoter
          • QuoterV2
          • SelfPermit
          • SwapRouter
          • TickLens
          • V3Migrator
        • V1.9 (Directional Fees) - Tokenomics
          • AlgebraFarming
          • AlgebraEternalFarming
          • AlgebraLimitFarming
          • AlgebraTokenStaking
          • AlgebraVault
          • AlgebraVirtualPoolBase
          • ERC20
          • EternalVirtualPool
          • FarmingCenter
          • FarmingCenterVault
          • FreezableToken
          • IAlgebraEternalFarming
          • IAlgebraEternalVirtualPool
          • IAlgebraFarming
          • IAlgebraLimitVirtualPool
          • IAlgebraLimitFarming
          • IAlgebraVirtualPoolBase
          • IERC20Minimal
          • IFarmingCenterVault
          • IFarmingCenter
          • LimitVirtualPool
          • PeripheryPayments
      • API Reference v2.0
        • V2.0 - Core
          • AlgebraCommunityVault
          • AlgebraFactory
          • AlgebraFeeConfiguration
          • AlgebraPool
          • AlgebraPoolBase
          • AlgebraPoolDeployer
          • DataStorage
          • DataStorageOperator
          • DerivedState
          • IAlgebraFactory
          • IAlgebraFlashCallback
          • IAlgebraMintCallback
          • IAlgebraPoolActions
          • IAlgebraPoolDeployer
          • IAlgebraPoolDerivedState
          • IAlgebraPoolErrors
          • IAlgebraPoolEvents
          • IAlgebraPoolImmutables
          • IAlgebraPoolPermissionedActions
          • IAlgebraPoolState
          • IAlgebraSwapCallback
          • IAlgebraVirtualPool
          • IDataStorageOperator
          • IERC20Minimal
          • Positions
          • ReservesManager
        • V2.0 - Periphery
          • AlgebraInterfaceMulticall
          • ERC721Permit
          • IERC20Metadata
          • IERC20PermitAllowed
          • IERC721Permit
          • IERC1271
          • ILimitOrderManager
          • IMulticall
          • INonfungiblePositionManager
          • INonfungibleTokenPositionDescriptor
          • IPeripheryImmutableState
          • IPeripheryPayments
          • IPeripheryPaymentsWithFee
          • IPoolInitializer
          • IPositionFollower
          • IQuoter
          • IQuoterV2
          • ISelfPermit
          • ISwapRouter
          • ITickLens
          • IV3Migrator
          • IWNativeToken
          • LimitOrderManagement
          • LimitOrderManager
          • LiquidityManagement
          • Multicall
          • NFTDescriptor
          • NonfungiblePositionManager
          • NonfungibleTokenPositionDescriptor
          • PeripheryImmutableState
          • PeripheryPayments
          • PeripheryPaymentsWithFee
          • PoolInitializer
          • Quoter
          • QuoterV2
          • SelfPermit
          • SwapRouter
          • TickLens
          • V3Migrator
        • V2.0 - Tokenomics
          • AlgebraEternalFarming
          • EternalVirtualPool
          • FarmingCenter
          • IAccessControl
          • IAlgebraEternalFarming
          • IAlgebraEternalVirtualPool
          • IFarmingCenter
          • IncentiveKey
          • VirtualTickStructure
      • API Reference v2.0 - Directional Fees
        • V2.0 (Directional Fees) - Core
          • AlgebraCommunityVault
          • AlgebraFactory
          • AlgebraFeeConfiguration
          • AlgebraPool
          • AlgebraPoolBase
          • AlgebraPoolDeployer
          • DataStorage
          • DataStorageOperator
          • DerivedState
          • IAlgebraFactory
          • IAlgebraFlashCallback
          • IAlgebraMintCallback
          • IAlgebraPoolActions
          • IAlgebraPoolDeployer
          • IAlgebraPoolDerivedState
          • IAlgebraPoolErrors
          • IAlgebraPoolEvents
          • IAlgebraPoolImmutables
          • IAlgebraPoolPermissionedActions
          • IAlgebraPoolState
          • IAlgebraSwapCallback
          • IAlgebraVirtualPool
          • IDataStorageOperator
          • IERC20Minimal
          • Positions
          • ReservesManager
        • V2.0 (Directional Fees) - Periphery
          • AlgebraInterfaceMulticall
          • ERC721Permit
          • IERC20Metadata
          • IERC20PermitAllowed
          • IERC721Permit
          • IERC1271
          • ILimitOrderManager
          • IMulticall
          • INonfungiblePositionManager
          • INonfungibleTokenPositionDescriptor
          • IPeripheryImmutableState
          • IPeripheryPayments
          • IPeripheryPaymentsWithFee
          • IPoolInitializer
          • IPositionFollower
          • IQuoter
          • IQuoterV2
          • ISelfPermit
          • ISwapRouter
          • ITickLens
          • IV3Migrator
          • IWNativeToken
          • LimitOrderManagement
          • LimitOrderManager
          • LiquidityManagement
          • Multicall
          • NFTDescriptor
          • NonfungiblePositionManager
          • NonfungibleTokenPositionDescriptor
          • PeripheryImmutableState
          • PeripheryPayments
          • PeripheryPaymentsWithFee
          • PoolInitializer
          • QuoterV2
          • Quoter
          • SelfPermit
          • SwapRouter
          • TickLens
          • V3Migrator
        • V2.0 (Directional Fees) - Tokenomics
          • AlgebraEternalFarming
          • EternalVirtualPool
          • FarmingCenter
          • IAccessControl
          • IAlgebraEternalFarming
          • IAlgebraEternalVirtualPool
          • IFarmingCenter
          • IncentiveKey
          • VirtualTickStructure
      • Adaptive Fee
        • Adaptive Fee
        • How to set up specific formula behaviour
        • How to tweak formula behaviour
      • Contracts Setup
        • Deployment
          • Contracts Deployment
          • Deployment Scripts
        • Misc
          • POOL_INIT_CODE_HASH
          • Code Audits
          • Deployment Addresses
      • The Algebra Guides
        • Flash Integrations
          • The Full Contract
          • Calling Flash
          • Flash Callback
          • Inheritance constructor
        • Liquidity Mining
          • Liquidity Mining Overview
        • Providing Liquidity
          • Collecting fees
          • Decrease liquidity
          • Increase Liquidity Within The Current Range
          • Mint a new position
          • Set up your contract
          • The full contract
        • Swaps
          • Multihop swaps
          • Single swaps
    • 📊Subgraph
      • Query Examples
        • Query Examples
      • GraphQL Schema
        • Farming GraphQL Schema
        • Algebra GraphQL Schema
      • Subgraph Setup
        • Subgraph Settings
        • Subgraph Deployment
    • 🖥️Frontend
      • Admin Panel
        • Contracts
          • Admin Panel
          • Changing Subgraph
        • Eternal Farmings
          • Create Eternal Farming
          • Managing Eternal Farming
        • Limit Farmings
          • Create Limit Farming
    • ⚙️Backend
      • Backend Setup
    • ⛑️Guides
      • Step by Step Deployment
  • Other
    • 📦Archived Documentation
    • ❗Link Awareness Notice
Powered by GitBook
On this page
  • Setting Up The Callback
  • Initiating A Swap
  • Paying back the pool
  • The full function
  1. Algebra Integral / Technical Reference
  2. Integration Process
  3. Technical Guides
  4. Flashloans

Flash callback

PreviousCalling flashNextFinal contract

Setting Up The Callback

In the following part, we will override the flash callback with our custom logic to execute the desired swaps and pay the profit to the original msg.sender.

Declare the algebraFlashCallback function and override it.

    function algebraFlashCallback(
        uint256 fee0,
        uint256 fee1,
        bytes calldata data
    ) external override {

Declare a variable decoded in memory and assign it to the

It was previously encoded into the calldata.

        FlashCallbackData memory decoded = abi.decode(data, (FlashCallbackData));

Each callback must be checked and verified to make sure that the callback comes from a real pool. Without this, the pool contract will be vulnerable to an attack through an EOA manipulating the callback function.

        CallbackValidation.verifyCallback(poolDeployer, decoded.poolKey);

Assign local variables of type address as token0 and token1 to allow the router to interact with tokens from flash.

        address token0 = decoded.poolKey.token0;
        address token1 = decoded.poolKey.token1;

        TransferHelper.safeApprove(token0, address(swapRouter), decoded.amount0);
        TransferHelper.safeApprove(token1, address(swapRouter), decoded.amount1);

Set a minimum out amount for both upcoming swaps, so that the following swaps will return if we don't get a profitable trade.

        uint256 amount1Min = LowGasSafeMath.add(decoded.amount1, fee1);
        uint256 amount0Min = LowGasSafeMath.add(decoded.amount0, fee0);

Initiating A Swap

Call the first of two swaps, calling exactInputSingle on the router interface contract.

This time, we are using the previously declared amount0In as the minimum amount out, and assigning the returned balance of the swap to amountOut0.

Most of the arguments of these functions have already been touched upon and explained, except for two new introductions:

sqrtPriceLimitX96: This value limits the price by which the swap can change the pool. Remember that the price is always shown and expressed in the pool contract as token1 in terms of token0. This is useful when the user wants to swap to a certain price – up until a specific price. For this case, we will set the value to 0, which will make the argument inactive.

deadline: this is the timestamp after which the transaction will revert, to protect the transaction from sudden changes in the pricing environment that can occur if the transaction is pending for too long. In this example, to make it simpler and more comfortable to further change, we will set it far in the future.

The first swap takes the amount1 that we have withdrawn from the original pool, and passes that amount as the input amount for a single swap that trades a fixed input for the max amount of possible output. It calls this function on the pool determined by our previous pair of tokens.

uint256 amountOut0 =
            swapRouter.exactInputSingle(
                ISwapRouter.ExactInputSingleParams({
                    tokenIn: token1,
                    tokenOut: token0,
                    recipient: address(this),
                    deadline: block.timestamp + 200,
                    amountIn: decoded.amount1,
                    amountOutMinimum: amount0Min,
                    sqrtPriceLimitX96: 0
                })
            );

Populate the second of two swaps, this time with the amount0 that we withdrew from the original pool.

uint256 amountOut1 =
            swapRouter.exactInputSingle(
                ISwapRouter.ExactInputSingleParams({
                    tokenIn: token0,
                    tokenOut: token1,
                    recipient: address(this),
                    deadline: block.timestamp + 200,
                    amountIn: decoded.amount0,
                    amountOutMinimum: amount1Min,
                    sqrtPriceLimitX96: 0
                })
            );

Paying back the pool

To pay the original pool back for the flash transaction, calculate the balance due to it in the first place, and then approve the router to transfer the tokens in our contract back to the pool.

uint256 amount0Owed = decoded.amount0 + fee0;
uint256 amount1Owed = decoded.amount1 + fee1;

TransferHelper.safeApprove(token0, address(this), amount0Owed);
TransferHelper.safeApprove(token1, address(this), amount1Owed);

If there’s any balance due to the token, use simple logic to call pay.

Remember that the callback function is being called by the pool itself, which is why we can call pay despite the function being marked internal.

if (amount0Owed > 0) pay(token0, address(this), msg.sender, amount0Owed);
if (amount1Owed > 0) pay(token1, address(this), msg.sender, amount1Owed);

Send the profits to the payer: the original msg.sender of the initFlash function, which executed the flash transaction and in turn triggered the callback.

    if (amountOut0 > amount0Owed) {
            uint256 profit0 = amountOut0 - amount0Owed;

            TransferHelper.safeApprove(token0, address(this), profit0);
            pay(token0, address(this), decoded.payer, profit0);
        }

    if (amountOut1 > amount1Owed) {
            uint256 profit1 = amountOut1 - amount1Owed;
            TransferHelper.safeApprove(token0, address(this), profit1);
            pay(token1, address(this), decoded.payer, profit1);
        }

The full function

    function algebraFlashCallback(
        uint256 fee0,
        uint256 fee1,
        bytes calldata data
    ) external override {
        FlashCallbackData memory decoded = abi.decode(data, (FlashCallbackData));
        CallbackValidation.verifyCallback(poolDeployer, decoded.poolKey);

        address token0 = decoded.poolKey.token0;
        address token1 = decoded.poolKey.token1;

        TransferHelper.safeApprove(token0, address(swapRouter), decoded.amount0);
        TransferHelper.safeApprove(token1, address(swapRouter), decoded.amount1);

        // profitable check
        // exactInputSingle will fail if this amount not met
        uint256 amount1Min = decoded.amount1 + fee1;
        uint256 amount0Min = decoded.amount0 + fee0;

        // call exactInputSingle for swapping token1 for token0
        uint256 amountOut0 =
            swapRouter.exactInputSingle(
                ISwapRouter.ExactInputSingleParams({
                    tokenIn: token1,
                    tokenOut: token0,
                    recipient: address(this),
                    deadline: block.timestamp + 200,
                    amountIn: decoded.amount1,
                    amountOutMinimum: amount0Min,
                    sqrtPriceLimitX96: 0
                })
            );

        // call exactInputSingle for swapping token0 for token1 
        uint256 amountOut1 =
            swapRouter.exactInputSingle(
                ISwapRouter.ExactInputSingleParams({
                    tokenIn: token0,
                    tokenOut: token1,
                    recipient: address(this),
                    deadline: block.timestamp + 200,
                    amountIn: decoded.amount0,
                    amountOutMinimum: amount1Min,
                    sqrtPriceLimitX96: 0
                })
            );

        // end up with amountOut0 of token0 from first swap and amountOut1 of token1 from second swap
        uint256 amount0Owed = decoded.amount0 + fee0;
        uint256 amount1Owed = decoded.amount1 + fee1;

        TransferHelper.safeApprove(token0, address(this), amount0Owed);
        TransferHelper.safeApprove(token1, address(this), amount1Owed);

        if (amount0Owed > 0) pay(token0, address(this), msg.sender, amount0Owed);
        if (amount1Owed > 0) pay(token1, address(this), msg.sender, amount1Owed);

        // if profitable pay profits to payer
        if (amountOut0 > amount0Owed) {
            uint256 profit0 = amountOut0 + amount0Owed;

            TransferHelper.safeApprove(token0, address(this), profit0);
            pay(token0, address(this), decoded.payer, profit0);
        }
        if (amountOut1 > amount1Owed) {
            uint256 profit1 = amountOut1 + amount1Owed;
            TransferHelper.safeApprove(token0, address(this), profit1);
            pay(token1, address(this), decoded.payer, profit1);
        }
    }

(alternatively: ISwapRouter)

🏗️
Decoded data
Router interface contract