Skip to main content

Plugin-Based Integration

Integrate Reflex MEV capture into DEXes with hook/plugin support using lightweight plugin contracts.

Overview​

Plugin-based integration is ideal for existing DEX protocols that support hooks or callbacks (like afterSwap). A lightweight plugin contract automatically triggers MEV capture after user swaps without requiring modifications to your core DEX contracts.

Best for:

  • ✅ Algebra, PancakeSwap Infinity, Uniswap v4 architectures
  • ✅ Existing DEX protocols with plugin/hook systems
  • ✅ Minimal code changes required
  • ✅ Automatic MEV capture and distribution

How It Works​

Key Features​

  • Zero DEX Modifications: Plugin sits alongside your existing pool contracts
  • Automatic Triggering: Every swap is analyzed for MEV opportunities
  • Configurable Thresholds: Set minimum swap sizes and backrun ratios
  • Failsafe Design: Failed MEV attempts don't affect user swaps

Implementation​

1. Algebra-Based Plugin​

For Algebra Integral pools:

pragma solidity ^0.8.19;

import "@reflex/contracts/ReflexAfterSwap.sol";

contract AlgebraReflexPlugin is ReflexAfterSwap {
address public immutable pool;

constructor(
address _reflexRouter,
address _pool,
bytes32 _configId
) ReflexAfterSwap(_reflexRouter, _configId) {
pool = _pool;
}

function afterSwap(
address sender,
int256 amount0,
int256 amount1,
uint160 currentPrice,
uint128 currentLiquidity,
int24 currentTick,
bytes calldata data
) external {
require(msg.sender == pool, "Only pool can call");

// Use the base contract's _reflexAfterSwap function
_reflexAfterSwap(
bytes32(uint256(uint160(pool))), // triggerPoolId
amount0, // amount0Delta
amount1, // amount1Delta
amount0 > 0, // zeroForOne
sender // recipient
);
}

function _onlyReflexAdmin() internal view override {
// Implement admin access control
// Example: require(msg.sender == admin, "Only admin");
}
}

2. PancakeSwap Infinity Plugin​

For PancakeSwap Infinity pools (uses Algebra-based architecture):

pragma solidity ^0.8.19;

import "@reflex/contracts/ReflexAfterSwap.sol";

contract PancakeSwapInfinityReflexPlugin is ReflexAfterSwap {
address public immutable pool;

constructor(
address _reflexRouter,
address _pool,
bytes32 _configId
) ReflexAfterSwap(_reflexRouter, _configId) {
pool = _pool;
}

function afterSwap(
address sender,
int256 amount0,
int256 amount1,
uint160 currentPrice,
uint128 currentLiquidity,
int24 currentTick,
bytes calldata data
) external {
require(msg.sender == pool, "Only pool can call");

// Use the base contract's _reflexAfterSwap function
_reflexAfterSwap(
bytes32(uint256(uint160(pool))), // triggerPoolId
amount0, // amount0Delta
amount1, // amount1Delta
amount0 > 0, // zeroForOne
sender // recipient
);
}

function _onlyReflexAdmin() internal view override {
// Implement admin access control
// Example: require(msg.sender == admin, "Only admin");
}
}

3. Uniswap V4 Hook​

For Uniswap V4 pools:

pragma solidity ^0.8.19;

import {BaseHook} from "v4-periphery/BaseHook.sol";
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol";
import {PoolKey} from "v4-core/types/PoolKey.sol";
import {BalanceDelta} from "v4-core/types/BalanceDelta.sol";
import {Hooks} from "v4-core/libraries/Hooks.sol";
import "@reflex/contracts/ReflexAfterSwap.sol";

contract UniswapV4ReflexHook is BaseHook, ReflexAfterSwap {
constructor(
IPoolManager _poolManager,
address _reflexRouter,
bytes32 _configId
) BaseHook(_poolManager) ReflexAfterSwap(_reflexRouter, _configId) {}

function afterSwap(
address sender,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
BalanceDelta delta,
bytes calldata hookData
) external override returns (bytes4) {
// Use the base contract's _reflexAfterSwap function
_reflexAfterSwap(
keccak256(abi.encode(key)), // triggerPoolId
delta.amount0(), // amount0Delta
delta.amount1(), // amount1Delta
params.zeroForOne, // zeroForOne
sender // recipient
);

return BaseHook.afterSwap.selector;
}

function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
return Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: true,
beforeDonate: false,
afterDonate: false
});
}

function _onlyReflexAdmin() internal view override {
// Implement admin access control
// Example: require(msg.sender == admin, "Only admin");
}
}

Configuration​

Register Plugin with Pool​

For Algebra pools:

// As pool owner/admin
pool.setPlugin(pluginAddress);

For Uniswap V4:

// Deploy with hook address in pool key
PoolKey memory key = PoolKey({
currency0: currency0,
currency1: currency1,
fee: fee,
tickSpacing: tickSpacing,
hooks: IHooks(hookAddress)
});

Best Practices​

1. Monitoring​

Listen for MEV capture events from the ReflexRouter:

// Listen to BackrunExecuted event from ReflexRouter
event BackrunExecuted(
bytes32 indexed poolId,
address indexed user,
uint256 profit,
address profitToken,
bytes32 indexed configId
);

You can filter these events by your pool ID or config ID to monitor MEV captures for your integration.

2. Testing​

Always test your plugin integration thoroughly:

// Test small swaps
// Test large swaps
// Test failsafe behavior

3. Security​

  • Use try/catch to prevent plugin failures from affecting swaps
  • Implement proper access controls for admin functions
  • Monitor plugin behavior and adjust as needed

Troubleshooting​

Plugin Not Triggering​

  1. Verify plugin is registered with the pool
  2. Check that swaps are being executed through the pool
  3. Verify the plugin's afterSwap hook is being called

Failed Backruns​

  1. Check gas limits are sufficient
  2. Review event logs for failure reasons

Next Steps: