Skip to main content

Overview

Swap Guards provide an additional layer of security and control over conditional orders by restricting which orders can be settled via CoW Protocol. They implement the ISwapGuard interface and are called during order verification to enforce custom restrictions.
Swap Guards are optional. If no guard is set for an owner, all authorized conditional orders can be settled without restrictions.

How Swap Guards Work

When a conditional order is being verified for settlement, ComposableCoW checks if the owner has set a swap guard. If one exists, the guard’s verify function must return true for the order to proceed.
// From ComposableCoW.sol
function _guardCheck(
    address owner,
    bytes32 ctx,
    IConditionalOrder.ConditionalOrderParams memory params,
    bytes memory offchainInput,
    GPv2Order.Data memory order
) internal view returns (bool) {
    ISwapGuard guard = swapGuards[owner];
    if (address(guard) != address(0)) {
        return guard.verify(order, ctx, params, offchainInput);
    }
    return true;
}
If the guard returns false, the order verification fails with a SwapGuardRestricted error.

ISwapGuard Interface

The ISwapGuard interface is minimal and flexible, allowing for various restriction implementations:
interface ISwapGuard is IERC165 {
    /**
     * @notice Verify that the order is allowed to be settled via CoW Protocol.
     * @param order The order to verify.
     * @param ctx The context of the order (bytes32(0) if a merkle tree is used, otherwise H(params))
     * @param params The conditional order parameters (handler, salt, staticInput).
     * @param offchainInput Any offchain input to verify.
     * @return True if the order is allowed to be settled via CoW Protocol.
     */
    function verify(
        GPv2Order.Data calldata order,
        bytes32 ctx,
        IConditionalOrder.ConditionalOrderParams calldata params,
        bytes calldata offchainInput
    ) external view returns (bool);
}

Parameters

  • order: The complete GPv2Order.Data struct containing all order details (tokens, amounts, receiver, etc.)
  • ctx: The context identifier - bytes32(0) for merkle tree orders, or H(params) for single orders
  • params: The conditional order parameters including handler address, salt, and static input
  • offchainInput: Dynamic off-chain data that may be used in order generation

BaseSwapGuard

The BaseSwapGuard abstract contract provides ERC165 interface support, making it easier to implement custom guards:
abstract contract BaseSwapGuard is ISwapGuard {
    /**
     * @inheritdoc IERC165
     */
    function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
        return interfaceId == type(ISwapGuard).interfaceId || interfaceId == type(IERC165).interfaceId;
    }
}

Example Implementation: ReceiverLock

The ReceiverLock guard ensures that orders can only settle funds back to the owner’s Safe (not to external addresses):
contract ReceiverLock is BaseSwapGuard {
    /**
     * Only allow orders with a receiver of 0x0 (ie. self)
     * @param order The order being verified
     */
    function verify(
        GPv2Order.Data calldata order,
        bytes32,
        IConditionalOrder.ConditionalOrderParams calldata,
        bytes calldata
    ) external pure override returns (bool) {
        return order.receiver == address(0);
    }
}
In GPv2 orders, address(0) for the receiver is a special value meaning “self” - the owner receives the bought tokens.

Setting a Swap Guard

1

Deploy your guard contract

Deploy your custom ISwapGuard implementation or use an existing one like ReceiverLock.
2

Call setSwapGuard

Call ComposableCoW.setSwapGuard(ISwapGuard swapGuard) from your Safe to enable the guard.
composableCow.setSwapGuard(ISwapGuard(guardAddress));
3

Verify the guard is active

Check that the guard is set:
address activeGuard = address(composableCow.swapGuards(safeAddress));

Removing a Swap Guard

To remove a swap guard and allow unrestricted settlements again:
composableCow.setSwapGuard(ISwapGuard(address(0)));

Use Cases

Receiver Restrictions

Prevent funds from being sent to external addresses (like ReceiverLock)

Token Whitelisting

Only allow trading specific token pairs

Time-based Controls

Restrict settlements to specific time windows

Amount Limits

Enforce maximum trade sizes or daily volume limits

Custom Swap Guard Example

Here’s an example of a guard that restricts settlements to specific hours:
contract TimeRestrictedGuard is BaseSwapGuard {
    uint256 public immutable startHour;
    uint256 public immutable endHour;
    
    constructor(uint256 _startHour, uint256 _endHour) {
        require(_startHour < 24 && _endHour < 24, "Invalid hours");
        startHour = _startHour;
        endHour = _endHour;
    }
    
    function verify(
        GPv2Order.Data calldata order,
        bytes32,
        IConditionalOrder.ConditionalOrderParams calldata,
        bytes calldata
    ) external view override returns (bool) {
        uint256 currentHour = (block.timestamp / 1 hours) % 24;
        
        if (startHour <= endHour) {
            return currentHour >= startHour && currentHour < endHour;
        } else {
            // Handle overnight ranges (e.g., 22:00 to 06:00)
            return currentHour >= startHour || currentHour < endHour;
        }
    }
}
Swap guards are called during signature verification. Ensure your guard implementation:
  • Is gas-efficient (it’s a view function)
  • Does not rely on external state that could change
  • Returns deterministic results for the same inputs

Integration with Order Flow

Swap guards are checked at two key points:
  1. During getTradeableOrderWithSignature: Before returning an order to watchtowers
  2. During isValidSafeSignature: When CoW Protocol verifies the order signature
This ensures that even if an old order signature exists, it cannot be settled if the guard restrictions are not met.

Next Steps

Value Factories

Learn about on-chain value determination for orders

Custom Orders

Implement your own conditional order types

Build docs developers (and LLMs) love