Back to skills
extension
Category: Development & EngineeringNo API key required

crane-camelot

This skill should be used when the user asks about "Camelot integration", "Camelot swap", "Camelot liquidity", "Camelot V2", "fee-on-transfer tokens", "asymmetric fees", "directional fees", or needs to interact with Camelot DEX on Arbitrum using Crane's service library.

personAuthor: jakexiaohubgithub

Crane Camelot V2 Integration

Crane provides Camelot V2 integration with service library, stubs, and test infrastructure. Camelot differs from standard Uniswap V2 forks by supporting asymmetric (directional) fees.

Components

| Component | Location | Purpose | |-----------|----------|---------| | CamelotV2Service | services/CamelotV2Service.sol | Swap, deposit, withdraw operations | | CamelotV2RouterAwareRepo | CamelotV2RouterAwareRepo.sol | Router dependency injection | | CamelotV2FactoryAwareRepo | CamelotV2FactoryAwareRepo.sol | Factory dependency injection | | TestBase_CamelotV2 | test/bases/TestBase_CamelotV2.sol | Full protocol deployment |

Key Difference: Asymmetric Fees

Camelot pools have directional fees - different fees for each swap direction:

// Camelot's getReserves returns fees for each direction
(uint112 reserve0, uint112 reserve1, uint16 token0feePercent, uint16 token1FeePercent) = pool.getReserves();

// token0feePercent: Fee when swapping token0 -> token1
// token1FeePercent: Fee when swapping token1 -> token0

Quick Start: Execute Swap

import {CamelotV2Service} from "@crane/contracts/protocols/dexes/camelot/v2/services/CamelotV2Service.sol";
import {ICamelotV2Router} from "@crane/contracts/interfaces/protocols/dexes/camelot/v2/ICamelotV2Router.sol";
import {ICamelotPair} from "@crane/contracts/interfaces/protocols/dexes/camelot/v2/ICamelotPair.sol";

contract CamelotSwapper {
    ICamelotV2Router public router;

    function swap(
        ICamelotPair pool,
        IERC20 tokenIn,
        IERC20 tokenOut,
        uint256 amountIn
    ) external returns (uint256 amountOut) {
        tokenIn.transferFrom(msg.sender, address(this), amountIn);

        amountOut = CamelotV2Service._swap(
            router,
            pool,
            amountIn,
            tokenIn,
            tokenOut,
            address(0)  // referrer (optional)
        );
    }
}

Service Operations

Deposit (Add Liquidity)

function _deposit(
    ICamelotV2Router router,
    IERC20 tokenA,
    IERC20 tokenB,
    uint256 amountADesired,
    uint256 amountBDesired
) internal returns (uint256 liquidity);

Withdraw (Remove Liquidity)

// Direct withdrawal (no router)
function _withdrawDirect(
    ICamelotPair pool,
    uint256 amt
) internal returns (uint256 amount0, uint256 amount1);

Swap

// Swap with pool auto-detection
function _swap(
    ICamelotV2Router router,
    ICamelotPair pool,
    uint256 amountIn,
    IERC20 tokenIn,
    IERC20 tokenOut,
    address referrer
) internal returns (uint256 amountOut);

// Swap with explicit reserves and fees
function _swap(
    ICamelotV2Router router,
    uint256 amountIn,
    IERC20 tokenIn,
    uint256 reserveIn,
    uint256 feePercent,
    IERC20 tokenOut,
    uint256 reserveOut,
    address referrer
) internal returns (uint256 amountOut);

Swap and Deposit (Zap In)

function _swapDeposit(
    ICamelotV2Router router,
    ICamelotPair pool,
    IERC20 tokenIn,
    uint256 saleAmt,
    IERC20 opToken,
    address referrer
) internal returns (uint256 lpAmount);

Withdraw and Swap (Zap Out)

function _withdrawSwapDirect(
    ICamelotPair pool,
    ICamelotV2Router router,
    uint256 amt,
    IERC20 tokenOut,
    IERC20 opToken,
    address referrer
) internal returns (uint256 amountOut);

Reserve Sorting

Get reserves sorted by known token:

(
    uint256 knownReserve,
    uint256 opposingReserve,
    uint256 knownFeePercent,
    uint256 opposingFeePercent
) = CamelotV2Service._sortReserves(pool, knownToken);

Testing

import {TestBase_CamelotV2} from "@crane/contracts/protocols/dexes/camelot/v2/test/bases/TestBase_CamelotV2.sol";

contract MyTest is TestBase_CamelotV2 {
    function setUp() public override {
        super.setUp();
        // camelotV2Factory and camelotV2Router available
    }

    function test_swap() public {
        // Create pair
        address pair = camelotV2Factory.createPair(
            address(tokenA),
            address(tokenB)
        );

        // Add liquidity
        CamelotV2Service._deposit(
            camelotV2Router,
            tokenA,
            tokenB,
            1000e18,
            1000e18
        );

        // Execute swap
        uint256 amountOut = CamelotV2Service._swap(
            camelotV2Router,
            ICamelotPair(pair),
            100e18,
            tokenA,
            tokenB,
            address(0)
        );
    }
}

Fee-on-Transfer Token Support

Camelot uses swapExactTokensForTokensSupportingFeeOnTransferTokens to support deflationary tokens:

router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
    amountIn,
    amountOutMin,
    path,
    to,
    referrer,
    deadline
);

File Organization

contracts/protocols/dexes/camelot/v2/
├── services/
│   └── CamelotV2Service.sol
├── CamelotV2RouterAwareRepo.sol
├── CamelotV2FactoryAwareRepo.sol
├── stubs/
│   ├── CamelotFactory.sol
│   ├── CamelotRouter.sol
│   ├── CamelotPair.sol
│   └── libraries/
│       ├── Math.sol
│       ├── SafeMath.sol
│       └── UniswapV2Library.sol
└── test/bases/
    └── TestBase_CamelotV2.sol

Additional Resources

Reference Files

  • references/camelot-services.md - Detailed patterns and examples